我想知道数据使用历史,并注意到"新"android-6 NetworkStatsManager
似乎是积极的(我已经使用TrafficStats
了一段时间,但不会覆盖任何重启之前的任何东西).
从API文档:
注意:此API需要权限PACKAGE_USAGE_STATS,这是系统级权限,不会授予第三方应用程序.但是,声明权限意味着使用API的意图,并且设备的用户可以通过"设置"应用程序授予权限.配置文件所有者应用程序被自动授予查询其管理的配置文件上的数据的权限(即,除querySummaryForDevice(int,String,long,long)之外的任何查询).设备所有者应用程序同样可以访问主要用户的使用数据.
我想知道聚合级别的数据使用情况,而不是使用数据的应用程序,所以我试着像这样使用它:
NetworkStatsManager service = context.getSystemService(NetworkStatsManager.class);
NetworkStats.Bucket bucket =
service.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE, null, from, to);
...
Run Code Online (Sandbox Code Playgroud)
不幸的是,抛出一个SecurityException
:
java.lang.SecurityException: NetworkStats: Neither user 10174 nor current process has android.permission.READ_NETWORK_USAGE_HISTORY.
at android.os.Parcel.readException(Parcel.java:1620)
at android.os.Parcel.readException(Parcel.java:1573)
at android.net.INetworkStatsSession$Stub$Proxy.getDeviceSummaryForNetwork(INetworkStatsSession.java:259)
at android.app.usage.NetworkStats.getDeviceSummaryForNetwork(NetworkStats.java:316)
at android.app.usage.NetworkStatsManager.querySummaryForDevice(NetworkStatsManager.java:100)
...
Run Code Online (Sandbox Code Playgroud)
android.permission.READ_NETWORK_USAGE_HISTORY
第三方应用不允许该权限.所以这似乎是一个死胡同.
但是,我深入研究了内部结构,发现您可以使用内部/隐藏API执行相同的操作而无需请求任何权限:
INetworkStatsService service =
INetworkStatsService.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
INetworkStatsSession session = service.openSession();
NetworkTemplate mobileTemplate = NetworkTemplate.buildTemplateMobileWildcard();
int fields = NetworkStatsHistory.FIELD_RX_BYTES | NetworkStatsHistory.FIELD_TX_BYTES;
NetworkStatsHistory mobileHistory = session.getHistoryForNetwork(mobileTemplate, fields);
for (int i = 0; i < …
Run Code Online (Sandbox Code Playgroud) permissions android android-6.0-marshmallow networkstatsmanager
我正在比较新NetworkStats
类与TrafficStats
测量网络接口和给定应用程序的流量(pex Chrome)
由于TrafficStats
自设备启动以来有值,我正在执行的测试是这样的:
获得的数据TrafficStats
是这样的:
TrafficStats.getTotalRxBytes() aprox 17.21 MB
TrafficStats.getUidRxBytes(chromeUid) aprox 13.22 MB
Run Code Online (Sandbox Code Playgroud)
我授予了权限NetworkStats
,我获得的值是这样的:
wifiBucket.getRxBytes() + mobileBucket.getRxBytes() aprox 17.23 MB
dataFromWiFiBucket[1] + dataFromMobileBucket[1] gives 0 bytes
Run Code Online (Sandbox Code Playgroud)
从中获取数据的代码NetworkStats
如下:
long timeStamp = System.currentTimeMillis();
long bootTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
NetworkStats.Bucket wifiBucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_WIFI, null, bootTime, timeStamp);
NetworkStats.Bucket mobileBucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE, subscriberID, bootTime, timeStamp);
NetworkStats wifiBucketForApp = networkStatsManager.queryDetailsForUid(ConnectivityManager.TYPE_WIFI, null, bootTime, timeStamp, chromeUid);
NetworkStats mobileBucketForApp = networkStatsManager.queryDetailsForUid(ConnectivityManager.TYPE_MOBILE, subscriberID, bootTime, …
Run Code Online (Sandbox Code Playgroud) 我实现了一个应用程序来获取数据,用于获取我们需要提供两个权限的数据 -
PACKAGE_USAGE_STATS
READ_PHONE_STATE
当我将应用程序安装为Play商店应用程序时,它工作正常,但当我将其作为系统应用程序推送时,它会崩溃.此崩溃的原因是 - PACKAGE_USAGE_STATS权限.对于系统应用程序,其默认值已启用但仍然崩溃并产生以下异常
java.lang.SecurityException:NetworkStats:用户和当前进程都没有android.permission.READ_NETWORK_USAGE_HISTORY.在Android.OS.Parcel.readException(Parcel.java:1620)的android.UN.Parcel.readException(Parcel.java:1573)android.net.INetworkStatsSession $ Stub $ Proxy.getHistoryIntervalForUid(INetworkStatsSession.java:425)at android.app.usage.NetworkStats.startHistoryEnumeration(NetworkStats.java:341)位于com.android.launcher3.appdatausage.DataUsageManager $ 2.run(DataUsageManager.java)的android.app.usage.NetworkStatsManager.queryDetailsForUid(NetworkStatsManager.java:201) :204)在java.lang.Thread.run(Thread.java:818)
一旦我切换权限,它就可以正常工作.怎么解决这个?
我试图了解我只注意到几个应用程序的数据差异的原因。在 Tidal 和 Apple 音乐中,如果我在听曲目时跳过曲目,我将立即在所有应用程序数据使用量总和与设备总音量之间获得 10% 到 15% 的数据差异。
测试用例
通过启用数据保护程序的潮汐(跳过曲目)执行 36.03MiB,以将后台数据限制到最低限度。
Android 数据使用计数器(设置 - 连接 - 数据使用)
全部的
- Total 36.03MiB
Run Code Online (Sandbox Code Playgroud)
应用
- Tidal 31 MiB
- Google Play Services 448.04 KiB
- My Data Manager 59.9 KiB
- com.samsung.accessory.wmmanager 10.94 KiB
- Google Play Store 5.27 KiB
- Android.OS 5.13 KiB
- Samsung Push Service 3.59 KiB
-----------------------------------------------
- Total of all Apps 31.52 MiB
Run Code Online (Sandbox Code Playgroud)
缺失数据
- Total 4.51 MiB
Run Code Online (Sandbox Code Playgroud)
我的数据经理
对于完全相同的数据测试,我的数据管理器报告相同的值
- Tidal 30.8 MiB
- …
Run Code Online (Sandbox Code Playgroud) 我正在尝试制作一个网络使用情况监控应用程序,它向用户显示移动数据使用历史记录。为此,我使用使用情况访问来获取准确的数据使用统计信息NetworkStatsManager
。但这在 Android 10 中不再有效。
我正在使用NetworkStatsManager.querySummaryForDevice
它需要订阅者 ID,之前我可以使用TelephonyManager.getSubscriberId
.
但getSubscriberId
现在该功能在 Android 10 中无法使用,因为它需要READ_PRIVILEGED_PHONE_STATE
第三方应用程序无法具备的功能。
关于如何使其发挥作用有什么想法吗?我了解获取订阅者 ID 的限制,但只要我获得移动数据使用量(对此我有足够的权限),我并不真正关心订阅者 ID。
android telephonymanager android-data-usage networkstatsmanager android-10.0
我正在为Android 6.0制作应用程序,我想使用新类NetworkStatsManager来获取移动数据.
我在清单中添加了我需要的所有权限,并且需要权限运行时.
当我调用方法时:
bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_WIFI, "", fromDate.getTime(), toDate.getTime());
Run Code Online (Sandbox Code Playgroud)
返回正确的WIFI使用价值.
但是如果我用TYPE_MOBILE替换TYPE_WIFI,结果总是为0.
NetworkStats.Bucket bucket = null;
try {
bucket = networkStatsManager.querySummaryForDevice(ConnectivityManager.TYPE_MOBILE, "", fromDate.getTime(), toDate.getTime());
if(bucket == null){
Log.i("Info", "Error");
}else{
Log.i("Info", "Total: " + (bucket.getRxBytes() + bucket.getTxBytes()));
}
} catch (RemoteException e) {
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud) 我正在构建一个应用程序,用于在一段时间内监视应用程序网络数据的使用情况。
在 android 5 上,我对 TrafficStats 没有任何问题,尽管在 android 8 上使用 NetworkStats 我总是收到相同的数据。我读到存储桶每 30 分钟左右刷新一次,所以我尝试听 youtube 大约 1 小时,但数据使用量仍然相同(在包 com.google.android.youtube 中)。
那么,我的问题是,为什么 NetworkStats 总是返回相同的数据?
这是我的代码:
public class DataService extends Service {
private int interval = 1000 * 5; //Time interval
private List<ApplicationInfo> infos;
private PackageManager packageManager;
private static int counter = 0;
private ArrayList<ValuesHolder> values;
private Context context;
private Handler mHandler;
public static final String DATA_INTENT_FILTER = "Transmitted data updated";
private Runnable mHandlerTask = new Runnable() {
@Override
public void run() …
Run Code Online (Sandbox Code Playgroud)