How can I find the data usage on a per-application basis on Android?
Asked Answered
D

7

44

I am trying to find out the data usage on Android on a per-application basis. Something like Android Data Usage Apps and Quota / Cap Monitor Widgets: never get charged extra for data or get capped again!.

I looked at Stack Overflow question How to go about detecting data usage in the Android environment.

But it's not been of much help.


ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
ActivityManager.MemoryInfo mInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo( mInfo );
List<RunningAppProcessInfo> listOfRunningProcess = activityManager.getRunningAppProcesses();
Log.d(TAG, "XXSize: " + listOfRunningProcess.size());

for (RunningAppProcessInfo runningAppProcessInfo : listOfRunningProcess) {

    if (runningAppProcessInfo.uid > 1026)
    {
        Log.d(TAG, "ANS " + runningAppProcessInfo.processName +
                   " Id :" + runningAppProcessInfo.pid +
                   " UID: " + runningAppProcessInfo.uid);
    }
}

I tried the above code as suggested by Akos Cz. However all the UIDs are numbers, unlike app_79 as you have mentioned above. Is this all right?

Deformed answered 13/8, 2012 at 18:14 Comment(2)
Are you wanting this information to put in an app (programmatically), or are you just curious? What device?Photomicroscope
Oops. I want to do this programmatically.Deformed
T
45

The following links should help you figure out how to programmatically determine the data usage per application.

You will need to implement your code to use the TraficStats API and track the number of bytes sent/received per UID (application).

Tenno answered 13/8, 2012 at 18:31 Comment(12)
Thanks. I had just figured this thing out. I was about to post the update. Can you please explain me the difference between UID and PID ? From my understanding UID is based on User.. For every app running on my device, wouldn't the UID be the same??? And PID should vary for every application process.. I may be incorrect. Please clarify. Thanks. :)Deformed
Thanks. I just figured this thing out. Is UID different of Every application? I assumed that it was same for every process running on my device. Can you please clarify this. Thanks.Deformed
- Each app (package) is assigned an arbitrary but distinct OS user ID at installation time. Typically something like app_XX (e.g. app_79) - Does not change during app’s life on a device - All app resources are owned by its UID - Each app process runs under its own UID - Apps that are signed with the same certificate can share data, user ID, as well as run in a single process. They just need to specify the same sharedUserId and processTenno
Got it. Thanks.agolovatyuk.blogspot.com/2012/04/…Deformed
AndroidManifest.xml <manifest package="com.example.myapp" android:sharedUserId="myapp" android:sharedUserLabel="@string/myapp_uid" … > <application android:process="myapp" … > … </application> </manifest>Tenno
ActivityManager activityManager = (ActivityManager) this.getSystemService( ACTIVITY_SERVICE ); ActivityManager.MemoryInfo mInfo = new ActivityManager.MemoryInfo (); activityManager.getMemoryInfo( mInfo ); List<RunningAppProcessInfo> r = activityManager.getRunningAppProcesses(); Log.d(TAG,"XXSize: " + r.size()); for (RunningAppProcessInfo tempR : r) { if(tempR.uid > 1026) { Log.d(TAG, "ANS " + tempR.processName + " Id :" + tempR.pid + " UID: " + tempR.uid ); }Deformed
I tried the above code as your suggestion. However all the UID are Numbers. Unlike app_79 as you have mentioned above. Is this alright?Deformed
As I have a low reputation, I have made the changes in my question.Deformed
my mistake. yes the UID's are numbers.Tenno
TrafficStats cannot be used to monitor other apps anymore. You should use NetworkStatsManager instead : developer.android.com/reference/android/net/… . I think you are supposed to use "queryDetailsForUid" there, as shown here: groups.google.com/forum/embed/#!topic/android-developers/…Staunch
@androiddeveloper the link doesn't work for groups.google.com - any idea how to use NetworkStatsManager to get package wise data consumption !!?!!Dominiquedominium
@Dominiquedominium Here: issuetracker.google.com/issues/37118933 , issuetracker.google.com/issues/38319872Staunch
J
11

Use this method after create a new class PackageInformationTotal.

public void getPakagesInfoUsingHashMap() {
    final PackageManager pm = getPackageManager();
    // get a list of installed apps.
    List<ApplicationInfo> packages = pm.getInstalledApplications(0);

    // loop through the list of installed packages and see if the selected
    // app is in the list
    for (ApplicationInfo packageInfo : packages) {
        // get the UID for the selected app
        UID = packageInfo.uid;
        String package_name = packageInfo.packageName;
        ApplicationInfo app = null;
        try {
            app = pm.getApplicationInfo(package_name, 0);
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        String name = (String) pm.getApplicationLabel(app);
        Drawable icon = pm.getApplicationIcon(app);
        // internet usage for particular app(sent and received)
        double received = (double) TrafficStats.getUidRxBytes(UID)

                / (1024 * 1024);
        double send = (double) TrafficStats.getUidTxBytes(UID)
                / (1024 * 1024);
        double total = received + send;

        if(total>0)
        {
            PackageInformationTotal pi=new PackageInformationTotal();
            pi.name=name;
            pi.packageName=package_name;
            pi.icon=icon;               
            pi.totalMB=String.format( "%.2f", total )+" MB";
            pi.individual_mb=String.format( "%.2f", total );
            totalData+=Double.parseDouble(String.format( "%.2f", total ));
            dataHash.add(pi);
        Log.e(name,String.format( "%.2f", total )+" MB");
        }

    }
    Editor edit=shared.edit();
    edit.putString("Total",String.format( "%.2f", totalData));
    edit.commit();
}

After that you can track all process usages in MB.

Joost answered 21/3, 2014 at 13:44 Comment(3)
This doesn't work well on all devices. Is there a similar thing for battery usage per app?Staunch
in PackageInformationTotal what we should implement can u post the code plz.Waggoner
this also is not a 100% solution - won't always work eg. api 23Dominiquedominium
H
1

Prorammatically:

You can declare the intent filter for the ACTION_MANAGE_NETWORK_USAGE action (introduced in Android 4.0) to indicate that your application defines an activity that offers options to control data usage. ACTION_MANAGE_NETWORK_USAGE shows settings for managing the network data usage of a specific application. When your app has a settings activity that allows users to control network usage, you should declare this intent filter for that activity. Check this out for more information about managing data usage manage usage per application.

The proper definition of ACTION_MANAGE_NETWORK_USAGE is you can see here.

Hatshepsut answered 13/8, 2012 at 18:34 Comment(0)
C
0

This snippet also works for those actually running apps in your device

final PackageManager pm = getPackageManager();

ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
//final List<ActivityManager.RunningTaskInfo> recentTasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (int i = 0; i < appProcesses.size(); i++) {
    Log.d("Executed app", "Application executed : " + appProcesses.get(i).processName + "\t\t ID: " + appProcesses.get(i).pid + "");
    //  String packageName = activityManager.getRunningTasks(1).get(0).topActivity.getPackageName();
    //String packageName = appProcesses.get(i)..getPackageName();
    ApplicationInfo app = null;
    try {
        app = pm.getApplicationInfo(appProcesses.get(i).processName, 0);
        if ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) {
            //it's a system app, not interested
        } else if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 1) {
            //Discard this one
            //in this case, it should be a user-installed app
        } else {
            // tx = TrafficStats.getUidTxBytes(app.uid);
            //rx = TrafficStats.getUidRxBytes(app.uid);
            long delta_rx = TrafficStats.getUidRxBytes(app.uid) - rx;

            long delta_tx = TrafficStats.getUidTxBytes(app.uid) - tx;
        }
    }
