TrafficStats Api android and calculation of daily data usage - android

Have a confusion over following two methods of TrafficStats of Android:
getUidTxBytes(int uid) and getUidRxBytes(int uid) ,
These two methods return the number of bytes transmitted and received through the network for this UID. But what is the time unit of it, is it per second?
If I want to calculate data transmitted and received per day per app, what should I do. I thought one way, to store data in sql and keep on adding data to the table. Is it proper way?

These are counters "since the interface went up" or "since the application with this UID has started". So say if your phone goes into "Airplane mode" and then back, the counters might start from zero again. If you need per-second values, you'll need to call these functions every second, and then use the delta from the last call. If the delta is negative, just use the value as-is, it means the counter started from zero again.
One more thing: As far as I know, these counters count TCP/IP only. Not UDP. So if you need a very precise accounting, and the application in question uses UDP/IP, or any other protocol besides TCP, these counters will be wrong.
For the insight how this function works, look at the source of Android, freely available. File in question is ./frameworks/base/core/jni/android_net_TrafficStats.cpp
This function gets the data from /proc/uid_stat/[uid]/tcp_snd. If you need more info about that, you'll need to dive into the Linux kernel...

These counters contain the byte count since the last reboot. One some phones these counters may periodically reset, but most of the time they only reset after a reboot. Going into airplane mode or changing between mobile and Wi-Fi will not reset these counters.
One important point is that these counters do not include packet overhead, only payload size. So typically this would mean 3-4% of the data may be unaccounted for. However, if it is a streaming, torrent or VoIP app where packet payloads are small, there may be a much higher amount of data unaccounted for.
Interestingly, getTotalRxBytes (received bytes across all interfaces, ex mobile and Wi-Fi combined) and getMobileRxBytes (received bytes only on the mobile interface) include all bytes including overhead. So basically, your app byte count total will be less that your interface byte count total, and therefore less than the amount of data your network operator is billing you for.
One last point, most streaming apps don't account for their data under their own UID. They are accounted under the system.media UID. So if you are monitoring data usage for YouTube, only a very small amount of data will actually appear under that app; the rest will be under the media UID (1013).

Here, I getting those apps, which has permission of Internet,
You can change the Permission name and get apps as per you needed.
ArrayList<AppObject> listApps;
public void getAllAppList() {
listApps = new ArrayList<AppObject>();
PackageManager p = getPackageManager();
List<ApplicationInfo> packages = p.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo applicationInfo : packages) {
try {
PackageInfo packageInfo = p.getPackageInfo(applicationInfo.packageName, PackageManager.GET_PERMISSIONS);
String[] permissions = packageInfo.requestedPermissions;
for (String permissionName : permissions) {
if (permissionName.equals("android.permission.INTERNET")) {
ApplicationInfo appInfo = packageInfo.applicationInfo;
AppObject appObject = new AppObject();
appObject.appDrawable = getPackageManager().getApplicationIcon(appInfo);
appObject.appName = (String) getPackageManager().getApplicationLabel(appInfo);
appObject.dataUsage = getDataUsage(appInfo);
listApps.add(appObject);
}
}
} catch (NullPointerException e) {
e.printStackTrace();
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
Debug.e("APP_SIZE", ":" + listApps.size());
appsAdapter.addAll(listApps);
}
public String getDataUsage(ApplicationInfo appInfo) {
int uid = appInfo.uid;
double received = (double) TrafficStats.getUidRxBytes(uid) / (1024 * 1024);
double sent = (double) TrafficStats.getUidTxBytes(uid) / (1024 * 1024);
double total = received + sent;
return String.format("%.2f", total) + " MB";
}

getUidRxBytes() and getUidTxBytes() are basically used for received and transmitted bytes respectively. To monitor your data for each app just find the uid of each process and find the corresponding data to each process and that will be your data for each app and then you can use this code for calculations.
TextView totData = (TextView)findViewById(R.id.totData);
TextView wifiTot = (TextView)findViewById(R.id.wifitotData);
TextView wifiTX = (TextView)findViewById(R.id.wifiUpData);
TextView wifiRX = (TextView)findViewById(R.id.wifiDownData);
TextView mobileTot = (TextView)findViewById(R.id.mobtotData);
TextView mobTX = (TextView)findViewById(R.id.mobUpData);
TextView mobRX = (TextView)findViewById(R.id.mobDownData);
/*
* Converting bytes to MB
*/
long rxBytes = TrafficStats.getTotalRxBytes()/1048576;
long txBytes = TrafficStats.getTotalTxBytes()/1048576;
long mobUpload = TrafficStats.getMobileTxBytes()/1048576;
long mobDown = TrafficStats.getMobileRxBytes()/1048576;
long wifiUpload = txBytes-(mobUpload);
long wifiDown = rxBytes-(mobDown);
wifiRX.setText(Long.toString(wifiDown));
wifiTX.setText(Long.toString(wifiUpload));
long wifitot = wifiUpload+wifiDown;
wifiTot.setText(Long.toString(wifitot));
mobTX.setText(Long.toString(mobUpload));
mobRX.setText(Long.toString(mobDown));
long mobTot = mobUpload+mobDown;
mobileTot.setText(Long.toString(mobTot));
totData.setText(Long.toString(wifitot+mobTot));

Related

How to avoid data leakage and thread blocking while writing data on a file on android

I'm working with android sensors and have a method inside a listener that keeps appending data on a string builder with really high frequency. After some data is collected I compress the string with gzip and write it on a file to avoid out of memory exceptions. This keeps repeating forever. This is all in the same thread so as the file gets bigger it starts to block the thread and the data appending on the string. I do create new files if they get too large but i think i need to implement a threading and lock mechanism for the compression and file writing to avoid any blocking but at the same time not have any problems with leakage of data. Can anyone help me with that? Im not sure if im wording my question correctly.
// on rotation method of gyroscope
#Override
public void onRotation(long timestamp,float rx, float ry, float rz) {
try {
//get string of new lines of the write data for the sensor
str.append("gyroTest,userTag=testUser,deviceTag="+deviceName+" rx="+rx+",ry="+ry+",rz="+rz+" "+timestamp+"\n");
if(count >=2000){
b = GZIPCompression.compress(str);
Log.i(FILE_TAG, "Write gyroscope file");
FileHandling.testWrite( GYROSCOPE,b);
str.setLength(0);
count=0;
}
count++;
} catch (Exception e) {
e.printStackTrace();
}
}
You're on the right track in that you need to separate reading from the sensor, processing the data, and writing it all back to disk.
To pass the data from the sensor reads, you may consider using something like a LinkedBlockingQueue with your Strings.
private LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>();
#Override
public void onRotation(long timestamp, float rx, float ry, float rz) {
queue.add(
"gyroTest,userTag=testUser,deviceTag="+deviceName+" rx="+rx+",ry="+ry+",rz="+rz+" "+timestamp+"\n"
);
}
And then in another Thread, looping until canceled, you could drain the queue, process, and write without blocking the reading (main) Thread.
private boolean canceled = false;
private void startProcessingQueue() {
Runnable processQueueRunnable = new Runnable() {
#Override
public void run() {
while (!canceled) {
drainQueueAndWriteLog();
Thread.sleep(250);
}
}
};
new Thread(processQueueRunnable)
.start();
}
private void drainQueueAndWriteLog() {
List<String> dequeuedRotations = new ArrayList<String>();
queue.drainTo(dequeuedRotations);
if (0 < dequeuedRotations.size()) {
// Write each line, or all lines together
}
}
Note: take care to ensure the runnable is canceled when your Activity is paused.
As mentioned in your question, the more data you're writing, the slower it's going to be. Since you're writing data from a sensor, it's inevitably going to grow. For this, you could partition your files into smaller segments, by using something like a date-based naming convention for your log files.
For instance, a log name pattern of yyyyMMddHHmm would create minute-spaced log files, which you could then later aggregate and sort.
private SimpleDateFormat logFileDateFormat = new SimpleDateFormat("yyyyMMddHHmm");
private String getCurrentLogFileName() {
return String.format(
"rotations-%s.log",
logFileDateFormat.format(new Date())
);
}
Just keep in mind that since you're not writing in the same thread you're reading from, your timestamps may not match up perfectly with your log file names. This shouldn't be a problem, though, as you're already including the timestamps in the persisted data.
Further down the line, if you're still finding you're not quite hitting the level of write-throughput that your project requires, you may also want to consider condensing the amount of information you're actually storing by encoding common byte usages, or even reducing the length of each key to their most-unique values. For example, consider this 1 line output:
"gyroTest,userTag=testUser,deviceTag=some-device-name rx=12345,ry=4567,rz=87901872166251542545144\n"
And now reducing the keys:
"gyroTest,u=testUser,d=some-device-name x=12345,y=4567,z=87901872166251542545144\n"
Removes 18 characters from every line that needs to be written, without sacrificing any information.
Also worth noting: you either need a space (or better a comma) before the timestamp in your data line, else you won't be able to nicely pick out rz from it. And your deviceName should be escaped with quotation marks if it can contain spaces, else it will conflict with pulling out rx.

System.currentTimeMillis() returns incorrect timestamp on Huawei

The issue is that System.currentTimeMillis() returns the wrong milliseconds with different ranges of time mainly within the future sometimes up to 6 months, but it varies from a few seconds to months.
The device that this is occurring on is a Tablet model Huawei M2-A201W on android 5.1.1 the kernel version is: **3.10.74-gdbd9055**
My first assumption was that the NTP was somehow messing up with the time but I have thousands of those tablets and some of them have no network connection, no SIM card so no GSM/3G/4G.
Im using the System.currentTimeMillis() to save in a column for a table for when was a row created in the local sqlite database.
This anomally happens very often(30% of each System.currentTimeMillis() call) on the tablets that I use.
As a workaround for using System.currentTimeMillis(), maybe you can let sqlite handle the timestamp creation and see if that solves your problem?
Define/Alter your "created"-column with timestamp default current_timestamp or with default(strftime('%Y-%m-%d %H:%M:%f', 'now')) if you need milliseconds as well, like this:
sqlite> create table my_table(id integer primary key autoincrement not null, name text, created timestamp default(strftime('%Y-%m-%d %H:%M:%f', 'now')) not null);
sqlite> insert into my_table(name) values ('MyTestRow1');
sqlite> insert into my_table(name) values ('MyTestRow2');
sqlite> select * from my_table;
1|MyTestRow1|2017-08-07 10:08:50.898
2|MyTestRow2|2017-08-07 10:08:54.701
When you don't have SIM card so no GSM/3G/4G, your phone can't update correct time based on the network provided time/zone.
So, devices with the network show the correct time, while other devices without the network can show incorrect time -- you have to manually set the correct time. System.currentTimeMilis() reads the time from your system. g But on power turn, the clock works.
Check if NTP (UDP port 123) is blocked by apps using Socket or DatagramSocket. Note: NTP applies to the scenario where clocks of all hosts or routers on the network must be the same. If your device switch to two (or more) different network and gets time updated from different sources, it can fluctuate time.
Ultimately, your system time is being changed, that's why it is fluctuating. If you manually System.currentTimeMilis() after you manually disable automatic date and time, I believe, it doesn't fluctuate (no anomaly). If this is the case then your Huewai tablet doesn't have bugs.
The java API call System.currentTimeMillis() in Android platform use the POSIX api gettimeofday to get the time in milli seconds. See here.
static jlong System_currentTimeMillis(JNIEnv*, jclass) {
timeval now;
gettimeofday(&now, NULL);
jlong when = now.tv_sec * 1000LL + now.tv_usec / 1000;
return when;
}
It assume every call to gettimeofday will be successful. I guess your problem might happen here.
It's better to check the return value of every API call and determine what to do next if error happen.
So I suggest a more reliable method in JNI with your own implementation like below. Call these POSIX APIs in order, if gettimeofday failed, call clock_gettime, if it failed again, call time.
struct timeval now;
if (gettimeofday(&now, NULL) != 0) {
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
now.tv_sec = ts.tv_sec;
now.tv_usec = ts.tv_nsec / 1000LL;
} else {
now.tv_sec = time(NULL);
now.tv_usec = 0;
}
}
jlong when = now.tv_sec * 1000LL + now.tv_usec / 1000LL;
__android_log_print(ANDROID_LOG_INFO, "TAG", "%lld", when);
What about fetching the timestamp natively by running "date +%s" command in Linux kernel?
Here, "+%s" is seconds since 1970-01-01 00:00:00 UTC. (GNU Coreutils 8.24 Date manual)
try {
// Run the command
Process process = Runtime.getRuntime().exec("date +%s");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
// Grab the results
StringBuilder log = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
If you print this,
Log.e("unix_time: ", "" + log.toString());
You'll get an Unix timestamp e.g. 1502187111
To convert it back to a date object, multiply by 1000, since java is expecting milliseconds,
Date time = new Date(Long.parseLong(log.toString()) * 1000);
Log.e("date_time: ", "" + time.toString());
This will give you a plain date format. e.g. Tue Aug 08 16:15:58 GMT+06:00 2017
Since you mentioned that most of the calls are getting the proper time and it only happens 30% of the cases, I would create an receiver for ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED intent broadcasts to find out when the time changes. Maybe this will give you a clue on what is changing the time.
Together with the ConnectivityManager you can detect if the device is connected and what type of a connection you have, maybe some connection is triggering the time change.
// init the register and register the intents, in onStart, using:
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
getNetworkInfo();
if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction()))
Log.d(this.getClass().getName(), "Detected a time change. isWifiConn: " +
isWifiConn + " isMobileConn: " + isMobileConn);
if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction()))
Log.d(this.getClass().getName(), "Detected a timezone change. isWifiConn: " +
isWifiConn + " isMobileConn: " + isMobileConn);
}
};
IntentFilter filters = new IntentFilter();
filters.addAction(Intent.ACTION_TIME_CHANGED);
filters.addAction(Intent.ACTION_TIMEZONE_CHANGED);
registerReceiver(receiver, filters);
Log.d(DEBUG_TAG, "Receiver registered");
// do not forget to unregister the receiver, eg. onStop, using:
unregisterReceiver(receiver);
//...
private void getNetworkInfo() {
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
isWifiConn = networkInfo.isConnected();
networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
isMobileConn = networkInfo.isConnected();
Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn);
Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn);
}
Does this device have a real hardware RTC? I couldn't find a definitive answer from googling and reading spec sheets. A run of:
$ dmesg -s 65535 | grep -i rtc
from a shell should give you an answer. You should see something like this (will vary with chipset and kernel version):
[ 3.816058] rtc_cmos 00:02: RTC can wake from S4
[ 3.816429] rtc_cmos 00:02: rtc core: registered rtc_cmos as rtc0
[ 3.816510] rtc_cmos 00:02: alarms up to one month, y3k, 242 bytes nvram, hpet irqs
If there is no message returned by grep (and you grepped against the whole kernel message buffer), then there's your answer. You have no clock to keep time on these devices. You will always need NTP and a working network connection to the Internet to keep such a device without a clock chip in sync with world time.
RTC: https://en.wikipedia.org/wiki/Real-time_clock

