1 /* 2 * Copyright (C) 2019 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 com.android.providers.media.util; 18 19 import static android.Manifest.permission.ACCESS_MEDIA_LOCATION; 20 import static android.Manifest.permission.ACCESS_MTP; 21 import static android.Manifest.permission.BACKUP; 22 import static android.Manifest.permission.INSTALL_PACKAGES; 23 import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE; 24 import static android.Manifest.permission.MANAGE_MEDIA; 25 import static android.Manifest.permission.QUERY_ALL_PACKAGES; 26 import static android.Manifest.permission.READ_EXTERNAL_STORAGE; 27 import static android.Manifest.permission.READ_MEDIA_AUDIO; 28 import static android.Manifest.permission.READ_MEDIA_IMAGES; 29 import static android.Manifest.permission.READ_MEDIA_VIDEO; 30 import static android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED; 31 import static android.Manifest.permission.UPDATE_DEVICE_STATS; 32 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; 33 import static android.app.AppOpsManager.MODE_ALLOWED; 34 import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE; 35 import static android.app.AppOpsManager.OPSTR_NO_ISOLATED_STORAGE; 36 import static android.app.AppOpsManager.OPSTR_READ_MEDIA_AUDIO; 37 import static android.app.AppOpsManager.OPSTR_READ_MEDIA_IMAGES; 38 import static android.app.AppOpsManager.OPSTR_READ_MEDIA_VIDEO; 39 import static android.app.AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES; 40 import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_AUDIO; 41 import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES; 42 import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO; 43 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 44 import static android.provider.CloudMediaProviderContract.MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION; 45 46 import android.annotation.UserIdInt; 47 import android.app.AppOpsManager; 48 import android.app.DownloadManager; 49 import android.content.Context; 50 import android.content.pm.PackageInfo; 51 import android.content.pm.PackageManager; 52 import android.os.UserHandle; 53 import android.provider.MediaStore; 54 55 import androidx.annotation.NonNull; 56 import androidx.annotation.Nullable; 57 import androidx.annotation.VisibleForTesting; 58 59 import com.android.modules.utils.build.SdkLevel; 60 61 public class PermissionUtils { 62 63 // Callers must hold both the old and new permissions, so that we can 64 // handle obscure cases like when an app targets Q but was installed on 65 // a device that was originally running on P before being upgraded to Q. 66 67 private static ThreadLocal<String> sOpDescription = new ThreadLocal<>(); 68 setOpDescription(@ullable String description)69 public static void setOpDescription(@Nullable String description) { 70 sOpDescription.set(description); 71 } 72 clearOpDescription()73 public static void clearOpDescription() { sOpDescription.set(null); } 74 checkPermissionSelf(@onNull Context context, int pid, int uid)75 public static boolean checkPermissionSelf(@NonNull Context context, int pid, int uid) { 76 return UserHandle.getAppId(android.os.Process.myUid()) == UserHandle.getAppId(uid); 77 } 78 79 /** 80 * Return {@code true} when the given user id's corresponsing app id is the same as current 81 * process's app id, else return {@code false}. 82 */ checkPermissionSelf(@serIdInt int uid)83 public static boolean checkPermissionSelf(@UserIdInt int uid) { 84 return UserHandle.getAppId(android.os.Process.myUid()) == UserHandle.getAppId(uid); 85 } 86 87 /** 88 * Returns {@code true} if the given {@code uid} is a {@link android.os.Process.ROOT_UID} or 89 * {@link android.os.Process.SHELL_UID}. {@code false} otherwise. 90 */ checkPermissionShell(int uid)91 public static boolean checkPermissionShell(int uid) { 92 switch (uid) { 93 case android.os.Process.ROOT_UID: 94 case android.os.Process.SHELL_UID: 95 return true; 96 default: 97 return false; 98 } 99 } 100 101 /** 102 * @return {@code true} if the given {@code uid} is {@link android.os.Process#SYSTEM_UID}, 103 * {@code false} otherwise. 104 */ checkPermissionSystem(int uid)105 public static boolean checkPermissionSystem(int uid) { 106 return UserHandle.getAppId(uid) == android.os.Process.SYSTEM_UID; 107 } 108 109 /** 110 * Check if the given package has been granted the "file manager" role on 111 * the device, which should grant them certain broader access. 112 */ checkPermissionManager(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)113 public static boolean checkPermissionManager(@NonNull Context context, int pid, 114 int uid, @NonNull String packageName, @Nullable String attributionTag) { 115 return checkPermissionForDataDelivery(context, MANAGE_EXTERNAL_STORAGE, pid, uid, 116 packageName, attributionTag, 117 generateAppOpMessage(packageName,sOpDescription.get())); 118 } 119 120 /** 121 * Check if the given package has the ability to "delegate" the ownership of 122 * media items that they own to other apps, typically when they've finished 123 * performing operations on behalf of those apps. 124 * <p> 125 * One use-case for this is backup/restore apps, where the app restoring the 126 * content needs to shift the ownership back to the app that originally 127 * owned that media. 128 * <p> 129 * Another use-case is {@link DownloadManager}, which shifts ownership of 130 * finished downloads to the app that originally requested them. 131 */ checkPermissionDelegator(@onNull Context context, int pid, int uid)132 public static boolean checkPermissionDelegator(@NonNull Context context, int pid, int uid) { 133 return (context.checkPermission(BACKUP, pid, uid) == PERMISSION_GRANTED) 134 || (context.checkPermission(UPDATE_DEVICE_STATS, pid, uid) == PERMISSION_GRANTED); 135 } 136 checkPermissionWriteStorage(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)137 public static boolean checkPermissionWriteStorage(@NonNull Context context, int pid, int uid, 138 @NonNull String packageName, @Nullable String attributionTag) { 139 return checkPermissionForDataDelivery(context, WRITE_EXTERNAL_STORAGE, pid, uid, 140 packageName, attributionTag, 141 generateAppOpMessage(packageName,sOpDescription.get())); 142 } 143 checkPermissionReadStorage(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)144 public static boolean checkPermissionReadStorage(@NonNull Context context, int pid, int uid, 145 @NonNull String packageName, @Nullable String attributionTag) { 146 return checkPermissionForDataDelivery(context, READ_EXTERNAL_STORAGE, pid, uid, 147 packageName, attributionTag, 148 generateAppOpMessage(packageName,sOpDescription.get())); 149 } 150 151 /** 152 * Check if the given package has been granted the 153 * android.Manifest.permission#ACCESS_MEDIA_LOCATION permission. 154 */ checkPermissionAccessMediaLocation(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean isTargetSdkAtLeastT)155 public static boolean checkPermissionAccessMediaLocation(@NonNull Context context, int pid, 156 int uid, @NonNull String packageName, @Nullable String attributionTag, 157 boolean isTargetSdkAtLeastT) { 158 return checkPermissionForDataDelivery(context, ACCESS_MEDIA_LOCATION, pid, uid, packageName, 159 attributionTag, generateAppOpMessage(packageName, sOpDescription.get())) 160 || checkPermissionAccessMediaCompatGrant(context, pid, uid, packageName, 161 attributionTag, isTargetSdkAtLeastT); 162 } 163 164 /** 165 * Check if ACCESS_MEDIA_LOCATION is requested, and that READ_MEDIA_VISUAL_USER_SELECTED is 166 * implicitly requested and fully granted 167 */ checkPermissionAccessMediaCompatGrant(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean isTargetSdkAtLeastT)168 private static boolean checkPermissionAccessMediaCompatGrant(@NonNull Context context, int pid, 169 int uid, @NonNull String packageName, @Nullable String attributionTag, 170 boolean isTargetSdkAtLeastT) { 171 if (!SdkLevel.isAtLeastU() || !isTargetSdkAtLeastT) { 172 return false; 173 } 174 try { 175 PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, 176 PackageManager.GET_PERMISSIONS); 177 if (pi.requestedPermissions == null) { 178 return false; 179 } 180 181 boolean amlRequested = false; 182 boolean userSelectedImplicit = false; 183 for (int i = 0; i < pi.requestedPermissions.length; i++) { 184 if (ACCESS_MEDIA_LOCATION.equals(pi.requestedPermissions[i])) { 185 amlRequested = true; 186 } 187 if (READ_MEDIA_VISUAL_USER_SELECTED.equals(pi.requestedPermissions[i])) { 188 userSelectedImplicit = (pi.requestedPermissionsFlags[i] 189 & PackageInfo.REQUESTED_PERMISSION_IMPLICIT) != 0; 190 } 191 } 192 193 return amlRequested && userSelectedImplicit && checkPermissionReadVisualUserSelected( 194 context, pid, uid, packageName, attributionTag, isTargetSdkAtLeastT); 195 } catch (PackageManager.NameNotFoundException e) { 196 return false; 197 } 198 } 199 200 /** 201 * Check if the given package has been granted the 202 * android.Manifest.permission#MANAGE_MEDIA permission. 203 */ checkPermissionManageMedia(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)204 public static boolean checkPermissionManageMedia(@NonNull Context context, int pid, int uid, 205 @NonNull String packageName, @Nullable String attributionTag) { 206 return checkPermissionForDataDelivery(context, MANAGE_MEDIA, pid, uid, packageName, 207 attributionTag, generateAppOpMessage(packageName, sOpDescription.get())); 208 } 209 checkIsLegacyStorageGranted(@onNull Context context, int uid, String packageName, @Nullable String attributionTag, boolean isTargetSdkAtLeastV)210 public static boolean checkIsLegacyStorageGranted(@NonNull Context context, int uid, 211 String packageName, @Nullable String attributionTag, boolean isTargetSdkAtLeastV) { 212 if (!isTargetSdkAtLeastV && context.getSystemService(AppOpsManager.class) 213 .unsafeCheckOp(OPSTR_LEGACY_STORAGE, uid, packageName) == MODE_ALLOWED) { 214 return true; 215 } 216 // Check OPSTR_NO_ISOLATED_STORAGE app op. 217 return checkNoIsolatedStorageGranted(context, uid, packageName, attributionTag); 218 } 219 checkPermissionReadAudio( @onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean targetSdkIsAtLeastT)220 public static boolean checkPermissionReadAudio( 221 @NonNull Context context, 222 int pid, 223 int uid, 224 @NonNull String packageName, 225 @Nullable String attributionTag, 226 boolean targetSdkIsAtLeastT) { 227 228 String permission = targetSdkIsAtLeastT && SdkLevel.isAtLeastT() 229 ? READ_MEDIA_AUDIO : READ_EXTERNAL_STORAGE; 230 231 if (!checkPermissionForPreflight(context, permission, pid, uid, packageName)) { 232 return false; 233 } 234 return checkAppOpAllowingLegacy(context, OPSTR_READ_MEDIA_AUDIO, pid, 235 uid, packageName, attributionTag, 236 generateAppOpMessage(packageName, sOpDescription.get())); 237 } 238 checkPermissionWriteAudio(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)239 public static boolean checkPermissionWriteAudio(@NonNull Context context, int pid, int uid, 240 @NonNull String packageName, @Nullable String attributionTag) { 241 if (!checkPermissionAllowingNonLegacy( 242 context, WRITE_EXTERNAL_STORAGE, pid, uid, packageName)) { 243 return false; 244 } 245 return checkAppOpAllowingLegacy(context, OPSTR_WRITE_MEDIA_AUDIO, pid, 246 uid, packageName, attributionTag, 247 generateAppOpMessage(packageName, sOpDescription.get())); 248 } 249 checkPermissionReadVideo( @onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean targetSdkIsAtLeastT)250 public static boolean checkPermissionReadVideo( 251 @NonNull Context context, 252 int pid, 253 int uid, 254 @NonNull String packageName, 255 @Nullable String attributionTag, 256 boolean targetSdkIsAtLeastT) { 257 String permission = targetSdkIsAtLeastT && SdkLevel.isAtLeastT() 258 ? READ_MEDIA_VIDEO : READ_EXTERNAL_STORAGE; 259 260 if (!checkPermissionForPreflight(context, permission, pid, uid, packageName)) { 261 return false; 262 } 263 264 return checkAppOpAllowingLegacy(context, OPSTR_READ_MEDIA_VIDEO, pid, 265 uid, packageName, attributionTag, 266 generateAppOpMessage(packageName, sOpDescription.get())); 267 } 268 checkPermissionWriteVideo(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)269 public static boolean checkPermissionWriteVideo(@NonNull Context context, int pid, int uid, 270 @NonNull String packageName, @Nullable String attributionTag) { 271 if (!checkPermissionAllowingNonLegacy( 272 context, WRITE_EXTERNAL_STORAGE, pid, uid, packageName)) { 273 return false; 274 } 275 return checkAppOpAllowingLegacy(context, OPSTR_WRITE_MEDIA_VIDEO, pid, 276 uid, packageName, attributionTag, 277 generateAppOpMessage(packageName, sOpDescription.get())); 278 } 279 checkPermissionReadImages( @onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean targetSdkIsAtLeastT)280 public static boolean checkPermissionReadImages( 281 @NonNull Context context, 282 int pid, 283 int uid, 284 @NonNull String packageName, 285 @Nullable String attributionTag, 286 boolean targetSdkIsAtLeastT) { 287 String permission = targetSdkIsAtLeastT && SdkLevel.isAtLeastT() 288 ? READ_MEDIA_IMAGES : READ_EXTERNAL_STORAGE; 289 290 if (!checkPermissionForPreflight(context, permission, pid, uid, packageName)) { 291 return false; 292 } 293 294 return checkAppOpAllowingLegacy(context, OPSTR_READ_MEDIA_IMAGES, pid, 295 uid, packageName, attributionTag, 296 generateAppOpMessage(packageName, sOpDescription.get())); 297 } 298 checkPermissionWriteImages(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)299 public static boolean checkPermissionWriteImages(@NonNull Context context, int pid, int uid, 300 @NonNull String packageName, @Nullable String attributionTag) { 301 if (!checkPermissionAllowingNonLegacy( 302 context, WRITE_EXTERNAL_STORAGE, pid, uid, packageName)) { 303 return false; 304 } 305 return checkAppOpAllowingLegacy(context, OPSTR_WRITE_MEDIA_IMAGES, pid, 306 uid, packageName, attributionTag, 307 generateAppOpMessage(packageName, sOpDescription.get())); 308 } 309 310 /** 311 * Check if the given package has been granted the 312 * android.Manifest.permission#READ_MEDIA_VISUAL_USER_SELECTED permission. 313 */ checkPermissionReadVisualUserSelected( @onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean targetSdkIsAtLeastT)314 public static boolean checkPermissionReadVisualUserSelected( 315 @NonNull Context context, 316 int pid, 317 int uid, 318 @NonNull String packageName, 319 @Nullable String attributionTag, 320 boolean targetSdkIsAtLeastT) { 321 if (!SdkLevel.isAtLeastU() || !targetSdkIsAtLeastT) { 322 return false; 323 } 324 return checkPermissionForDataDelivery(context, READ_MEDIA_VISUAL_USER_SELECTED, pid, uid, 325 packageName, attributionTag, 326 generateAppOpMessage(packageName, sOpDescription.get())); 327 } 328 329 /** 330 * Check if the given package has been granted the 331 * android.Manifest.permission#QUERY_ALL_PACKAGES permission. 332 */ checkPermissionQueryAllPackages(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)333 public static boolean checkPermissionQueryAllPackages(@NonNull Context context, int pid, 334 int uid, @NonNull String packageName, @Nullable String attributionTag) { 335 return checkPermissionForDataDelivery(context, QUERY_ALL_PACKAGES, pid, 336 uid, packageName, attributionTag, null); 337 } 338 339 /** 340 * Check if the given package has been granted the 341 * android.provider.MediaStore.#ACCESS_MEDIA_OWNER_PACKAGE_NAME_PERMISSION permission. 342 */ checkPermissionAccessMediaOwnerPackageName(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)343 public static boolean checkPermissionAccessMediaOwnerPackageName(@NonNull Context context, 344 int pid, int uid, @NonNull String packageName, @Nullable String attributionTag) { 345 return checkPermissionForDataDelivery(context, 346 MediaStore.ACCESS_MEDIA_OWNER_PACKAGE_NAME_PERMISSION, 347 pid, uid, packageName, attributionTag, null); 348 } 349 checkPermissionInstallPackages(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)350 public static boolean checkPermissionInstallPackages(@NonNull Context context, int pid, int uid, 351 @NonNull String packageName, @Nullable String attributionTag) { 352 return checkPermissionForDataDelivery(context, INSTALL_PACKAGES, pid, 353 uid, packageName, attributionTag, null); 354 } 355 checkPermissionAccessMtp(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)356 public static boolean checkPermissionAccessMtp(@NonNull Context context, int pid, int uid, 357 @NonNull String packageName, @Nullable String attributionTag) { 358 return checkPermissionForDataDelivery(context, ACCESS_MTP, pid, 359 uid, packageName, attributionTag, null); 360 } 361 362 /** 363 * Returns {@code true} if the given package has write images or write video app op, which 364 * indicates the package is a system gallery. 365 */ checkWriteImagesOrVideoAppOps(@onNull Context context, int uid, @NonNull String packageName, @Nullable String attributionTag)366 public static boolean checkWriteImagesOrVideoAppOps(@NonNull Context context, int uid, 367 @NonNull String packageName, @Nullable String attributionTag) { 368 return checkAppOp( 369 context, OPSTR_WRITE_MEDIA_IMAGES, uid, packageName, attributionTag, 370 generateAppOpMessage(packageName, sOpDescription.get())) 371 || checkAppOp( 372 context, OPSTR_WRITE_MEDIA_VIDEO, uid, packageName, attributionTag, 373 generateAppOpMessage(packageName, sOpDescription.get())); 374 } 375 376 /** 377 * Returns {@code true} if any package for the given uid has request_install_packages app op. 378 */ checkAppOpRequestInstallPackagesForSharedUid(@onNull Context context, int uid, @NonNull String[] sharedPackageNames, @Nullable String attributionTag)379 public static boolean checkAppOpRequestInstallPackagesForSharedUid(@NonNull Context context, 380 int uid, @NonNull String[] sharedPackageNames, @Nullable String attributionTag) { 381 for (String packageName : sharedPackageNames) { 382 if (checkAppOp(context, OPSTR_REQUEST_INSTALL_PACKAGES, uid, packageName, 383 attributionTag, generateAppOpMessage(packageName, sOpDescription.get()))) { 384 return true; 385 } 386 } 387 return false; 388 } 389 390 /** 391 * @param context Application context 392 * @param pid calling process ID 393 * @param uid callers UID 394 * @return true if the given uid has MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION permission, 395 * otherwise returns false. 396 */ checkManageCloudMediaProvidersPermission(@onNull Context context, int pid, @UserIdInt int uid)397 public static boolean checkManageCloudMediaProvidersPermission(@NonNull Context context, 398 int pid, @UserIdInt int uid) { 399 return context.checkPermission( 400 MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION, 401 pid, 402 uid 403 ) == PERMISSION_GRANTED; 404 } 405 406 @VisibleForTesting checkNoIsolatedStorageGranted(@onNull Context context, int uid, @NonNull String packageName, @Nullable String attributionTag)407 static boolean checkNoIsolatedStorageGranted(@NonNull Context context, int uid, 408 @NonNull String packageName, @Nullable String attributionTag) { 409 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 410 int ret = appOps.noteOpNoThrow(OPSTR_NO_ISOLATED_STORAGE, uid, packageName, attributionTag, 411 generateAppOpMessage(packageName, "am instrument --no-isolated-storage")); 412 return ret == AppOpsManager.MODE_ALLOWED; 413 } 414 415 /** 416 * Generates a message to be used with the different {@link AppOpsManager#noteOp} variations. 417 * If the supplied description is {@code null}, the returned message will be {@code null}. 418 */ generateAppOpMessage( @onNull String packageName, @Nullable String description)419 private static String generateAppOpMessage( 420 @NonNull String packageName, @Nullable String description) { 421 if (description == null) { 422 return null; 423 } 424 return "Package: " + packageName + ". Description: " + description + "."; 425 } 426 427 /** 428 * Similar to {@link #checkPermissionForPreflight(Context, String, int, int, String)}, 429 * but also returns true for non-legacy apps. 430 */ checkPermissionAllowingNonLegacy(@onNull Context context, @NonNull String permission, int pid, int uid, @NonNull String packageName)431 private static boolean checkPermissionAllowingNonLegacy(@NonNull Context context, 432 @NonNull String permission, int pid, int uid, @NonNull String packageName) { 433 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 434 435 // Allowing non legacy apps to bypass this check 436 if (appOps.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE, uid, 437 packageName) != AppOpsManager.MODE_ALLOWED) return true; 438 439 // Seems like it's a legacy app, so it has to pass the permission check 440 return checkPermissionForPreflight(context, permission, pid, uid, packageName); 441 } 442 443 /** 444 * Checks *only* App Ops. 445 */ checkAppOp(@onNull Context context, @NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, @Nullable String opMessage)446 private static boolean checkAppOp(@NonNull Context context, 447 @NonNull String op, int uid, @NonNull String packageName, 448 @Nullable String attributionTag, @Nullable String opMessage) { 449 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 450 final int mode = appOps.noteOpNoThrow(op, uid, packageName, attributionTag, opMessage); 451 switch (mode) { 452 case AppOpsManager.MODE_ALLOWED: 453 return true; 454 case AppOpsManager.MODE_DEFAULT: 455 case AppOpsManager.MODE_IGNORED: 456 case AppOpsManager.MODE_ERRORED: 457 return false; 458 default: 459 throw new IllegalStateException(op + " has unknown mode " + mode); 460 } 461 } 462 463 464 /** 465 * Checks *only* App Ops, also returns true for legacy apps. 466 */ checkAppOpAllowingLegacy(@onNull Context context, @NonNull String op, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, @Nullable String opMessage)467 private static boolean checkAppOpAllowingLegacy(@NonNull Context context, 468 @NonNull String op, int pid, int uid, @NonNull String packageName, 469 @Nullable String attributionTag, @Nullable String opMessage) { 470 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 471 final int mode = appOps.noteOpNoThrow(op, uid, packageName, attributionTag, opMessage); 472 switch (mode) { 473 case AppOpsManager.MODE_ALLOWED: 474 return true; 475 case AppOpsManager.MODE_DEFAULT: 476 case AppOpsManager.MODE_IGNORED: 477 case AppOpsManager.MODE_ERRORED: 478 // Legacy apps technically have the access granted by this op, 479 // even when the op is denied 480 if ((appOps.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE, uid, 481 packageName) == AppOpsManager.MODE_ALLOWED)) return true; 482 483 return false; 484 default: 485 throw new IllegalStateException(op + " has unknown mode " + mode); 486 } 487 } 488 489 /** 490 * Checks whether a given package in a UID and PID has a given permission 491 * and whether the app op that corresponds to this permission is allowed. 492 * 493 * <strong>NOTE:</strong> Use this method only for permission checks at the 494 * preflight point where you will not deliver the permission protected data 495 * to clients but schedule permission data delivery, apps register listeners, 496 * etc. 497 * 498 * <p>For example, if an app registers a location listener it should have the location 499 * permission but no data is actually sent to the app at the moment of registration 500 * and you should use this method to determine if the app has or may have location 501 * permission (if app has only foreground location the grant state depends on the app's 502 * fg/gb state) and this check will not leave a trace that permission protected data 503 * was delivered. When you are about to deliver the location data to a registered 504 * listener you should use {@link #checkPermissionForDataDelivery(Context, String, 505 * int, int, String, String, String)} which will evaluate the permission access based on the 506 * current fg/bg state of the app and leave a record that the data was accessed. 507 * 508 * @param context Context for accessing resources. 509 * @param permission The permission to check. 510 * @param pid The process id for which to check. 511 * @param uid The uid for which to check. 512 * @param packageName The package name for which to check. If null the 513 * the first package for the calling UID will be used. 514 * @return boolean if permission is {@link #PERMISSION_GRANTED} 515 * 516 * @see #checkPermissionForDataDelivery(Context, String, int, int, String, String, String) 517 */ checkPermissionForPreflight(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName)518 private static boolean checkPermissionForPreflight(@NonNull Context context, 519 @NonNull String permission, int pid, int uid, @Nullable String packageName) { 520 return checkPermissionCommon(context, permission, pid, uid, packageName, 521 null /*attributionTag*/, null /*message*/, 522 false /*forDataDelivery*/); 523 } 524 525 /** 526 * Checks whether a given package in a UID and PID has a given permission 527 * and whether the app op that corresponds to this permission is allowed. 528 * 529 * <strong>NOTE:</strong> Use this method only for permission checks at the 530 * point where you will deliver the permission protected data to clients. 531 * 532 * <p>For example, if an app registers a location listener it should have the location 533 * permission but no data is actually sent to the app at the moment of registration 534 * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)} 535 * to determine if the app has or may have location permission (if app has only foreground 536 * location the grant state depends on the app's fg/gb state) and this check will not 537 * leave a trace that permission protected data was delivered. When you are about to 538 * deliver the location data to a registered listener you should use this method which 539 * will evaluate the permission access based on the current fg/bg state of the app and 540 * leave a record that the data was accessed. 541 * 542 * @param context Context for accessing resources. 543 * @param permission The permission to check. 544 * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID 545 * is not known. 546 * @param uid The uid for which to check. 547 * @param packageName The package name for which to check. If null the 548 * the first package for the calling UID will be used. 549 * @param attributionTag attribution tag 550 * @return boolean true if {@link #PERMISSION_GRANTED} 551 * @param message A message describing the reason the permission was checked 552 * 553 * @see #checkPermissionForPreflight(Context, String, int, int, String) 554 */ checkPermissionForDataDelivery(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message)555 private static boolean checkPermissionForDataDelivery(@NonNull Context context, 556 @NonNull String permission, int pid, int uid, @Nullable String packageName, 557 @Nullable String attributionTag, @Nullable String message) { 558 return checkPermissionCommon(context, permission, pid, uid, packageName, attributionTag, 559 message, true /*forDataDelivery*/); 560 } 561 checkPermissionCommon(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)562 private static boolean checkPermissionCommon(@NonNull Context context, 563 @NonNull String permission, int pid, int uid, @Nullable String packageName, 564 @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery) { 565 if (packageName == null) { 566 String[] packageNames = context.getPackageManager().getPackagesForUid(uid); 567 if (packageNames != null && packageNames.length > 0) { 568 packageName = packageNames[0]; 569 } 570 } 571 572 if (isAppOpPermission(permission)) { 573 return checkAppOpPermission(context, permission, pid, uid, packageName, attributionTag, 574 message, forDataDelivery); 575 } 576 if (isRuntimePermission(permission)) { 577 return checkRuntimePermission(context, permission, pid, uid, packageName, 578 attributionTag, message, forDataDelivery); 579 } 580 581 return context.checkPermission(permission, pid, uid) == PERMISSION_GRANTED; 582 } 583 isAppOpPermission(String permission)584 private static boolean isAppOpPermission(String permission) { 585 switch (permission) { 586 case MANAGE_EXTERNAL_STORAGE: 587 case MANAGE_MEDIA: 588 return true; 589 } 590 return false; 591 } 592 isRuntimePermission(String permission)593 private static boolean isRuntimePermission(String permission) { 594 switch (permission) { 595 case ACCESS_MEDIA_LOCATION: 596 case READ_EXTERNAL_STORAGE: 597 case WRITE_EXTERNAL_STORAGE: 598 case READ_MEDIA_AUDIO: 599 case READ_MEDIA_VIDEO: 600 case READ_MEDIA_IMAGES: 601 case READ_MEDIA_VISUAL_USER_SELECTED: 602 return true; 603 } 604 return false; 605 } 606 checkAppOpPermission(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)607 private static boolean checkAppOpPermission(@NonNull Context context, 608 @NonNull String permission, int pid, int uid, @Nullable String packageName, 609 @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery) { 610 final String op = AppOpsManager.permissionToOp(permission); 611 if (op == null || packageName == null) { 612 return false; 613 } 614 615 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 616 final int opMode = (forDataDelivery) 617 ? appOpsManager.noteOpNoThrow(op, uid, packageName, attributionTag, message) 618 : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName); 619 620 switch (opMode) { 621 case AppOpsManager.MODE_ALLOWED: 622 case AppOpsManager.MODE_FOREGROUND: 623 return true; 624 case AppOpsManager.MODE_DEFAULT: 625 return context.checkPermission(permission, pid, uid) == PERMISSION_GRANTED; 626 default: 627 return false; 628 } 629 } 630 checkRuntimePermission(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)631 private static boolean checkRuntimePermission(@NonNull Context context, 632 @NonNull String permission, int pid, int uid, @Nullable String packageName, 633 @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery) { 634 if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { 635 return false; 636 } 637 638 final String op = AppOpsManager.permissionToOp(permission); 639 if (op == null || packageName == null) { 640 return true; 641 } 642 643 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 644 final int opMode = (forDataDelivery) 645 ? appOpsManager.noteOpNoThrow(op, uid, packageName, attributionTag, message) 646 : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName); 647 648 switch (opMode) { 649 case AppOpsManager.MODE_ALLOWED: 650 case AppOpsManager.MODE_FOREGROUND: 651 return true; 652 default: 653 return false; 654 } 655 } 656 } 657