Introduce DEVICESUMMARY access level to NetworkStatsAccess.

Apps with PACKAGE_USAGE_STATS app op or READ_NETWORK_USAGE_HISTORY
granted can query the summarized device data usage (but not individual
uids running in other users or profiles).

Bug:26677052
Change-Id: Id51631638f338a8cf48172c9b41746228a335084
This commit is contained in:
Zoltan Szatmary-Ban
2016-01-21 10:44:37 +00:00
parent 131806f111
commit 4ff8b948b0
3 changed files with 36 additions and 14 deletions

View File

@@ -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.

View File

@@ -66,14 +66,25 @@ public final class NetworkStatsAccess {
*
* <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 @@ 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).

View File

@@ -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);
}