Merge "Introduce DEVICESUMMARY access level to NetworkStatsAccess."
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index e8373a1..1a9bf4e 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -52,10 +52,12 @@
* {@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 53ba718..479b065 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -66,15 +66,26 @@
*
* <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;
/**
+ * 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.
+ * </ul>
+ */
+ int DEVICESUMMARY = 2;
+
+ /**
* Access level for apps which can access usage for any app on the device, including apps
* running on other users/profiles.
*
@@ -85,7 +96,7 @@
* <li>The system UID.
* </ul>
*/
- int DEVICE = 2;
+ int DEVICE = 3;
}
/** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
@@ -107,11 +118,15 @@
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 @@
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 b1d6f89..3aeceef 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 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);
}