Is there a way to synchronize clocks with the Microsoft Band using the SDK?

I'm working on a project where I need sensor data readings from the Band and a connected smartphone to be synchronized. Thus, I need to be able to find out the clock difference between both devices. Events contain a timestamp, which I could use for synchronization, but this would require a way to reliably force the Band to send a sensor reading directly on request.
The smartphone requests a sensor reading from the Band (f.e. by registering an event listener) and notes the local time t1 of the request transmission
The Band receives the request and directly responds to it, sending its local timestamp s1
The smartphone receives the response at local time t2.
Now, the smartphone can approximate the connection delay d = (t2 - t1)/2 and can set its local time to s1 + d to approximately synchronize with the Band. This protocol only works properly if the Band responds within a reasonable time.
Does getSensorManager().registerXXXEventListener() behave like this or is there a possibility that it delays the response (f.e. to save energy)? If it may introduce delays, is there some other way to get the Band's current time?
There seems to be an automatic synchronization. If you set the clock of the band to some other time and print the timestamp of the SDK you will notice that it corresponds to the phone time, not the band time.
So I guess there is no need for time synchronization between phone and band.
Grab a sensor and hook the appropriate timestamp? Don't have band with me but I believe ISensorReading:: Timestamp comes from the device?
As defined, pulled out of object browser...
Let us know if this works...
namespace Microsoft.Band.Sensors
{
public class BandSensorReadingEventArgs<T> : EventArgs where T : IBandSensorReading
{
public BandSensorReadingEventArgs(T reading);
public T SensorReading { get; }
}
}
System.DateTimeOffset Timestamp { get; } Member of Microsoft.Band.Sensors.IBandSensorReading
private async void HeartRate_ReadingChanged(object sender, BandSensorReadingEventArgs<IBandHeartRateReading> e)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
TextBlock_HeartBeatStatus.Text = e.SensorReading.HeartRate.ToString();
DateTimeOffset timestamp = e.SensorReading.Timestamp;
});
}
private async void Accelerometer_ReadingChanged(object sender, BandSensorReadingEventArgs<IBandAccelerometerReading> e)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
string status =
$"x:{e.SensorReading.AccelerationX.ToString("F1")} y:{e.SensorReading.AccelerationY.ToString("F1")} z:{e.SensorReading.AccelerationZ.ToString("F1")}";
TextBlock_AccelStatus.Text = status;
});
DateTimeOffset timestamp = e.SensorReading.Timestamp();
}

