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