1 /* 2 * Copyright (C) 2018 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.content; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.app.AppOpsManager; 23 import android.content.pm.PackageManager; 24 import android.content.pm.PermissionInfo; 25 import android.os.Binder; 26 import android.os.Process; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 31 /** 32 * This class provides permission check APIs that verify both the 33 * permission and the associated app op for this permission if 34 * such is defined. 35 * <p> 36 * In the new permission model permissions with protection level 37 * dangerous are runtime permissions. For apps targeting {@link android.os.Build.VERSION_CODES#M} 38 * and above the user may not grant such permissions or revoke 39 * them at any time. For apps targeting API lower than {@link android.os.Build.VERSION_CODES#M} 40 * these permissions are always granted as such apps do not expect 41 * permission revocations and would crash. Therefore, when the 42 * user disables a permission for a legacy app in the UI the 43 * platform disables the APIs guarded by this permission making 44 * them a no-op which is doing nothing or returning an empty 45 * result or default error. 46 * </p> 47 * <p> 48 * It is important that when you perform an operation on behalf of 49 * another app you use these APIs to check for permissions as the 50 * app may be a legacy app that does not participate in the new 51 * permission model for which the user had disabled the "permission" 52 * which is achieved by disallowing the corresponding app op. 53 * </p> 54 * <p> 55 * This class has two types of methods and you should be careful which 56 * type to call based on whether permission protected data is being 57 * passed to the app or you are just checking whether the app holds a 58 * permission. The reason is that a permission check requires checking 59 * the runtime permission and if it is granted checking the corresponding 60 * app op as for apps not supporting the runtime mode we never revoke 61 * permissions but disable app ops. Since there are two types of app op 62 * checks, one that does not leave a record an action was performed and 63 * another the does, one needs to call the preflight flavor of the checks 64 * named xxxForPreflight only if no private data is being delivered but 65 * a permission check is what is needed and the xxxForDataDelivery where 66 * the permission check is right before private data delivery. 67 * 68 * @hide 69 */ 70 public final class PermissionChecker { 71 /** The permission is granted. */ 72 public static final int PERMISSION_GRANTED = PackageManager.PERMISSION_GRANTED; 73 74 /** Returned when: 75 * <ul> 76 * <li>For non app op permissions, returned when the permission is denied.</li> 77 * <li>For app op permissions, returned when the app op is denied or app op is 78 * {@link AppOpsManager#MODE_DEFAULT} and permission is denied.</li> 79 * </ul> 80 * 81 */ 82 public static final int PERMISSION_HARD_DENIED = PackageManager.PERMISSION_DENIED; 83 84 /** Only for runtime permissions, its returned when the runtime permission 85 * is granted, but the corresponding app op is denied. */ 86 public static final int PERMISSION_SOFT_DENIED = PackageManager.PERMISSION_DENIED - 1; 87 88 /** Constant when the PID for which we check permissions is unknown. */ 89 public static final int PID_UNKNOWN = -1; 90 91 /** @hide */ 92 @IntDef({PERMISSION_GRANTED, 93 PERMISSION_SOFT_DENIED, 94 PERMISSION_HARD_DENIED}) 95 @Retention(RetentionPolicy.SOURCE) 96 public @interface PermissionResult {} 97 PermissionChecker()98 private PermissionChecker() { 99 /* do nothing */ 100 } 101 102 /** 103 * Checks whether a given package in a UID and PID has a given permission 104 * and whether the app op that corresponds to this permission is allowed. 105 * 106 * <strong>NOTE:</strong> Use this method only for permission checks at the 107 * point where you will deliver the permission protected data to clients. 108 * 109 * <p>For example, if an app registers a location listener it should have the location 110 * permission but no data is actually sent to the app at the moment of registration 111 * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)} 112 * to determine if the app has or may have location permission (if app has only foreground 113 * location the grant state depends on the app's fg/gb state) and this check will not 114 * leave a trace that permission protected data was delivered. When you are about to 115 * deliver the location data to a registered listener you should use this method which 116 * will evaluate the permission access based on the current fg/bg state of the app and 117 * leave a record that the data was accessed. 118 * 119 * @param context Context for accessing resources. 120 * @param permission The permission to check. 121 * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID 122 * is not known. 123 * @param uid The uid for which to check. 124 * @param packageName The package name for which to check. If null the 125 * the first package for the calling UID will be used. 126 * @param attributionTag attribution tag 127 * @return The permission check result which is either {@link #PERMISSION_GRANTED} 128 * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. 129 * @param message A message describing the reason the permission was checked 130 * 131 * @see #checkPermissionForPreflight(Context, String, int, int, String) 132 */ 133 @PermissionResult checkPermissionForDataDelivery(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message)134 public static int checkPermissionForDataDelivery(@NonNull Context context, 135 @NonNull String permission, int pid, int uid, @Nullable String packageName, 136 @Nullable String attributionTag, @Nullable String message) { 137 return checkPermissionCommon(context, permission, pid, uid, packageName, attributionTag, 138 message, true /*forDataDelivery*/); 139 } 140 141 /** 142 * Checks whether a given package in a UID and PID has a given permission 143 * and whether the app op that corresponds to this permission is allowed. 144 * 145 * <strong>NOTE:</strong> Use this method only for permission checks at the 146 * preflight point where you will not deliver the permission protected data 147 * to clients but schedule permission data delivery, apps register listeners, 148 * etc. 149 * 150 * <p>For example, if an app registers a location listener it should have the location 151 * permission but no data is actually sent to the app at the moment of registration 152 * and you should use this method to determine if the app has or may have location 153 * permission (if app has only foreground location the grant state depends on the app's 154 * fg/gb state) and this check will not leave a trace that permission protected data 155 * was delivered. When you are about to deliver the location data to a registered 156 * listener you should use {@link #checkPermissionForDataDelivery(Context, String, 157 * int, int, String, String)} which will evaluate the permission access based on the current 158 * fg/bg state of the app and leave a record that the data was accessed. 159 * 160 * @param context Context for accessing resources. 161 * @param permission The permission to check. 162 * @param pid The process id for which to check. 163 * @param uid The uid for which to check. 164 * @param packageName The package name for which to check. If null the 165 * the first package for the calling UID will be used. 166 * @return The permission check result which is either {@link #PERMISSION_GRANTED} 167 * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. 168 * 169 * @see #checkPermissionForDataDelivery(Context, String, int, int, String, String) 170 */ 171 @PermissionResult checkPermissionForPreflight(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName)172 public static int checkPermissionForPreflight(@NonNull Context context, 173 @NonNull String permission, int pid, int uid, @Nullable String packageName) { 174 return checkPermissionCommon(context, permission, pid, uid, packageName, 175 null /*attributionTag*/, null /*message*/, false /*forDataDelivery*/); 176 } 177 178 /** 179 * Checks whether your app has a given permission and whether the app op 180 * that corresponds to this permission is allowed. 181 * 182 * <strong>NOTE:</strong> Use this method only for permission checks at the 183 * point where you will deliver the permission protected data to clients. 184 * 185 * <p>For example, if an app registers a location listener it should have the location 186 * permission but no data is actually sent to the app at the moment of registration 187 * and you should use {@link #checkSelfPermissionForPreflight(Context, String)} 188 * to determine if the app has or may have location permission (if app has only foreground 189 * location the grant state depends on the app's fg/gb state) and this check will not 190 * leave a trace that permission protected data was delivered. When you are about to 191 * deliver the location data to a registered listener you should use this method 192 * which will evaluate the permission access based on the current fg/bg state of the 193 * app and leave a record that the data was accessed. 194 * 195 * <p>This API assumes the the {@link Binder#getCallingUid()} is the same as 196 * {@link Process#myUid()}. 197 * 198 * @param context Context for accessing resources. 199 * @param permission The permission to check. 200 * @return The permission check result which is either {@link #PERMISSION_GRANTED} 201 * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. 202 * @param message A message describing the reason the permission was checked 203 * 204 * @see #checkSelfPermissionForPreflight(Context, String) 205 */ 206 @PermissionResult checkSelfPermissionForDataDelivery(@onNull Context context, @NonNull String permission, @Nullable String message)207 public static int checkSelfPermissionForDataDelivery(@NonNull Context context, 208 @NonNull String permission, @Nullable String message) { 209 return checkPermissionForDataDelivery(context, permission, Process.myPid(), 210 Process.myUid(), context.getPackageName(), context.getAttributionTag(), message); 211 } 212 213 /** 214 * Checks whether your app has a given permission and whether the app op 215 * that corresponds to this permission is allowed. 216 * 217 * <strong>NOTE:</strong> Use this method only for permission checks at the 218 * preflight point where you will not deliver the permission protected data 219 * to clients but schedule permission data delivery, apps register listeners, 220 * etc. 221 * 222 * <p>For example, if an app registers a location listener it should have the location 223 * permission but no data is actually sent to the app at the moment of registration 224 * and you should use this method to determine if the app has or may have location 225 * permission (if app has only foreground location the grant state depends on the 226 * app's fg/gb state) and this check will not leave a trace that permission protected 227 * data was delivered. When you are about to deliver the location data to a registered 228 * listener you should use this method which will evaluate the permission access based 229 * on the current fg/bg state of the app and leave a record that the data was accessed. 230 * 231 * <p>This API assumes the the {@link Binder#getCallingUid()} is the same as 232 * {@link Process#myUid()}. 233 * 234 * @param context Context for accessing resources. 235 * @param permission The permission to check. 236 * @return The permission check result which is either {@link #PERMISSION_GRANTED} 237 * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. 238 * 239 * @see #checkSelfPermissionForDataDelivery(Context, String, String) 240 */ 241 @PermissionResult checkSelfPermissionForPreflight(@onNull Context context, @NonNull String permission)242 public static int checkSelfPermissionForPreflight(@NonNull Context context, 243 @NonNull String permission) { 244 return checkPermissionForPreflight(context, permission, Process.myPid(), 245 Process.myUid(), context.getPackageName()); 246 } 247 248 /** 249 * Checks whether the IPC you are handling has a given permission and whether 250 * the app op that corresponds to this permission is allowed. 251 * 252 * <strong>NOTE:</strong> Use this method only for permission checks at the 253 * point where you will deliver the permission protected data to clients. 254 * 255 * <p>For example, if an app registers a location listener it should have the location 256 * permission but no data is actually sent to the app at the moment of registration 257 * and you should use {@link #checkCallingPermissionForPreflight(Context, String, String)} 258 * to determine if the app has or may have location permission (if app has only foreground 259 * location the grant state depends on the app's fg/gb state) and this check will not 260 * leave a trace that permission protected data was delivered. When you are about to 261 * deliver the location data to a registered listener you should use this method which 262 * will evaluate the permission access based on the current fg/bg state of the app and 263 * leave a record that the data was accessed. 264 * 265 * @param context Context for accessing resources. 266 * @param permission The permission to check. 267 * @param packageName The package name making the IPC. If null the 268 * the first package for the calling UID will be used. 269 * @param attributionTag attribution tag 270 * @return The permission check result which is either {@link #PERMISSION_GRANTED} 271 * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. 272 * @param message A message describing the reason the permission was checked 273 * 274 * @see #checkCallingPermissionForPreflight(Context, String, String) 275 */ 276 @PermissionResult checkCallingPermissionForDataDelivery(@onNull Context context, @NonNull String permission, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message)277 public static int checkCallingPermissionForDataDelivery(@NonNull Context context, 278 @NonNull String permission, @Nullable String packageName, 279 @Nullable String attributionTag, @Nullable String message) { 280 if (Binder.getCallingPid() == Process.myPid()) { 281 return PERMISSION_HARD_DENIED; 282 } 283 return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(), 284 Binder.getCallingUid(), packageName, attributionTag, message); 285 } 286 287 /** 288 * Checks whether the IPC you are handling has a given permission and whether 289 * the app op that corresponds to this permission is allowed. 290 * 291 * <strong>NOTE:</strong> Use this method only for permission checks at the 292 * preflight point where you will not deliver the permission protected data 293 * to clients but schedule permission data delivery, apps register listeners, 294 * etc. 295 * 296 * <p>For example, if an app registers a location listener it should have the location 297 * permission but no data is actually sent to the app at the moment of registration 298 * and you should use this method to determine if the app has or may have location 299 * permission (if app has only foreground location the grant state depends on the app's 300 * fg/gb state) and this check will not leave a trace that permission protected data 301 * was delivered. When you are about to deliver the location data to a registered 302 * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context, 303 * String, String)} which will evaluate the permission access based on the current fg/bg state 304 * of the app and leave a record that the data was accessed. 305 * 306 * @param context Context for accessing resources. 307 * @param permission The permission to check. 308 * @param packageName The package name making the IPC. If null the 309 * the first package for the calling UID will be used. 310 * @return The permission check result which is either {@link #PERMISSION_GRANTED} 311 * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. 312 * 313 * @see #checkCallingPermissionForDataDelivery(Context, String, String, String) 314 */ 315 @PermissionResult checkCallingPermissionForPreflight(@onNull Context context, @NonNull String permission, @Nullable String packageName)316 public static int checkCallingPermissionForPreflight(@NonNull Context context, 317 @NonNull String permission, @Nullable String packageName) { 318 if (Binder.getCallingPid() == Process.myPid()) { 319 return PERMISSION_HARD_DENIED; 320 } 321 return checkPermissionForPreflight(context, permission, Binder.getCallingPid(), 322 Binder.getCallingUid(), packageName); 323 } 324 325 /** 326 * Checks whether the IPC you are handling or your app has a given permission 327 * and whether the app op that corresponds to this permission is allowed. 328 * 329 * <strong>NOTE:</strong> Use this method only for permission checks at the 330 * point where you will deliver the permission protected data to clients. 331 * 332 * <p>For example, if an app registers a location listener it should have the location 333 * permission but no data is actually sent to the app at the moment of registration 334 * and you should use {@link #checkCallingOrSelfPermissionForPreflight(Context, String)} 335 * to determine if the app has or may have location permission (if app has only foreground 336 * location the grant state depends on the app's fg/gb state) and this check will not 337 * leave a trace that permission protected data was delivered. When you are about to 338 * deliver the location data to a registered listener you should use this method which 339 * will evaluate the permission access based on the current fg/bg state of the app and 340 * leave a record that the data was accessed. 341 * 342 * @param context Context for accessing resources. 343 * @param permission The permission to check. 344 * @return The permission check result which is either {@link #PERMISSION_GRANTED} 345 * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. 346 * @param attributionTag attribution tag of caller (if not self) 347 * @param message A message describing the reason the permission was checked 348 * 349 * @see #checkCallingOrSelfPermissionForPreflight(Context, String) 350 */ 351 @PermissionResult checkCallingOrSelfPermissionForDataDelivery(@onNull Context context, @NonNull String permission, @Nullable String attributionTag, @Nullable String message)352 public static int checkCallingOrSelfPermissionForDataDelivery(@NonNull Context context, 353 @NonNull String permission, @Nullable String attributionTag, @Nullable String message) { 354 String packageName = (Binder.getCallingPid() == Process.myPid()) 355 ? context.getPackageName() : null; 356 attributionTag = (Binder.getCallingPid() == Process.myPid()) 357 ? context.getAttributionTag() : attributionTag; 358 return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(), 359 Binder.getCallingUid(), packageName, attributionTag, message); 360 } 361 362 /** 363 * Checks whether the IPC you are handling or your app has a given permission 364 * and whether the app op that corresponds to this permission is allowed. 365 * 366 * <strong>NOTE:</strong> Use this method only for permission checks at the 367 * preflight point where you will not deliver the permission protected data 368 * to clients but schedule permission data delivery, apps register listeners, 369 * etc. 370 * 371 * <p>For example, if an app registers a location listener it should have the location 372 * permission but no data is actually sent to the app at the moment of registration 373 * and you should use this method to determine if the app has or may have location 374 * permission (if app has only foreground location the grant state depends on the 375 * app's fg/gb state) and this check will not leave a trace that permission protected 376 * data was delivered. When you are about to deliver the location data to a registered 377 * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context, 378 * String, String, String)} which will evaluate the permission access based on the current 379 * fg/bg state of the app and leave a record that the data was accessed. 380 * 381 * @param context Context for accessing resources. 382 * @param permission The permission to check. 383 * @return The permission check result which is either {@link #PERMISSION_GRANTED} 384 * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. 385 * 386 * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String, String) 387 */ 388 @PermissionResult checkCallingOrSelfPermissionForPreflight(@onNull Context context, @NonNull String permission)389 public static int checkCallingOrSelfPermissionForPreflight(@NonNull Context context, 390 @NonNull String permission) { 391 String packageName = (Binder.getCallingPid() == Process.myPid()) 392 ? context.getPackageName() : null; 393 return checkPermissionForPreflight(context, permission, Binder.getCallingPid(), 394 Binder.getCallingUid(), packageName); 395 } 396 checkPermissionCommon(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)397 static int checkPermissionCommon(@NonNull Context context, @NonNull String permission, 398 int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, 399 @Nullable String message, boolean forDataDelivery) { 400 final PermissionInfo permissionInfo; 401 try { 402 // TODO(b/147869157): Cache platform defined app op and runtime permissions to avoid 403 // calling into the package manager every time. 404 permissionInfo = context.getPackageManager().getPermissionInfo(permission, 0); 405 } catch (PackageManager.NameNotFoundException ignored) { 406 return PERMISSION_HARD_DENIED; 407 } 408 409 if (packageName == null) { 410 String[] packageNames = context.getPackageManager().getPackagesForUid(uid); 411 if (packageNames != null && packageNames.length > 0) { 412 packageName = packageNames[0]; 413 } 414 } 415 416 if (permissionInfo.isAppOp()) { 417 return checkAppOpPermission(context, permission, pid, uid, packageName, attributionTag, 418 message, forDataDelivery); 419 } 420 if (permissionInfo.isRuntime()) { 421 return checkRuntimePermission(context, permission, pid, uid, packageName, 422 attributionTag, message, forDataDelivery); 423 } 424 return context.checkPermission(permission, pid, uid); 425 } 426 checkAppOpPermission(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)427 private static int checkAppOpPermission(@NonNull Context context, @NonNull String permission, 428 int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, 429 @Nullable String message, boolean forDataDelivery) { 430 final String op = AppOpsManager.permissionToOp(permission); 431 if (op == null || packageName == null) { 432 return PERMISSION_HARD_DENIED; 433 } 434 435 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 436 final int opMode = (forDataDelivery) 437 ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, attributionTag, message) 438 : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName); 439 440 switch (opMode) { 441 case AppOpsManager.MODE_ALLOWED: 442 case AppOpsManager.MODE_FOREGROUND: { 443 return PERMISSION_GRANTED; 444 } 445 case AppOpsManager.MODE_DEFAULT: { 446 return context.checkPermission(permission, pid, uid) 447 == PackageManager.PERMISSION_GRANTED 448 ? PERMISSION_GRANTED : PERMISSION_HARD_DENIED; 449 } 450 default: { 451 return PERMISSION_HARD_DENIED; 452 } 453 } 454 } 455 checkRuntimePermission(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)456 private static int checkRuntimePermission(@NonNull Context context, @NonNull String permission, 457 int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, 458 @Nullable String message, boolean forDataDelivery) { 459 if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { 460 return PERMISSION_HARD_DENIED; 461 } 462 463 final String op = AppOpsManager.permissionToOp(permission); 464 if (op == null || packageName == null) { 465 return PERMISSION_GRANTED; 466 } 467 468 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 469 final int opMode = (forDataDelivery) 470 ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, attributionTag, message) 471 : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName); 472 473 switch (opMode) { 474 case AppOpsManager.MODE_ALLOWED: 475 case AppOpsManager.MODE_FOREGROUND: 476 return PERMISSION_GRANTED; 477 default: 478 return PERMISSION_SOFT_DENIED; 479 } 480 } 481 } 482