Cheiro answered 5/9, 2015 at 12:16 Comment(5)
what is tx and rx in this case?Monosyllable
Transmit and ReceiveFrangipani
Are any permissions required? Also, it is said it's not supported on N and above, and that we should use NetworkStatsManager instead (here: developer.android.com/reference/android/net/… ) . Can you show how?Staunch
@androiddeveloper did you find any solution for this !?!Dominiquedominium
@Dominiquedominium Here: issuetracker.google.com/issues/37118933 , issuetracker.google.com/issues/38319872Staunch
A
0
 public class Main extends Activity {

    private Handler mHandler = new Handler();
    private long mStartRX = 0;
    private long mStartTX = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mStartRX = TrafficStats.getTotalRxBytes();
        mStartTX = TrafficStats.getTotalTxBytes();
        if (mStartRX == TrafficStats.UNSUPPORTED || mStartTX == TrafficStats.UNSUPPORTED) {
            AlertDialog.Builder alert = new AlertDialog.Builder(this);
            alert.setTitle("Uh Oh!");
            alert.setMessage("Your device does not support traffic stat monitoring.");
            alert.show();
        } else {
            mHandler.postDelayed(mRunnable, 1000);
        }
    }

    private final Runnable mRunnable = new Runnable() {
        public void run() {
            TextView RX = (TextView)findViewById(R.id.RX);
            TextView TX = (TextView)findViewById(R.id.TX);
            long rxBytes = TrafficStats.getTotalRxBytes()- mStartRX;
            RX.setText(Long.toString(rxBytes));
            long txBytes = TrafficStats.getTotalTxBytes()- mStartTX;
            TX.setText(Long.toString(txBytes));
            mHandler.postDelayed(mRunnable, 1000);
        }
     };
}

You can also checkout https://github.com/commonsguy/cw-andtuning/tree/master/TrafficMonitor

