All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.net.NetworkStatsAccess Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * 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.NetworkStats.UID_ALL;
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.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Process;
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.DEVICESUMMARY, 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: *

    *
  • Profile owners. *
*/ 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. * *

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. *
*/ int DEVICESUMMARY = 2; /** * 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 = 3; } /** 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; final long token = Binder.clearCallingIdentity(); try { hasCarrierPrivileges = tm != null && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; } finally { Binder.restoreCallingIdentity(token); } final boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid); final int appId = UserHandle.getAppId(callingUid); if (hasCarrierPrivileges || isDeviceOwner || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) { // Carrier-privileged apps and device owners, and the system (including the // network stack) can access data usage for all apps on the device. 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; } //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. boolean isProfileOwner = dpmi != null && (dpmi.isActiveProfileOwner(callingUid) || dpmi.isActiveDeviceOwner(callingUid)); 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; } // 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.DEVICESUMMARY: // Can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering) and // anonymized uids return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING || uid == UID_ALL || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); 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.noteOp(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; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy