Как получить текущее сетевое использование приложения (или в целом), даже на Android N?

Как говорится в названии. Я хочу знать, сколько байтов в секунду используется конкретное приложение в определенное время.

Может быть, я могу использовать команду netstat? Но если да, то как я могу отфильтровать его для конкретного приложения/процесса?

Нужно ли мне также иметь какое-то разрешение?

В настоящее время люди говорят использовать TrafficStats.getUidRxBytes(packageInfo.uid), но отсюда: https://developer.android.com/reference/android/net/TrafficStats.html#getUidRxBytes(int), он говорит, что он не поддерживается с N, и что Вместо этого я должен использовать NetworkStatsManager. Есть ли какой-нибудь пример для его использования?

Может быть, объединенное решение?

EDIT: я попытался использовать NetworkStatsManager на Android N, но мне не удалось. Я не могу найти какой-либо образец того, как его использовать, и все вопросы, связанные с stackOverflow об этом, были схожи в том смысле, что они не могут его хорошо использовать. Пожалуйста, если кто знает, как его использовать, напишите об этом.

Ответ 1

Использование 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, который содержит данные.

    GLOBAL:

    Чтобы получить общее использование WiFi:

    NetworkStats.Bucket bucket;
    try {
        bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_WIFI,
                "",
                0,
                System.currentTimeMillis());
    } catch (RemoteException e) {
        return -1;
    }
    

    из NetworkStats.Bucket, можно вызвать два метода для использования (в Bps):

    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 repo, демонстрирующий использование.

Ответ 2

Существует также сложный способ получить статистику, но это должно работать для всех адаптеров: (но это дорого, потому что вы должны постоянно читать файлы),

  • Здесь вы можете увидеть все свои адаптеры и отправленные/полученные данные:
cat /proc/net/dev
  1. Вы можете получить статистику для каждого адаптера из этих файлов:
cat /sys/class/net/**wlan0**/statistics/**rx**_bytes

wlan0 может быть всеми вашими адаптерами, но вам нужно поддерживать значение в своем приложении, потому что если вы выключите/активируете адаптер, значение снова будет 0. (У вас могут быть значения RX и TX)

  1. Вы можете получить активный, в настоящее время список отправителей/получателей.
cat /proc/net/**tcp6**

Это также можно сделать с помощью tcp, tcp6, upd, upd6

Здесь у вас есть столбец "uid", который является UID установленных приложений. (Так что приложение использует сеть прямо сейчас)

Из этого файла вы также можете увидеть конечную точку соединения.

  1. Проверить отправленные/полученные байты на приложение (например, вызовы API TrafficStats)
cat /proc/uid_stat/**10348**/tcp_snd

id - это UID приложения. Вы отправили: tcp_snd и полученные файлы: tcp_rcv.

  1. Вы также можете выполнить соответствующий процесс и UID с помощью:
cat /proc/**17621**/status

Идентификатор здесь - это идентификатор процесса, из которого вы можете получить, например. верхняя команда. В файле status у вас будет UID, который является UID установленного/системного приложения.

+1. Вы также можете посмотреть этот файл, API TrafficStats использует это:

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

значения:

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

Итак, возможно, смешав первый ответ с этими знаниями, вы можете получить больше и лучшую статистику.