Amylum answered 4/3, 2016 at 6:21 Comment(1)
Does it require any permission? Also, it is said it's not supported on N and above, and that we should use NetworkStatsManager instead (here: developer.android.com/reference/android/net/… ) . Can you show how?Staunch
M
0

To access an individual app stats you will need the uid of that app, which is an int value assigned by the system to each app at install time.

PackageManager packageManager = context.getPackageManager();

ApplicationInfo info = packageManager.getApplicationInfo("com.example.app", 0); 

int packageUid = info.uid;

To get all Rx and Tx bytes of Mobile for package :

NetworkStats.Bucket bucket = networkStatsManager.queryDetailsForUid(ConnectivityManager.TYPE_MOBILE, getSubscriberId(context, ConnectivityManager.TYPE_MOBILE), 0, System.currentTimeMillis(),packageUid);
            
            
    
long rxBytes = 0L;
           
long txBytes = 0L;
            
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
           
while (networkStats.hasNextBucket()) {
            
     networkStats.getNextBucket(bucket);
     rxBytes += bucket.getRxBytes();
     txBytes += bucket.getTxBytes(); 
}
networkStats.close();

For more clarification about this, check: How do I programmatically show data usage of all applications?

Manducate answered 26/8, 2020 at 12:25 Comment(0)
C
-1

After a long struggle,I am able to find the Solution for getting data over any interface for each installed Application in android device.

As Android provides TrafficStats Apis but these APIs are providing comple Data stastics for each app uid since device boot and Even APIs are not supporting to get the data over any interface for a particular application. Even if we rely over TraffiucStates APIS ,we get a new data statstics for each Application.

So I thought to use the hidden APIs to USe this..

Here I am mentioning the Steps to get the data statstics for each application over any Interface in Android...

  1. Estabalish a "INetworkStatsSession" session

    #import android.net.INetworkStatsSession;

INetworkStatsSession mStatsSession = mStatsService.openSession();

  1. Create a Network Templeate according to interafce which you want to measure..

    #import static android.net.NetworkTemplate.buildTemplateEthernet;
    #import static android.net.NetworkTemplate.buildTemplateMobile3gLower;
    #import static android.net.NetworkTemplate.buildTemplateMobile4g;
    #import static android.net.NetworkTemplate.buildTemplateMobileAll;
    #import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
    
    #import android.net.NetworkTemplate;
    
    private NetworkTemplate mTemplate;
    
    mTemplate = buildTemplateMobileAll(getActiveSubscriberId(this
                    .getApplicationContext()));
    
  2. GetActive SubcriberID:

    private static String getActiveSubscriberId(Context context) {
        final TelephonyManager tele = TelephonyManager.from(context);
        final String actualSubscriberId = tele.getSubscriberId();
        return SystemProperties.get(TEST_SUBSCRIBER_PROP, actualSubscriberId);
    }
    
  3. Collect the network HIStory of respective application byt passing application UIDs...

     private NetworkStatsHistory collectHistoryForUid(NetworkTemplate template,
            int uid, int set) throws RemoteException {
        final NetworkStatsHistory history = mStatsSession.getHistoryForUid(
                template, uid, set, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES);
        return history;
    
    }
    
  4. Get the total Consumption data:

    public void showConsuption(int UID){
        NetworkStatsHistory history = collectHistoryForUid(mTemplate, UID,
                SET_DEFAULT);
    
        Log.i(DEBUG_TAG, "load:::::SET_DEFAULT:.getTotalBytes:"+ Formatter.formatFileSize(context, history.getTotalBytes()));
    
        history = collectHistoryForUid(mTemplate, 10093,
                SET_FOREGROUND);
        Log.i(DEBUG_TAG, "load::::SET_FOREGROUND::.getTotalBytes:"+ Formatter.formatFileSize(context, history.getTotalBytes()));
    
        history = collectHistoryForUid(mTemplate, 10093,
                SET_ALL);
        Log.i(DEBUG_TAG, "load::::SET_ALL::.getTotalBytes:"+ Formatter.formatFileSize(context, history.getTotalBytes()));
    
    }
    
Candlestand answered 20/4, 2015 at 11:56 Comment(4)
@Mysterion could you give more insight regarding INetworkSession,basically needing data usage per day per applicationCheiro
@SrishtiRoy to use INetworkSession ..you need to build your app as System application..And if you want to calculate per Day per application basis you need to maintain the per day data in a database.As in existing internal android API don't have ..so you have to maintain this explicitly in your applicationCandlestand
@Candlestand any idea how to list only those apps which consume mobile dataCheiro
@SrishtiRoy You can maintain a statistical DB of app installed with mobile data history (using above solution) in regular interval and With difference of mobile data you can get list of application which are consuming mobile data.Candlestand

© 2022 - 2024 — McMap. All rights reserved.