How do I programmatically show data usage of all applications?

On Android 4.0 onwards we have data usage control options in the phone. Please check the attached screen shot for further understanding.
http://developer.android.com/about/versions/android-4.0-highlights.html
Now I have some requirement to check these things (All Application's Data usage in specific time period/specific days) from my application. How can I achieve this? I am also using the below class for Network Usage details.
http://developer.oesf.biz/em/developer/reference/eggplant/android/net/NetworkStatsHistory.html
Please check the below link images. I need to develop the same kind of application.
http://developer.android.com/sdk/images/4.0/usage-all-lg.png
http://developer.android.com/sdk/images/4.0/usage-maps-lg.png
Thanks for sharing your code, but I need to know data used by each application instead of all applications. So far I observed in the links no one is talking about data usage of individual applications. I already know how to show installed applications in the device. Now I would like to know what's the data used by each and every application.
I am using the below code for list of installed applications in the device.
private ArrayList<PInfo> getInstalledApps(boolean getSysPackages) {
ArrayList<PInfo> res = new ArrayList<PInfo>();
List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);
for (int i=0; i<packs.size(); i++) {
PackageInfo p = packs.get(i);
if ((!getSysPackages) && (p.versionName == null)) {
continue ;
}
PInfo newInfo = new PInfo();
newInfo.setAppname(p.applicationInfo.loadLabel(getPackageManager()).toString());
newInfo.setPname(p.packageName);
newInfo.setVersionName(p.versionName);
newInfo.setVersionCode(p.versionCode);
newInfo.setIcon(p.applicationInfo.loadIcon(getPackageManager()));
res.add(newInfo);
}
return res;
}
How do I know what's the data used by each application?
Actually, I need a solution which gives data usage of applications in a given time period, i.e. in between two days.
Old Answer (Mostly work for devices below Api level 23)
First, get a list of all running apps' process info:
List<RunningAppProcessInfo>
Then get the UID of every app and get then send and receive traffic of the app:
// Get running processes
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningApps = manager.getRunningAppProcesses();
for (RunningAppProcessInfo runningApp : runningApps) {
// Get UID of the selected process
int uid = ((RunningAppProcessInfo)getListAdapter().getItem(position)).uid;
// Get traffic data
long received = TrafficStats.getUidRxBytes(uid);
long send = TrafficStats.getUidTxBytes(uid);
Log.v("" + uid , "Send :" + send + ", Received :" + received);
}
Edited Answer
There are some more options to get network usage :
NetworkStatsManager - So NetworkStatsManager is an option which is also provides required info but it has a drawback i.e. This API is available only on Marshmallow(API level 23) or higher. For the devices below to api 23 the my old answer can be used.
According to the official documentation:
[NetworkStatsManager] provides network traffic statistics. These
statistics include bytes transmitted and received and network packets
transmitted and received, over all interfaces, over the mobile
interface, and on a per-UID basis.
So to use NetworkStatsManager :
Declare required permissions in AndroidManifest file :
<uses-permission android:name="android.permission.READ_PHONE_STATE" / >
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" / >
Since “android.permission.PACKAGE_USAGE_STATS” is a system level
permission we will need to handle the request in a different manner.
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;
}
This permission can be granted from the Settings -> Security -> Apps with usage access screen. To ask for this permission, simply start an activity with Settings.ACTION_USAGE_ACCESS_SETTINGS Intent to help the user to get there:
startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
Once everything has been set up you can get an instance of NetworkStatsManager which we will need to fetch network usage data:
NetworkStatsManager networkStatsManager = (NetworkStatsManager) context.getSystemService(Context.NETWORK_STATS_SERVICE);
Whatever query you will perform, you will get as a result a NetworkStats.Bucket or a NetworkStats (which is basically a container for multiple buckets with methods hasNextBucket() and getNextBucket() to access the real data (also remember to use close() before the object is out of scope).
In every query you will have to specify the network type (ConnectivityManager.TYPE_WIFI or ConnectivityManager.TYPE_MOBILE).
Subscriber Id required to make query and it remains same unless the user switches SIM card or carrier. To get that
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String subscriberId = manager.getSubscriberId();
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 uid = info.uid;
UIDs used for the network usage caused by :

Unistalled apps : UID_REMOVED
Tethering : UID_TETHERING
Android OS : SYSTEM_UID
To get stats for all apps : UID_ALL
Some example queries:
To get all Rx and Tx bytes of Mobile :
NetworkStats.Bucket bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE, getSubscriberId(context, ConnectivityManager.TYPE_MOBILE), 0, System.currentTimeMillis());
 
