4

I have an application that uses the traffic stats API to see which running processes are using the network.

I used to do it by getting the uid obtained through the getRunningAppProcesses() method. Apparently this has been changed in Android M to only return your application package name as shown here.

My question is: Is there another way to get the Name and UID of every running processes in Android M?

Here is a sample of how I was doing this before, I would like to recreate this functionality on Android M.

List<RunningAppProcessInfo> procInfos = activityManager.getRunningAppProcesses();

PackageManager pm = context.getPackageManager();
for (int i = 0; i < procInfos.size(); i++) {
    try {
        String packageName = procInfos.get(i).processName;
        String appName = "";
        try {
            appName = pm.getApplicationLabel(
                    pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA))
                        .toString();
        } catch (NameNotFoundException e) {
            appName = "";
        }

        int uid = procInfos.get(i).uid;
        long ulBytes = TrafficStats.getUidTxBytes(uid);
        long dlBytes = TrafficStats.getUidRxBytes(uid);
        // Do other stuff.

Any help is very appreciated. Thanks!

Community
  • 1
  • 1
Dave
  • 3,178
  • 5
  • 28
  • 44
  • The same thing happens to me. Any solution? I see https://code.google.com/p/android-developer-preview/issues/detail?id=2347 but nobody provides a solution! – LopezAgrela Aug 26 '15 at 08:25

1 Answers1

3

You can use ActivityManager.getRunningServices(int maxNum):

PackageManager pm = context.getPackageManager();
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> runningServices = am.getRunningServices(Integer.MAX_VALUE);
for (ActivityManager.RunningServiceInfo service : runningServices) {
    String appName;
    try {
        appName = pm.getApplicationInfo(service.process, 0).loadLabel(pm).toString();
    } catch (PackageManager.NameNotFoundException e) {
        appName = null;
    }

    int uid = service.uid;

    long ulBytes = TrafficStats.getUidTxBytes(uid);
    long dlBytes = TrafficStats.getUidRxBytes(uid);
}

The documentation states that this is not intended for production. I haven't done much testing with it either. If it doesn't meet your requirements leave a comment. The only other thing I can think of is parsing the output of running ps in a shell.

UPDATE

Parsing the output of ps in a shell we can get the current running apps. Example:

PackageManager pm = context.getPackageManager();
// Get the output of running "ps" in a shell.
// This uses libsuperuser: https://github.com/Chainfire/libsuperuser
// To add this to your project: compile 'eu.chainfire:libsuperuser:1.0.0.+'
List<String> stdout = Shell.SH.run("ps");
List<String> packages = new ArrayList<>();
for (String line : stdout) {
    // Get the process-name. It is the last column.
    String[] arr = line.split("\\s+");
    String processName = arr[arr.length - 1].split(":")[0];
    packages.add(processName);
}

// Get a list of all installed apps on the device.
List<ApplicationInfo> apps = pm.getInstalledApplications(0);

// Remove apps which are not running.
for (Iterator<ApplicationInfo> it = apps.iterator(); it.hasNext(); ) {
    if (!packages.contains(it.next().packageName)) {
        it.remove();
    }
}

for (ApplicationInfo app : apps) {
    String appName = app.loadLabel(pm).toString();
    int uid = app.uid;
    long ulBytes = TrafficStats.getUidTxBytes(uid);
    long dlBytes = TrafficStats.getUidRxBytes(uid);
    /* do your stuff */
}
Jared Rummler
  • 37,824
  • 19
  • 133
  • 148
  • Hey Jared, Thanks for your response! I've tested it and it works for services that are running. However it skips over all other processes. So for example since my application is not in a service, I do not see my own applications network usage. Also I tried running the ps command in the adb shell, and it returns a PID, but not a uid which I need, so it's not looking like that will work either. – Dave Aug 27 '15 at 01:58
  • See my update. Tested on Nexus 7 running latest Android 6.0 release. – Jared Rummler Aug 27 '15 at 06:20
  • Hey Jared, sorry it's taken me a little while to respond. This looks like a really good answer. I just have one more question for you. Where are you getting the Shell library for the Shell.SH.run("ps"); command? I am unable to locally find that library. I've seen alternatives with the Runtime.getRuntime().exec("ps");. But i'd like to see if I can get your approach to work. Thanks! – Dave Sep 03 '15 at 00:55
  • @Dave I added it in the comments. The library is here: https://github.com/Chainfire/libsuperuser You can just add it as a dependency in gradle. `compile 'eu.chainfire:libsuperuser:1.0.0.+' ` – Jared Rummler Sep 03 '15 at 01:08
  • Awesome, Thanks Jared! This looks perfect for me. Cheers! – Dave Sep 03 '15 at 20:29
  • Seems like Nougat curtails access to procfs even more, making ps command useless when run programmatically within an app. Any other ideas? – user1118764 Apr 20 '17 at 06:52
  • @JaredRummler, Thanks for your effort. I already tried your code on my application. It works but output shown only one process (only my application process id) not other’s. – Syeful Islam Apr 22 '17 at 05:24