Как узнать текущее использование приложения в сети (или всего) даже на Android N?
Как видно из названия. Я хочу знать, сколько байтов в секунду конкретное приложение использует в определенное время.
Может быть, я могу использовать команду " netstat"? Но если так, как я могу отфильтровать его для конкретного приложения / процесса?
Нужно ли мне также иметь разрешение на это?
В настоящее время люди говорят, что используют TrafficStats.getUidRxBytes(packageInfo.uid), но отсюда: https://developer.android.com/reference/android/net/TrafficStats.html, он говорит, что он не поддерживается N, и что я должен использовать NetworkStatsManager вместо этого. Есть ли пример, чтобы использовать его?
Может быть, объединенное решение?
РЕДАКТИРОВАТЬ: я пытался использовать NetworkStatsManager на Android N, но мне не удалось. Я не могу найти ни одного примера того, как его использовать, и все вопросы об этом в стеке были схожи с точки зрения того, что он не может его использовать. Пожалуйста, если кто-нибудь знает, как им пользоваться, напишите об этом.
2 ответа
Использование NetworkStats
не сложно.
Уровень API устройства должен быть как минимум 23. Вот несколько шагов, необходимых для начала использования NetworkStatsManager
Объявите необходимые разрешения в
AndroidManifest.xml
:<uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions"/>
Спросите разрешения в
Activity
android.permission.PACKAGE_USAGE_STATS
не является нормальным разрешением, поэтому не может быть просто запрошено. Чтобы проверить, было ли предоставлено разрешение, проверьте: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; }
Чтобы запросить это разрешение, просто позвоните
Intent
:Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); startActivity(intent);
Также необходимо другое разрешение:
Manifest.permission.READ_PHONE_STATE
, Однако это нормальное разрешение, поэтому его можно запросить как любое другое разрешение.использование
NetworkStatsManager
:Чтобы получить его, позвоните по телефону:
NetworkStatsManager networkStatsManager = (NetworkStatsManager) getApplicationContext().getSystemService(Context.NETWORK_STATS_SERVICE);
Все, что извлекается из
NetworkStatsManager
упакован вBuckets
, Это просто простой POJO, который содержит данные.ГЛОБАЛЬНЫЙ:
Чтобы получить общее использование WiFi:
NetworkStats.Bucket bucket; try { bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_WIFI, "", 0, System.currentTimeMillis()); } catch (RemoteException e) { return -1; }
от
NetworkStats.Bucket
для получения использования можно вызвать два метода (в бит / с):bucket.getRxBytes(); bucket.getTxBytes();
Получить данные для мобильной сети сложнее. Для того чтобы получить
Bucket
вызов: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 ""; }
ПРИЛОЖЕНИЕ:
Для получения данных для конкретного приложения прочитайте документацию для queryDetailsForUID.
Чтобы узнать, как использовать пакет для 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);
Чтобы получить пакет использования для мобильных устройств:
Unfortunalety 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);
К сожалению, в соответствии с этим фрагментом кода получение статистики возможно только для
ConnectivityManager.TYPE_MOBILE
а такжеConnectivityManager.TYPE_WIFI
,
Сделал пример репозитория Github, демонстрирующий использование.
Существует также сложный способ получения статистики, но он должен работать для всех адаптеров: (но это дорого, потому что вы должны постоянно читать файлы),
- Здесь вы можете увидеть все ваши адаптеры и отправленные / полученные данные:
cat /proc/net/dev
- Вы можете получить статистику по адаптеру из этих файлов:
cat /sys/class/net/**wlan0**/statistics/**rx**_bytes
wlan0 может быть всеми вашими адаптерами, но вам нужно сохранить значение в вашем приложении, потому что если вы выключите / включите адаптер, значение снова будет равно 0. (Вы можете иметь значения RX и TX)
- Вы можете получить активный, в данный момент отправляющий / получающий список приложений
cat /proc/net/**tcp6**
Это также можно сделать с помощью tcp, tcp6, upd, upd6
Здесь у вас есть столбец "uid", который является UID ваших установленных приложений. (Так что это приложение использует сеть прямо сейчас)
Из этого файла вы также можете увидеть конечную точку подключения.
- Проверять отправленные / полученные байты для каждого приложения (например, вызовы API TrafficStats)
cat /proc/uid_stat/**10348**/tcp_snd
Идентификатор здесь - это UID приложения. Вы также отправили: tcp_snd и полученные: tcp_rcv файлы.
- Вы также можете выполнить некоторые процессы и сопоставить UID с:
cat /proc/**17621**/status
Идентификатор здесь - это идентификатор процесса, который вы можете получить, например, из верхней команды. В файле состояния у вас будет UID, который является UID установленного / системного приложения.
+1. Вы также можете посмотреть на этот файл, API-интерфейс TrafficStats использует это:
cat /proc/net/xt_qtaguid/stats
Заголовки:
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
Ценности:
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
Так что, возможно, смешивая первый ответ с этими знаниями, вы можете получить больше и лучшую статистику.
Добавление моей упрощенной функции, чтобы получить общее использование сети через /proc/net/dev.
Нет уникального разрешения не требуется.
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;
}