1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net; 18 19 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; 20 import static android.net.NetworkStats.UID_ALL; 21 import static android.net.TrafficStats.UID_REMOVED; 22 import static android.net.TrafficStats.UID_TETHERING; 23 24 import android.Manifest; 25 import android.annotation.IntDef; 26 import android.annotation.Nullable; 27 import android.app.AppOpsManager; 28 import android.app.admin.DevicePolicyManager; 29 import android.content.Context; 30 import android.content.pm.PackageManager; 31 import android.os.Binder; 32 import android.os.Process; 33 import android.os.UserHandle; 34 import android.telephony.TelephonyManager; 35 36 import com.android.net.module.util.PermissionUtils; 37 38 import java.lang.annotation.Retention; 39 import java.lang.annotation.RetentionPolicy; 40 41 /** 42 * Utility methods for controlling access to network stats APIs. 43 * 44 * @hide 45 */ 46 public final class NetworkStatsAccess { NetworkStatsAccess()47 private NetworkStatsAccess() {} 48 49 /** 50 * Represents an access level for the network usage history and statistics APIs. 51 * 52 * <p>Access levels are in increasing order; that is, it is reasonable to check access by 53 * verifying that the caller's access level is at least the minimum required level. 54 */ 55 @IntDef({ 56 Level.DEFAULT, 57 Level.USER, 58 Level.DEVICESUMMARY, 59 Level.DEVICE, 60 }) 61 @Retention(RetentionPolicy.SOURCE) 62 public @interface Level { 63 /** 64 * Default, unprivileged access level. 65 * 66 * <p>Can only access usage for one's own UID. 67 * 68 * <p>Every app will have at least this access level. 69 */ 70 int DEFAULT = 0; 71 72 /** 73 * Access level for apps which can access usage for any app running in the same user. 74 * 75 * <p>Granted to: 76 * <ul> 77 * <li>Profile owners. 78 * </ul> 79 */ 80 int USER = 1; 81 82 /** 83 * Access level for apps which can access usage summary of device. Device summary includes 84 * usage by apps running in any profiles/users, however this access level does not 85 * allow querying usage of individual apps running in other profiles/users. 86 * 87 * <p>Granted to: 88 * <ul> 89 * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit 90 * so it is not necessarily sufficient to declare this in the manifest. 91 * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission. 92 * </ul> 93 */ 94 int DEVICESUMMARY = 2; 95 96 /** 97 * Access level for apps which can access usage for any app on the device, including apps 98 * running on other users/profiles. 99 * 100 * <p>Granted to: 101 * <ul> 102 * <li>Device owners. 103 * <li>Carrier-privileged applications. 104 * <li>The system UID. 105 * <li>NetworkStack application. 106 * </ul> 107 */ 108 int DEVICE = 3; 109 } 110 111 /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ checkAccessLevel( Context context, int callingPid, int callingUid, @Nullable String callingPackage)112 public static @NetworkStatsAccess.Level int checkAccessLevel( 113 Context context, int callingPid, int callingUid, @Nullable String callingPackage) { 114 final int appId = UserHandle.getAppId(callingUid); 115 if (appId == Process.SYSTEM_UID) { 116 // the system can access data usage for all apps on the device. 117 // check system uid first, to avoid possible dead lock from other APIs 118 return NetworkStatsAccess.Level.DEVICE; 119 } 120 final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class); 121 final TelephonyManager tm = (TelephonyManager) 122 context.getSystemService(Context.TELEPHONY_SERVICE); 123 final boolean hasCarrierPrivileges; 124 final boolean isDeviceOwner; 125 long token = Binder.clearCallingIdentity(); 126 try { 127 hasCarrierPrivileges = tm != null 128 && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) 129 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 130 isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage); 131 } finally { 132 Binder.restoreCallingIdentity(token); 133 } 134 135 final boolean isNetworkStack = PermissionUtils.hasAnyPermissionOf( 136 context, callingPid, callingUid, android.Manifest.permission.NETWORK_STACK, 137 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); 138 139 if (hasCarrierPrivileges || isDeviceOwner || isNetworkStack) { 140 // Carrier-privileged apps and device owners, and the network stack 141 // can access data usage for all apps on the device. 142 return NetworkStatsAccess.Level.DEVICE; 143 } 144 145 final boolean hasAppOpsPermission = 146 hasAppOpsPermission(context, callingUid, callingPackage); 147 if (hasAppOpsPermission || context.checkCallingOrSelfPermission( 148 READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) { 149 return NetworkStatsAccess.Level.DEVICESUMMARY; 150 } 151 152 final boolean isProfileOwner; 153 token = Binder.clearCallingIdentity(); 154 try { 155 isProfileOwner = mDpm != null && mDpm.isProfileOwnerApp(callingPackage); 156 } finally { 157 Binder.restoreCallingIdentity(token); 158 } 159 if (isProfileOwner) { 160 // Apps with the AppOps permission, profile owners, and apps with the privileged 161 // permission can access data usage for all apps in this user/profile. 162 return NetworkStatsAccess.Level.USER; 163 } 164 165 // Everyone else gets default access (only to their own UID). 166 return NetworkStatsAccess.Level.DEFAULT; 167 } 168 169 /** 170 * Returns whether the given caller should be able to access the given UID when the caller has 171 * the given {@link NetworkStatsAccess.Level}. 172 */ isAccessibleToUser(int uid, int callerUid, @NetworkStatsAccess.Level int accessLevel)173 public static boolean isAccessibleToUser(int uid, int callerUid, 174 @NetworkStatsAccess.Level int accessLevel) { 175 final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier(); 176 final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier(); 177 switch (accessLevel) { 178 case NetworkStatsAccess.Level.DEVICE: 179 // Device-level access - can access usage for any uid. 180 return true; 181 case NetworkStatsAccess.Level.DEVICESUMMARY: 182 // Can access usage for any app running in the same user, along 183 // with some special uids (system, removed, or tethering) and 184 // anonymized uids 185 return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED 186 || uid == UID_TETHERING || uid == UID_ALL 187 || userId == callerUserId; 188 case NetworkStatsAccess.Level.USER: 189 // User-level access - can access usage for any app running in the same user, along 190 // with some special uids (system, removed, or tethering). 191 return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED 192 || uid == UID_TETHERING 193 || userId == callerUserId; 194 case NetworkStatsAccess.Level.DEFAULT: 195 default: 196 // Default access level - can only access one's own usage. 197 return uid == callerUid; 198 } 199 } 200 hasAppOpsPermission( Context context, int callingUid, String callingPackage)201 private static boolean hasAppOpsPermission( 202 Context context, int callingUid, String callingPackage) { 203 if (callingPackage != null) { 204 AppOpsManager appOps = (AppOpsManager) context.getSystemService( 205 Context.APP_OPS_SERVICE); 206 207 final int mode = appOps.noteOp(AppOpsManager.OPSTR_GET_USAGE_STATS, 208 callingUid, callingPackage, null /* attributionTag */, null /* message */); 209 if (mode == AppOpsManager.MODE_DEFAULT) { 210 // The default behavior here is to check if PackageManager has given the app 211 // permission. 212 final int permissionCheck = context.checkCallingPermission( 213 Manifest.permission.PACKAGE_USAGE_STATS); 214 return permissionCheck == PackageManager.PERMISSION_GRANTED; 215 } 216 return (mode == AppOpsManager.MODE_ALLOWED); 217 } 218 return false; 219 } 220 } 221