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