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()));
}
}
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With