As the title says. I wish to know how many bytes per second a specific app use at specific time.
Maybe I can use "netstat" command? But if so, how can I filter it to a specific app/process ?
Do I also need to have some permission to do it?
Currently people say to use TrafficStats.getUidRxBytes(packageInfo.uid) , but, from here: https://developer.android.com/reference/android/net/TrafficStats.html#getUidRxBytes(int) , it says it's not supported from N , and that I should use NetworkStatsManager instead. Is there any example to use it?
Maybe a merged solution?
EDIT: I tried to use NetworkStatsManager on Android N, but I failed. I can't find any sample of how to use it, and all stackOverflow questions about it were similar in term of not being able to use it well. Please, if anyone knows how to use it, write about it.
Description. Powerful tool that displays and monitors (tracks) all inbound and outbound connection from and to your Android device. A low-level connections capture module ensures best performance with a minimal battery usage. Works on NO ROOT phones too.
The usage of NetworkStats
is not complicated.
The device API level must be at minimum 23. Here are some steps required prior to starting the usage of NetworkStatsManager
Declare the required permissions in AndroidManifest.xml
:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions"/>
Ask for permission in Activity
android.permission.PACKAGE_USAGE_STATS
is not a normal permission, therefore cannot be simply requested. In order to check, whether the permission has been granted, check:
AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), getPackageName());
if (mode == AppOpsManager.MODE_ALLOWED) {
return true;
}
To ask for this permission, simply call Intent
:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
Another permmission is also needed: Manifest.permission.READ_PHONE_STATE
. However, this is normal permission so can be requested as any other permission
Use NetworkStatsManager
:
To obtain it's reference, call:
NetworkStatsManager networkStatsManager = (NetworkStatsManager) getApplicationContext().getSystemService(Context.NETWORK_STATS_SERVICE);
Everything that is retrieved from NetworkStatsManager
is packed into Buckets
. This is just a simple POJO, that holds the data.
GLOBAL:
To get the overall usage for WiFi:
NetworkStats.Bucket bucket;
try {
bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_WIFI,
"",
0,
System.currentTimeMillis());
} catch (RemoteException e) {
return -1;
}
from NetworkStats.Bucket
, two methods can be called to get the usage (in Bps):
bucket.getRxBytes();
bucket.getTxBytes();
Obtaining the data for mobile network is harder. In order to obtain the Bucket
call:
public long getAllRxBytesMobile(Context context) {
NetworkStats.Bucket bucket;
try {
bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE,
getSubscriberId(context, ConnectivityManager.TYPE_MOBILE),
0,
System.currentTimeMillis());
} catch (RemoteException e) {
return -1;
}
return bucket.getRxBytes();
}
//Here Manifest.permission.READ_PHONE_STATS is needed
private String getSubscriberId(Context context, int networkType) {
if (ConnectivityManager.TYPE_MOBILE == networkType) {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.getSubscriberId();
}
return "";
}
APPLICATION:
For obtaining the data for specific application, read the documentation for queryDetailsForUID.
To get the package usage for WiFi:
NetworkStats networkStats = null;
try {
networkStats = networkStatsManager.queryDetailsForUid(
ConnectivityManager.TYPE_WIFI,
"",
0,
System.currentTimeMillis(),
packageUid);
} catch (RemoteException e) {
return -1;
}
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
networkStats.getNextBucket(bucket);
To get the package usage for Mobile:
NetworkStats networkStats = null;
try {
networkStats = networkStatsManager.queryDetailsForUid(
ConnectivityManager.TYPE_MOBILE,
getSubscriberId(context, ConnectivityManager.TYPE_MOBILE),
0,
System.currentTimeMillis(),
packageUid);
} catch (RemoteException e) {
return -1;
}
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
networkStats.getNextBucket(bucket);
Unfortunately, according to this piece of code getting statistics is only possible for ConnectivityManager.TYPE_MOBILE
and ConnectivityManager.TYPE_WIFI
.
Made a sample Github repo demostrating the usage.
There is also a complicated way to get statistics, but this should work for all adapters: (but it is expensive, because you have to read files continously),
cat /proc/net/dev
cat /sys/class/net/**wlan0**/statistics/**rx**_bytes
wlan0 could be all of your adapters, but you need to maintain the value in your app, because if you switch off/on the adapter, the value will be 0 again. (You can have RX and TX values)
cat /proc/net/**tcp6**
This also can be done with tcp, tcp6, upd, upd6
Here you have the "uid" column, which is the UID of your installed apps. (So that app is using the network right now)
From this file you can also see the connection endpoint.
cat /proc/uid_stat/**10348**/tcp_snd
The id here is the application UID. You have the sent: tcp_snd and the received: tcp_rcv files too.
cat /proc/**17621**/status
The id here is the process id what you can get from e.g. the top command. In the status file you will have the UID, which is the installed/system app UID.
+1. You can take a look also on this file, TrafficStats API uses this:
cat /proc/net/xt_qtaguid/stats
Headers:
idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
Values:
6 eth0 0x0 10005 0 0 0 80 2 0 0 0 0 0 0 80 2 0 0 0 0
7 eth0 0x0 10005 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
8 eth0 0x0 10007 0 11133 25 4751 24 11133 25 0 0 0 0 4751 24 0 0 0 0
9 eth0 0x0 10007 1 5965514 4358 102028 2327 5965514 4358 0 0 0 0 102028 2327 0 0 0 0
10 eth0 0x0 10014 0 95 1 40 1 95 1 0 0 0 0 40 1 0 0 0 0
So maybe mixing the first answer with this knowledge, you can have more and better statistics.
Adding my simplified function to get overall network usage via /proc/net/dev.
No unique permission is needed.
public static long[] getNetworkUsageKb() {
BufferedReader reader;
String line;
String[] values;
long[] totalBytes = new long[2];//rx,tx
try {
reader = new BufferedReader(new FileReader("/proc/net/dev"));
while ((line = reader.readLine()) != null) {
if (line.contains("eth") || line.contains("wlan")){
values = line.trim().split("\\s+");
totalBytes[0] +=Long.parseLong(values[1]);//rx
totalBytes[1] +=Long.parseLong(values[9]);//tx
}
}
reader.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
//transfer to kb
totalBytes[0] = totalBytes[0] / 1024;
totalBytes[1] = totalBytes[1] / 1024;
return totalBytes;
}
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