bucket.getRxBytes();
bucket.getTxBytes();
To get all Rx and Tx bytes of Wifi :
NetworkStats.Bucket bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_WIFI, ””, 0, System.currentTimeMillis());
bucket.getRxBytes();
bucket.getTxBytes();
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();
To get all Rx and Tx bytes of Wifi for package :
NetworkStats.Bucket bucket = networkStatsManager.queryDetailsForUid(ConnectivityManager.TYPE_WIFI, “”, 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();
Note :
Those queries should never be performed on the main thread or
they will cause your app to drop frame.
NetworkStatsManager.query* throws RemoteException
Roaming and tag were added in API level 24 (Android 7.0 Nougat) so if you’re targeting Marshmallow (API level 23) you won’t be able to use those.
Since API level 24 (Android 7.0 Nougat) you can use NetworkStatsManager without the PACKAGE_USAGE_STATS permission if you only want to get your app data. You’d still need it if your goal is to access other apps’ stats.
2. TrafficStats : It also provides required info but there are some drawbacks which makes it unreliable at least :
Data resets after every reboot
It may also be unsupported on some devices.
Some example methods of TrafficStats:
- To get Total Rx bytes - TrafficStats.getTotalRxBytes();
- To get Total Tx bytes - TrafficStats.getTotalTxBytes();
- To get all Mobile Rx bytes - TrafficStats.getMobileRxBytes();
- To get all Mobile Tx bytes - TrafficStats.getMobileTxBytes();
- To get all Wifi Rx bytes - TrafficStats.getTotalRxBytes() - TrafficStats.getMobileRxBytes();
- To get all Wifi Tx bytes - TrafficStats.getTotalTxBytes() - TrafficStats.getMobileTxBytes();
- To get Package Rx Bytes : - TrafficStats.getUidRxBytes(packageUid);
- To get Package Tx Bytes : - TrafficStats.getUidTxBytes(packageUid);
You can use the android.net.TrafficStats for getting the network usage details.
Please find a sample program below for the same.
package com.anchit.trafficstatus;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
public class TrafficStatus extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("bytes recvd", "" + android.net.TrafficStats.getMobileRxBytes());
Log.e("Total", "Bytes received" + android.net.TrafficStats.getTotalRxBytes());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
The solution from Arunendra, dated 2015, didn't immediately work for me on SDK 28 (Pie).
So I modified as follows:
void networkUsage() {
// Get running processes
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningApps = manager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo runningApp : runningApps) {
long received = TrafficStats.getUidRxBytes(runningApp.uid);
long sent = TrafficStats.getUidTxBytes(runningApp.uid);
Log.d(LOG_TAG, String.format(Locale.getDefault(),
"uid: %1d - name: %s: Sent = %1d, Rcvd = %1d", runningApp.uid, runningApp.processName, sent, received));
}
}
Note that the statistics returned by this class reset and start from zero after every reboot. To access more robust historical network statistics data, use NetworkStatsManager instead.
Src: https://developer.android.com/reference/android/net/TrafficStats
Please look at this answer for detailed info on how to use NetworkStatsManager: https://stackoverflow.com/a/39412045/6341943

