Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catering for devices running Jelly bean as well as versions later than Jelly bean when obtaining application data usage

I would like to cater for devices running on jelly bean version and below as well as versions above Jelly Bean.

My method is supposed to get app usage/traffic for all applications based on the application ID. Please take note of this line rx = Long.parseLong(String.valueOf(id)); on the first if clause which caters for devices running versions less than or equal to Jelly Bean.

The data usage of an installed application based on its ID is obtained using using TrafficStats.getUidTxBytes(uid) but that only returns a value of 0 in 4.3 however, the else clause using TrafficStats.getUidTxBytes(uid) retrieves app usage per app accurately in versions above 5.

I am particularly concerned about the if clause which caters for device running android version lower than 5 for example in this case 4.3 (Jelly Bean)

public void recordSnapshot(Context context)
{
  TinyDB settings = new TinyDB(context);
  int boot_id = settings.getInt(AppPreferences.BOOT_ID);
  PackageManager pm = context.getPackageManager();

  for (ApplicationInfo app : pm.getInstalledApplications(0))
  {
     String androidOS = Build.VERSION.RELEASE;
     int currentapiVersion = android.os.Build.VERSION.SDK_INT;

     long tx = 0;
     long rx = 0;
     int uid = app.uid;

     if(currentapiVersion <= Build.VERSION_CODES.JELLY_BEAN)
     {
        File dir = new File("/proc/uid_stat/");
        String[] children = dir.list();
        List<Integer> uids = new ArrayList<Integer>();

           for (int i = 0; i < children.length; i++) {
              uid = Integer.parseInt(children[i]);
              String uidString = String.valueOf(uid);
              File uidFileDir = new File("/proc/uid_stat/" + uidString);
              File uidActualFile = new File(uidFileDir, "tcp_rcv");
              StringBuilder text = new StringBuilder();

              try {
                 BufferedReader br = new BufferedReader(new FileReader(uidActualFile));
                 String line;

                 while ((line = br.readLine()) != null) {
                    Log.d(String.valueOf(uid), line);//this returns the amount of data received for the particular uid
                    rx = Long.parseLong(String.valueOf(uid));
                    text.append(line);

                    text.append('\n');
                 }
              } catch (IOException e) {
                 //handle this
              }

              uids.add(id);
           }
     }
     else {
        tx = TrafficStats.getUidTxBytes(uid);
        rx = TrafficStats.getUidRxBytes(uid);
     }
}

Entire Method

public void recordSnapshot(Context context)
    {
        TinyDB settings = new TinyDB(context);
        int boot_id = settings.getInt(AppPreferences.BOOT_ID);
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = cm.getActiveNetworkInfo();
        int networkType = NetworkState.GetNetworkState(context, info, "DataUsageRecorder"); // wifi, data, data roaming

        // Get all apps
        PackageManager pm = context.getPackageManager();
        for (ApplicationInfo app : pm.getInstalledApplications(0))
        {

            String androidOS = Build.VERSION.RELEASE;
            int currentapiVersion = android.os.Build.VERSION.SDK_INT;
            long tx = 0;
            long rx = 0;
            int uid = app.uid;


            if(currentapiVersion <= Build.VERSION_CODES.JELLY_BEAN_MR2)
            {

                File dir = new File("/proc/uid_stat/");
                String[] children = dir.list();
                List<Integer> uids = new ArrayList<Integer>();

                for (int i = 0; i < children.length; i++) {
                    uid = Integer.parseInt(children[i]);
                    String uidString = String.valueOf(uid);
                    File uidFileDir = new File("/proc/uid_stat/" + uidString);
                    File uidActualFile = new File(uidFileDir, "tcp_rcv");
                    StringBuilder text = new StringBuilder();

                    try {
                        BufferedReader br = new BufferedReader(new FileReader(uidActualFile));
                        String line;

                        while ((line = br.readLine()) != null) {
                            Log.d(String.valueOf(uid), line);//this returns the amount of data received for the particular uid
                            rx = Long.parseLong(String.valueOf(uid));
                            //text.append(line);

                            //text.append('\n');
                        }
                    } catch (IOException e) {
                        //handle this
                    }

                    uids.add(uid);
                }
            }

              else
            {

                 tx = TrafficStats.getUidTxBytes(uid);
                 rx = TrafficStats.getUidRxBytes(uid);
            }




            if ((tx == 0 || rx == 0))
            {
                // Skip inactive items
                continue;
            }
            else if (Globals.DEBUG && (tx < DEBUG_5MB && rx < DEBUG_5MB)) {
                // Let's skip all the BS for quick testing
                continue;
            }


            // Get package name
            String package_name;
            try {
                CharSequence name = pm.getApplicationLabel(app);
                package_name = name != null ? name.toString() : "";
            } catch (Exception e) {
                e.printStackTrace();
                package_name = "";
            }

            AppUsage totals;
            AppUsage appUsage;

            // Get current data entry for app
            //appUsage = appUsageDao.queryBuilder().where(AppUsageDao.Properties.App_uid.eq(uid), AppUsageDao.Properties.Type.eq(networkType), AppUsageDao.Properties.Boot_id.eq(boot_id)).limit(1).unique();

            // Get last recorded totals since device boot
            totals = appUsageDao.queryBuilder().where(AppUsageDao.Properties.App_uid.eq(uid), AppUsageDao.Properties.Type.eq(NetworkState.ALL), AppUsageDao.Properties.Boot_id.eq(boot_id)).limit(1).unique();

            long tx_diff = tx;
            long rx_diff = rx;

            if (totals != null)
            {
                // Get difference, and update
                tx_diff -= totals.getTx();
                rx_diff -= totals.getRx();

                totals.setTx(tx);
                totals.setRx(rx);
            }
            else
            {
                // add new master
                totals = new AppUsage(null, new Date(), uid, package_name, NetworkState.ALL, tx_diff, rx_diff, 0, 0, boot_id);
            }

            // add new app
            appUsage = new AppUsage(null, new Date(), uid, package_name, networkType, tx_diff, rx_diff, 0, 0, boot_id);


         /*if (appUsage == null)
         {
            // Create new
            appUsage = new AppUsage(null, new Date(), uid, package_name, networkType, tx, rx, 0, 0, boot_id);
         }
         else
         {
            // Update
            appUsage.setTx(tx);
            appUsage.setRx(rx);
         }*/

            try {
                // master
                appUsageDao.insertOrReplace(totals);
            } catch (DaoException e) {
                e.printStackTrace();
            }

            try {
                appUsageDao.insertOrReplace(appUsage);
            } catch (DaoException e) {
                e.printStackTrace();
            }

            //apps.put(app.uid, new DataUsageItem(app.uid, app.packageName, pm.getApplicationLabel(app).toString()));
        }
    }
like image 280
Zidane Avatar asked May 12 '16 08:05

Zidane


1 Answers

despite what the documentation says traffic stats doesnt seem to work well on 4.3 in the sense that in some instances it works for some app id and not for some , therefore I would bypass the whole trafficstats class and create two custom methods pointing to the native c file that contains app usage data to retrieve tx(transmitted data) and Rx(received data) within the same class

   long tx = yourClass.getUidTxBytes(uid);
    long rx = yourClass.getUidRxBytes(uid);

Then for RX

public static Long getUidRxBytes(int uid) {
        BufferedReader reader;
        Long rxBytes = 0L;
        try {
            reader = new BufferedReader(new FileReader("/proc/uid_stat/" + uid
                    + "/tcp_rcv"));
            rxBytes = Long.parseLong(reader.readLine());
            reader.close();
        }
        catch (FileNotFoundException e) {
            rxBytes = TrafficStats.getUidRxBytes(uid);
            //e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        return rxBytes;
    }**

Then for TX

 public static Long getUidTxBytes(int uid) {
        BufferedReader reader;
        Long txBytes = 0L;
        try {
            reader = new BufferedReader(new FileReader("/proc/uid_stat/" + uid
                    + "/tcp_snd"));
            txBytes = Long.parseLong(reader.readLine());
            reader.close();
        }
        catch (FileNotFoundException e) {
            txBytes = TrafficStats.getUidTxBytes(uid);
            //e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        return txBytes;
    }
like image 108
FlyBYNight Avatar answered Oct 26 '22 06:10

FlyBYNight