如何获得Android Q上的应用程序的网络使用率?

and*_*per 5 networking android android-10.0

背景

我知道我们可以通过使用类似的东西(在过去,在这里询问)来获取指定应用程序的网络使用情况(到目前为止,从某个特定时间到目前为止移动和Wifi的总带宽使用量):

    private final static int[] NETWORKS_TYPES = new int[]{ConnectivityManager.TYPE_WIFI, ConnectivityManager.TYPE_MOBILE};

    long rxBytes=0L, txBytes=0L;
    final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    final String subscriberId = telephonyManager.getSubscriberId();
    final ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(packageName, 0);
    final int uid = applicationInfo.uid;
    for (int networkType : NETWORKS_TYPES) {
        final NetworkStats networkStats = networkStatsManager.queryDetailsForUid(networkType, subscriberId, 0, System.currentTimeMillis(), uid); 
        final Bucket bucketOut = new Bucket();
        while (true) {
                networkStats.getNextBucket(bucketOut);
                final long rxBytes = bucketOut.getRxBytes();
                if (rxBytes >= 0)
                    totalRx += rxBytes;
                final long txBytes = bucketOut.getTxBytes();
                if (txBytes >= 0)
                    totalTx += txBytes;
                if (!networkStats.hasNextBucket())
                    break;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

文件:

https://developer.android.com/reference/android/app/usage/NetworkStatsManager.html#queryDetailsForUid(int,%20java.lang.String,%20long,%20long,%20int)

也可以获取全局网络使用情况(使用TrafficStats.getUidRxBytes(applicationInfo.uid)TrafficStats.getUidTxBytes(applicationInfo.uid)),但这不是该线程的全部用途。

问题

似乎Android Q已计划导致许多设备标识功能停止工作,这getSubscriberId就是其中之一。

我尝试过的

我尝试将targetSdk设置为29(Q),然后查看尝试使用它时会发生什么。

不出所料,我遇到了一个异常,向我表明我不能再这样做了。它说 :

019-06-11 02:08:01.871 13558-13558/com.android.myapplication E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.android.myapplication, PID: 13558
    java.lang.SecurityException: getSubscriberId: The user 10872 does not meet the requirements to access device identifiers.
        at android.os.Parcel.createException(Parcel.java:2069)
        at android.os.Parcel.readException(Parcel.java:2037)
        at android.os.Parcel.readException(Parcel.java:1986)
        at com.android.internal.telephony.IPhoneSubInfo$Stub$Proxy.getSubscriberIdForSubscriber(IPhoneSubInfo.java:984)
        at android.telephony.TelephonyManager.getSubscriberId(TelephonyManager.java:3498)
        at android.telephony.TelephonyManager.getSubscriberId(TelephonyManager.java:3473)
Run Code Online (Sandbox Code Playgroud)

在Internet和此处搜索时,我没有看到此消息,但是我发现了有关类似问题的获取IMEI和其他标识符的信息:

因此,现在我只在这里作了一个错误报告(包括一个示例项目):

https://issuetracker.google.com/issues/134919382

问题

是否可以在Android Q上获得指定应用程序的网络使用率(定向到该应用程序时)?也许没有SubscriberId?

如果是这样,怎么办?

如果不是,是否可以通过拥有root或通过adb?


编辑:

好的,我不知道如何正式使用它,但是至少对于根访问而言,可以使用此解决方案此处找到,以便获得SubscriberId 。

意思是这样的:

@SuppressLint("MissingPermission", "HardwareIds")
fun getSubscriberId(telephonyManager: TelephonyManager): String? {
    try {
        return telephonyManager.subscriberId
    } catch (e: Exception) {
    }
    val commandResult = Root.runCommands("service call iphonesubinfo 1 | grep -o \"[0-9a-f]\\{8\\} \" | tail -n+3 | while read a; do echo -n \"\\u\${a:4:4}\\u\${a:0:4}\"; done")
    val subscriberId = commandResult?.getOrNull(0)
    return if (subscriberId.isNullOrBlank()) null else subscriberId
}
Run Code Online (Sandbox Code Playgroud)

当然,这不是官方的解决方案,但是总比没有好...

编辑:通过根获得它的部分是错误的。它没有任何帮助。

Ata*_*rim 2

您可以为 API 29 及更高版本提供 null 值。它返回 WIFI 和移动数据的值 \xe2\x80\x8b\xe2\x80\x8b。

\n

文档:

\n
\n

如果适用,网络接口的订阅者 ID。\n从 API 级别 29 开始,订阅者 ID 受到附加限制的保护。调用不满足新要求的应用程序访问订阅者 ID 时,可以在查询移动网络类型以接收所有移动网络的使用情况时提供空值。有关其他详细信息,请参阅 TelephonyManager.getSubscriberId()。

\n
\n

权限(不要忘记获得用户的许可):

\n
<uses-permission android:name="android.permission.READ_PHONE_STATE"\n    android:maxSdkVersion="28"/>\n<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"\n    tools:ignore="ProtectedPermissions" />\n
Run Code Online (Sandbox Code Playgroud)\n

示例代码:

\n
//network stats\nNetworkStatsManager networkStatsManager = (NetworkStatsManager) activity.getSystemService(Context.NETWORK_STATS_SERVICE);\nint[] networkTypes = new int[]{NetworkCapabilities.TRANSPORT_CELLULAR, NetworkCapabilities.TRANSPORT_WIFI};\nString subscriberId;\nif (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {\n   TelephonyManager telephonyManager = (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE);\n   try {\n     subscriberId = telephonyManager.getSubscriberId(); //MissingPermission\n   } catch (SecurityException e) {\n     subscriberId = null;\n   }\n\n} else {\n   subscriberId = null;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

获取应用程序的 NetworkStats:

\n
long receivedBytes = 0;\nlong transmittedBytes = 0;\n\nfor (int networkType : networkTypes) {\n    NetworkStats networkStats;\n    try {\n        networkStats = networkStatsManager\n                .queryDetailsForUid(networkType,\n                        subscriberId,\n                        0,\n                        System.currentTimeMillis(),\n                        appUid);\n    } catch (SecurityException e) {\n        networkStats = null;\n    }\n\n    if(networkStats != null) {\n        NetworkStats.Bucket bucketOut = new NetworkStats.Bucket();\n        while (networkStats.hasNextBucket()) {\n            networkStats.getNextBucket(bucketOut);\n            long rxBytes = bucketOut.getRxBytes();\n            long txBytes = bucketOut.getTxBytes();\n            if (rxBytes >= 0) {\n                receivedBytes += rxBytes;\n            }\n            if (txBytes >= 0) {\n                transmittedBytes += txBytes;\n            }\n        }\n        networkStats.close();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n


归档时间:

查看次数:

461 次

最近记录:

6 年,5 月 前