TrafficStats.getTotalRxBytes doesnt count videoview's traffic flow

i'm making a soft to play online video, and i'm trying to add a traffic statistic feature tot the soft. I try to use TrafficStats and getUidRxBytes function. however, it doesnt count the videoview's net traffic.
Like the following code ,i can see the rx(return by getTotalRxBytes) increase a lot, but the myapprx(return by getUidRxBytes) doesnt change.
int uid = VideoViewPlayer.this.getApplicationInfo().uid;
long rx = TrafficStats.getTotalRxBytes();
long tx = TrafficStats.getTotalTxBytes();
long myapprx = TrafficStats.getUidRxBytes(uid);
long myapptx = TrafficStats.getUidTxBytes(uid);
String info = "uid:"+uid+" rx:"+rx+" tx:"+tx+" myrx:"+myapprx+" mytx:"+myapptx;
UPDATE
Thanks first, your comment gives me important clue. And I'm trying to find the uid responsable for steaming media. I use the following code.However i cannt find the process that comsume the traffic.
List<ActivityManager.RunningAppProcessInfo> appProcessList = am.getRunningAppProcesses();
ActivityManager.RunningAppProcessInfo info=null;
//List<ActivityManager.RunningServiceInfo> appProcessList = am.getRunningServices(100);
//ActivityManager.RunningServiceInfo info = null;
strinfo = "";
long max =0;
for(int i=0;i<appProcessList.size();++i)
{
info = appProcessList.get(i);
String key = info.processName+"_" +info.uid;
if(mNetTraffic.containsKey(key))
{
long myrx = TrafficStats.getUidRxBytes(info.uid);
long lastrx = mNetTraffic.get(key).longValue();
mNetTraffic.put(key, new Long(myrx));
if(myrx-lastrx>max && myrx - lastrx>0)
{
max = myrx-lastrx;
strinfo = key +":"+max;
}
}else
{
long myrx = TrafficStats.getUidRxBytes(info.uid);
mNetTraffic.put(key, new Long(myrx));
}
}
//trying to watch the key and max and find process and uid, sadly cant find it
Streaming media should be reported for a different UID, as it is actually streamed and played by an Android internal process and module (OpenCORE or StageFright, depending on Android version).
I had the same issue and managed to find out what UID the process has that streams media: the UID is 1013
http://forum.xda-developers.com/showthread.php?t=442557
http://android-dls.com/wiki/index.php?title=Android_UIDs_and_GIDs
Hope it helps :)

Categories

Resources