Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a8b343c authored by Zoltan Szatmary-Ban's avatar Zoltan Szatmary-Ban
Browse files

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
parent 6cfdf6b6
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -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.
+22 −6
Original line number Diff line number Diff line
@@ -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).
+7 −3
Original line number Diff line number Diff line
@@ -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);
                }