diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 2886cda9d2..0fce7a90ea 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkIdentity;
import android.net.NetworkTemplate;
+import android.os.Build;
import android.os.RemoteException;
import android.util.Log;
@@ -29,10 +30,9 @@ import android.util.Log;
* discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
*
* Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and
- * Long.MAX_VALUE can be used to simulate open ended intervals). All queries (except
- * {@link #querySummaryForDevice}) collect only network usage of apps belonging to the same user
- * as the client. In addition tethering usage, usage by removed users and apps, and usage by system
- * is also included in the results.
+ * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain
+ * data about themselves. See the below note for special cases in which apps can obtain data about
+ * other applications.
*
* Summary queries
*
@@ -51,13 +51,20 @@ import android.util.Log;
* multiple buckets for a particular key but all Bucket's state is going to be
* {@link NetworkStats.Bucket#STATE_ALL}.
*
- * NOTE: This API requires the permission
+ * NOTE: Accessing stats for apps other than the calling app requires the permission
* {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and
* will not be granted to third-party apps. However, declaring the permission implies intention to
* use the API and the user of the device can grant permission through the Settings application.
* Profile owner apps are automatically granted permission to query data on the profile they manage
- * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps likewise get
- * access to usage data of the primary user.
+ * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier-
+ * privileged apps likewise get access to usage data for all users on the device.
+ *
+ * In addition to tethering usage, usage by removed users and apps, and usage by the system
+ * is also included in the results for callers with one of these higher levels of access.
+ *
+ * NOTE: Prior to API level {@value Build.VERSION_CODES#N}, all calls to these APIs required
+ * the above permission, even to access an app's own data usage, and carrier-privileged apps were
+ * not included.
*/
public class NetworkStatsManager {
private final static String TAG = "NetworkStatsManager";
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
new file mode 100644
index 0000000000..53ba7184e0
--- /dev/null
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.net;
+
+import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
+import static android.net.TrafficStats.UID_REMOVED;
+import static android.net.TrafficStats.UID_TETHERING;
+
+import android.Manifest;
+import android.annotation.IntDef;
+import android.app.AppOpsManager;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+
+import com.android.server.LocalServices;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Utility methods for controlling access to network stats APIs. */
+public final class NetworkStatsAccess {
+ private NetworkStatsAccess() {}
+
+ /**
+ * Represents an access level for the network usage history and statistics APIs.
+ *
+ * Access levels are in increasing order; that is, it is reasonable to check access by
+ * verifying that the caller's access level is at least the minimum required level.
+ */
+ @IntDef({
+ Level.DEFAULT,
+ Level.USER,
+ Level.DEVICE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Level {
+ /**
+ * Default, unprivileged access level.
+ *
+ *
Can only access usage for one's own UID.
+ *
+ *
Every app will have at least this access level.
+ */
+ int DEFAULT = 0;
+
+ /**
+ * Access level for apps which can access usage for any app running in the same user.
+ *
+ *
Granted to:
+ *
+ * - Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
+ * so it is not necessarily sufficient to declare this in the manifest.
+ *
- Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
+ *
- Profile owners.
+ *
+ */
+ int USER = 1;
+
+ /**
+ * Access level for apps which can access usage for any app on the device, including apps
+ * running on other users/profiles.
+ *
+ * Granted to:
+ *
+ * - Device owners.
+ *
- Carrier-privileged applications.
+ *
- The system UID.
+ *
+ */
+ int DEVICE = 2;
+ }
+
+ /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
+ public static @NetworkStatsAccess.Level int checkAccessLevel(
+ Context context, int callingUid, String callingPackage) {
+ final DevicePolicyManagerInternal dpmi = LocalServices.getService(
+ DevicePolicyManagerInternal.class);
+ final TelephonyManager tm = (TelephonyManager)
+ context.getSystemService(Context.TELEPHONY_SERVICE);
+ boolean hasCarrierPrivileges = tm != null &&
+ tm.checkCarrierPrivilegesForPackage(callingPackage) ==
+ TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
+ DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ if (hasCarrierPrivileges || isDeviceOwner
+ || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) {
+ // Carrier-privileged apps and device owners, and the system can access data usage for
+ // all apps on the device.
+ return NetworkStatsAccess.Level.DEVICE;
+ }
+
+ boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (hasAppOpsPermission(context, callingUid, callingPackage) || isProfileOwner
+ || context.checkCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY) ==
+ PackageManager.PERMISSION_GRANTED) {
+ // Apps with the AppOps permission, profile owners, and apps with the privileged
+ // permission can access data usage for all apps in this user/profile.
+ return NetworkStatsAccess.Level.USER;
+ }
+
+ // Everyone else gets default access (only to their own UID).
+ return NetworkStatsAccess.Level.DEFAULT;
+ }
+
+ /**
+ * Returns whether the given caller should be able to access the given UID when the caller has
+ * the given {@link NetworkStatsAccess.Level}.
+ */
+ public static boolean isAccessibleToUser(int uid, int callerUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ switch (accessLevel) {
+ case NetworkStatsAccess.Level.DEVICE:
+ // Device-level access - can access usage for any uid.
+ return true;
+ case NetworkStatsAccess.Level.USER:
+ // User-level access - can access usage for any app running in the same user, along
+ // with some special uids (system, removed, or tethering).
+ return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
+ || uid == UID_TETHERING
+ || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+ case NetworkStatsAccess.Level.DEFAULT:
+ default:
+ // Default access level - can only access one's own usage.
+ return uid == callerUid;
+ }
+ }
+
+ private static boolean hasAppOpsPermission(
+ Context context, int callingUid, String callingPackage) {
+ if (callingPackage != null) {
+ AppOpsManager appOps = (AppOpsManager) context.getSystemService(
+ Context.APP_OPS_SERVICE);
+
+ final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
+ callingUid, callingPackage);
+ if (mode == AppOpsManager.MODE_DEFAULT) {
+ // The default behavior here is to check if PackageManager has given the app
+ // permission.
+ final int permissionCheck = context.checkCallingPermission(
+ Manifest.permission.PACKAGE_USAGE_STATS);
+ return permissionCheck == PackageManager.PERMISSION_GRANTED;
+ }
+ return (mode == AppOpsManager.MODE_ALLOWED);
+ }
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 15b68c7399..102695e343 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -22,24 +22,18 @@ import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
-import static android.net.TrafficStats.UID_TETHERING;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-import android.net.ConnectivityManager;
import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.os.Binder;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.IntArray;
-import libcore.io.IoUtils;
-
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
@@ -47,6 +41,8 @@ import com.android.internal.util.IndentingPrintWriter;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
+import libcore.io.IoUtils;
+
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -136,12 +132,12 @@ public class NetworkStatsCollection implements FileRotator.Reader {
return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
}
- public int[] getRelevantUids() {
+ public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
final int callerUid = Binder.getCallingUid();
IntArray uids = new IntArray();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
- if (isAccessibleToUser(key.uid, callerUid)) {
+ if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) {
int j = uids.binarySearch(key.uid);
if (j < 0) {
@@ -158,8 +154,10 @@ public class NetworkStatsCollection implements FileRotator.Reader {
* the requested parameters.
*/
public NetworkStatsHistory getHistory(
- NetworkTemplate template, int uid, int set, int tag, int fields) {
- return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE);
+ NetworkTemplate template, int uid, int set, int tag, int fields,
+ @NetworkStatsAccess.Level int accessLevel) {
+ return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE,
+ accessLevel);
}
/**
@@ -167,9 +165,10 @@ public class NetworkStatsCollection implements FileRotator.Reader {
* the requested parameters.
*/
public NetworkStatsHistory getHistory(
- NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) {
+ NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel) {
final int callerUid = Binder.getCallingUid();
- if (!isAccessibleToUser(uid, callerUid)) {
+ if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) {
throw new SecurityException("Network stats history of uid " + uid
+ " is forbidden for caller " + callerUid);
}
@@ -195,7 +194,8 @@ public class NetworkStatsCollection implements FileRotator.Reader {
* Summarize all {@link NetworkStatsHistory} in this collection which match
* the requested parameters.
*/
- public NetworkStats getSummary(NetworkTemplate template, long start, long end) {
+ public NetworkStats getSummary(NetworkTemplate template, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel) {
final long now = System.currentTimeMillis();
final NetworkStats stats = new NetworkStats(end - start, 24);
@@ -208,7 +208,8 @@ public class NetworkStatsCollection implements FileRotator.Reader {
final int callerUid = Binder.getCallingUid();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
- if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid)
+ if (templateMatches(template, key.ident)
+ && NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)
&& key.set < NetworkStats.SET_DEBUG_START) {
final NetworkStatsHistory value = mStats.valueAt(i);
historyEntry = value.getValues(start, end, now, historyEntry);
@@ -570,12 +571,6 @@ public class NetworkStatsCollection implements FileRotator.Reader {
}
}
- private static boolean isAccessibleToUser(int uid, int callerUid) {
- return UserHandle.getAppId(callerUid) == android.os.Process.SYSTEM_UID ||
- uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING
- || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
- }
-
/**
* Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
* in the given {@link NetworkIdentitySet}.
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 649086575c..c09196006b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -116,7 +116,8 @@ public class NetworkStatsRecorder {
}
public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
- return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null);
+ return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
+ NetworkStatsAccess.Level.DEVICE).getTotal(null);
}
/**
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 844934846f..b1d6f896dd 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -62,13 +62,9 @@ import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
-import android.Manifest;
import android.app.AlarmManager;
-import android.app.AppOpsManager;
import android.app.IAlarmManager;
import android.app.PendingIntent;
-import android.app.admin.DeviceAdminInfo;
-import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -97,9 +93,7 @@ import android.os.HandlerThread;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.PowerManager;
-import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -122,7 +116,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
-import com.android.server.LocalServices;
import com.android.server.connectivity.Tethering;
import java.io.File;
@@ -484,18 +477,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public int[] getRelevantUids() {
- enforcePermissionForManagedAdmin(mCallingPackage);
- return getUidComplete().getRelevantUids();
+ return getUidComplete().getRelevantUids(checkAccessLevel(mCallingPackage));
}
@Override
public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start,
long end) {
- enforcePermission(mCallingPackage);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ if (accessLevel < NetworkStatsAccess.Level.DEVICE) {
+ throw new SecurityException("Calling package " + mCallingPackage
+ + " cannot access device-level network stats");
+ }
NetworkStats result = new NetworkStats(end - start, 1);
final long ident = Binder.clearCallingIdentity();
try {
- result.combineAllValues(internalGetSummaryForNetwork(template, start, end));
+ result.combineAllValues(
+ internalGetSummaryForNetwork(template, start, end, accessLevel));
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -505,23 +502,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public NetworkStats getSummaryForNetwork(
NetworkTemplate template, long start, long end) {
- enforcePermission(mCallingPackage);
- return internalGetSummaryForNetwork(template, start, end);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ return internalGetSummaryForNetwork(template, start, end, accessLevel);
}
@Override
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
- return internalGetHistoryForNetwork(template, fields);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ return internalGetHistoryForNetwork(template, fields, accessLevel);
}
@Override
public NetworkStats getSummaryForAllUid(
NetworkTemplate template, long start, long end, boolean includeTags) {
- enforcePermissionForManagedAdmin(mCallingPackage);
- final NetworkStats stats = getUidComplete().getSummary(template, start, end);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ final NetworkStats stats =
+ getUidComplete().getSummary(template, start, end, accessLevel);
if (includeTags) {
final NetworkStats tagStats = getUidTagComplete()
- .getSummary(template, start, end);
+ .getSummary(template, start, end, accessLevel);
stats.combineAllValues(tagStats);
}
return stats;
@@ -530,11 +529,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public NetworkStatsHistory getHistoryForUid(
NetworkTemplate template, int uid, int set, int tag, int fields) {
- enforcePermissionForManagedAdmin(mCallingPackage);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
if (tag == TAG_NONE) {
- return getUidComplete().getHistory(template, uid, set, tag, fields);
+ return getUidComplete().getHistory(template, uid, set, tag, fields,
+ accessLevel);
} else {
- return getUidTagComplete().getHistory(template, uid, set, tag, fields);
+ return getUidTagComplete().getHistory(template, uid, set, tag, fields,
+ accessLevel);
}
}
@@ -542,12 +543,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public NetworkStatsHistory getHistoryIntervalForUid(
NetworkTemplate template, int uid, int set, int tag, int fields,
long start, long end) {
- enforcePermissionForManagedAdmin(mCallingPackage);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
if (tag == TAG_NONE) {
- return getUidComplete().getHistory(template, uid, set, tag, fields, start, end);
+ return getUidComplete().getHistory(template, uid, set, tag, fields, start, end,
+ accessLevel);
} else {
return getUidTagComplete().getHistory(template, uid, set, tag, fields,
- start, end);
+ start, end, accessLevel);
}
}
@@ -559,80 +561,42 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
};
}
- private boolean hasAppOpsPermission(String callingPackage) {
- final int callingUid = Binder.getCallingUid();
- boolean appOpsAllow = false;
- if (callingPackage != null) {
- AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
- Context.APP_OPS_SERVICE);
-
- final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
- callingUid, callingPackage);
- if (mode == AppOpsManager.MODE_DEFAULT) {
- // The default behavior here is to check if PackageManager has given the app
- // permission.
- final int permissionCheck = mContext.checkCallingPermission(
- Manifest.permission.PACKAGE_USAGE_STATS);
- appOpsAllow = permissionCheck == PackageManager.PERMISSION_GRANTED;
- }
- appOpsAllow = (mode == AppOpsManager.MODE_ALLOWED);
- }
- return appOpsAllow;
+ private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) {
+ return NetworkStatsAccess.checkAccessLevel(
+ mContext, Binder.getCallingUid(), callingPackage);
}
- private void enforcePermissionForManagedAdmin(String callingPackage) {
- boolean hasPermission = hasAppOpsPermission(callingPackage);
- if (!hasPermission) {
- // Profile and device owners are exempt from permission checking.
- final int callingUid = Binder.getCallingUid();
- final DevicePolicyManagerInternal dpmi = LocalServices.getService(
- DevicePolicyManagerInternal.class);
-
- // Device owners are also profile owners so it is enough to check for that.
- if (dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)) {
- return;
- }
- }
- if (!hasPermission) {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
- }
- }
-
- private void enforcePermission(String callingPackage) {
- boolean appOpsAllow = hasAppOpsPermission(callingPackage);
- if (!appOpsAllow) {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
- }
- }
-
-
/**
* Return network summary, splicing between DEV and XT stats when
* appropriate.
*/
private NetworkStats internalGetSummaryForNetwork(
- NetworkTemplate template, long start, long end) {
+ NetworkTemplate template, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel) {
// We've been using pure XT stats long enough that we no longer need to
// splice DEV and XT together.
- return mXtStatsCached.getSummary(template, start, end);
+ return mXtStatsCached.getSummary(template, start, end, accessLevel);
}
/**
* Return network history, splicing between DEV and XT stats when
* appropriate.
*/
- private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) {
+ private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields,
+ @NetworkStatsAccess.Level int accessLevel) {
// We've been using pure XT stats long enough that we no longer need to
// splice DEV and XT together.
- return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
+ return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields, accessLevel);
}
@Override
public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+ // Special case - since this is for internal use only, don't worry about a full access level
+ // check and just require the signature/privileged permission.
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
assertBandwidthControlEnabled();
- return internalGetSummaryForNetwork(template, start, end).getTotalBytes();
+ return internalGetSummaryForNetwork(template, start, end, NetworkStatsAccess.Level.DEVICE)
+ .getTotalBytes();
}
@Override