即使在Android N上,如何获取应用(或总体)的当前网络使用情况?

时间:2016-09-04 06:50:46

标签: android networking

正如标题所说。我想知道特定应用在特定时间每秒使用的字节数。

也许我可以使用“netstat”命令?但如果是这样,我如何将其过滤到特定的应用/流程?

我是否还需要获得一些许可?

目前人们说使用TrafficStats.getUidRxBytes(packageInfo.uid),但是,从这里:https://developer.android.com/reference/android/net/TrafficStats.html#getUidRxBytes(int),它表示N不支持它,我应该使用NetworkStatsManager。有没有使用它的例子?

也许合并后的解决方案?

编辑:我尝试在Android N上使用NetworkStatsManager,但我失败了。我找不到任何关于如何使用它的示例,并且关于它的所有stackOverflow问题都是类似的,因为它无法很好地使用它。如果有人知道如何使用它,请写下来。

3 个答案:

答案 0 :(得分:19)

NetworkStats的用法并不复杂。

设备API级别必须至少为23.以下是开始使用NetworkStatsManager之前所需的一些步骤

  1. AndroidManifest.xml中声明所需的权限:

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission
        android:name="android.permission.PACKAGE_USAGE_STATS"
        tools:ignore="ProtectedPermissions"/>
    
  2. 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。但是,这是正常的权限,因此可以requested as any other permission

  3. 使用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);
    

    不幸的是,根据this piece of code获取统计数据仅适用于ConnectivityManager.TYPE_MOBILEConnectivityManager.TYPE_WIFI

  4. 制作样本Github repo,说明用法。

答案 1 :(得分:7)

还有一种复杂的方法来获取统计信息,但这适用于所有适配器:(但它很昂贵,因为你必须不断读取文件),

  1. 您可以在此处查看所有适配器和已发送/已接收的数据:
  2. cat /proc/net/dev
    
    1. 您可以从这些文件中获取每个适配器的统计信息:
    2. cat /sys/class/net/**wlan0**/statistics/**rx**_bytes
      

      wlan0 可能是您的所有适配器,但您需要在应用中维护该值,因为如果您关闭/打开适配器,该值将再次为0。 (您可以拥有RX和TX值)

      1. 您可以获取有效的,当前正在发送/接收的应用列表
      2. cat /proc/net/**tcp6**
        

        这也可以通过 tcp tcp6 更新 upd6

        来完成

        在这里你有&#34; uid&#34;列,这是您安装的应用程序的UID。 (所以应用程序现在正在使用网络)

        从这个文件中你也可以看到连接端点。

        1. 检查每个应用程序的发送/接收字节数(如TrafficStats API调用)
        2. cat /proc/uid_stat/**10348**/tcp_snd
          

          这里的 id 是应用程序UID。 您已发送: tcp_snd 和收到的: tcp_rcv 文件。

          1. 您还可以执行以下操作和UID匹配:
          2. cat /proc/**17621**/status
            

            此处的ID是您可以从中获取的进程ID。 顶部命令。 在状态文件中,您将拥有UID,即已安装的/系统应用UID。

            1。你也可以看看这个文件,TrafficStats API使用这个:

            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
            

            因此,将第一个答案与这些知识混合起来,您可以获得更多更好的统计数据。

答案 2 :(得分:1)

添加我的简化功能可以通过/ 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;
}