diff options
3 files changed, 35 insertions, 13 deletions
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index e8373a175e95..1a9bf4e25b05 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -52,10 +52,12 @@ import android.util.Log; * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. * <p /> - * <b>NOTE:</b> 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. + * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or 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. + * <p /> * 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 and carrier- * privileged apps likewise get access to usage data for all users on the device. diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 53ba7184e0e5..479b065f5ced 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -66,13 +66,24 @@ public final class NetworkStatsAccess { * * <p>Granted to: * <ul> + * <li>Profile owners. + * </ul> + */ + int USER = 1; + + /** + * Access level for apps which can access usage summary of device. Device summary includes + * usage by apps running in any profiles/users, however this access level does not + * allow querying usage of individual apps running in other profiles/users. + * + * <p>Granted to: + * <ul> * <li>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. * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission. - * <li>Profile owners. * </ul> */ - int USER = 1; + int DEVICESUMMARY = 2; /** * Access level for apps which can access usage for any app on the device, including apps @@ -85,7 +96,7 @@ public final class NetworkStatsAccess { * <li>The system UID. * </ul> */ - int DEVICE = 2; + int DEVICE = 3; } /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ @@ -107,11 +118,15 @@ public final class NetworkStatsAccess { return NetworkStatsAccess.Level.DEVICE; } + boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage); + if (hasAppOpsPermission || context.checkCallingOrSelfPermission( + READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) { + return NetworkStatsAccess.Level.DEVICESUMMARY; + } + 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) { + if (isProfileOwner) { // 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; @@ -131,6 +146,7 @@ public final class NetworkStatsAccess { case NetworkStatsAccess.Level.DEVICE: // Device-level access - can access usage for any uid. return true; + case NetworkStatsAccess.Level.DEVICESUMMARY: 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). diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index b1d6f896dd47..3aeceef51de7 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -484,15 +484,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start, long end) { @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); - if (accessLevel < NetworkStatsAccess.Level.DEVICE) { + if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) { throw new SecurityException("Calling package " + mCallingPackage - + " cannot access device-level network stats"); + + " cannot access device summary network stats"); } NetworkStats result = new NetworkStats(end - start, 1); final long ident = Binder.clearCallingIdentity(); try { + // Using access level higher than the one we checked for above. + // Reason is that we are combining usage data in a way that is not PII + // anymore. result.combineAllValues( - internalGetSummaryForNetwork(template, start, end, accessLevel)); + internalGetSummaryForNetwork(template, start, end, + NetworkStatsAccess.Level.DEVICE)); } finally { Binder.restoreCallingIdentity(ident); } |