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 for read permission when legacy storage is granted. 153 * There is a bug in AppOpsManager that keeps legacy storage granted even 154 * when an app updates its targetSdkVersion from value <30 to >=30. 155 * If an app upgrades from targetSdk 29 to targetSdk 33, legacy storage 156 * remains granted and in targetSdk 33, app are required to replace R_E_S 157 * with R_M_*. If an app updates its manifest with R_M_*, permission check 158 * in MediaProvider will look for R_E_S and will not grant read access as 159 * the app would be still treated as legacy. Ensure that legacy app either has 160 * R_E_S or all of R_M_* to get read permission. Since this is a fix for legacy 161 * app op bug, we are avoiding granular permission checks based on media type. 162 */ checkPermissionReadForLegacyStorage(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean isTargetSdkAtleastT)163 public static boolean checkPermissionReadForLegacyStorage(@NonNull Context context, 164 int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, 165 boolean isTargetSdkAtleastT) { 166 if (isTargetSdkAtleastT) { 167 return checkPermissionForDataDelivery(context, READ_EXTERNAL_STORAGE, pid, uid, 168 packageName, attributionTag, 169 generateAppOpMessage(packageName, sOpDescription.get())) || ( 170 checkPermissionForDataDelivery(context, READ_MEDIA_IMAGES, pid, uid, 171 packageName, attributionTag, 172 generateAppOpMessage(packageName, sOpDescription.get())) 173 && checkPermissionForDataDelivery(context, READ_MEDIA_VIDEO, pid, uid, 174 packageName, attributionTag, 175 generateAppOpMessage(packageName, sOpDescription.get())) 176 && checkPermissionForDataDelivery(context, READ_MEDIA_AUDIO, pid, uid, 177 packageName, attributionTag, 178 generateAppOpMessage(packageName, sOpDescription.get()))); 179 } else { 180 return checkPermissionForDataDelivery(context, READ_EXTERNAL_STORAGE, pid, uid, 181 packageName, attributionTag, 182 generateAppOpMessage(packageName, sOpDescription.get())); 183 } 184 } 185 186 /** 187 * Check if the given package has been granted the 188 * android.Manifest.permission#ACCESS_MEDIA_LOCATION permission. 189 */ checkPermissionAccessMediaLocation(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean isTargetSdkAtLeastT)190 public static boolean checkPermissionAccessMediaLocation(@NonNull Context context, int pid, 191 int uid, @NonNull String packageName, @Nullable String attributionTag, 192 boolean isTargetSdkAtLeastT) { 193 return checkPermissionForDataDelivery(context, ACCESS_MEDIA_LOCATION, pid, uid, packageName, 194 attributionTag, generateAppOpMessage(packageName, sOpDescription.get())) 195 || checkPermissionAccessMediaCompatGrant(context, pid, uid, packageName, 196 attributionTag, isTargetSdkAtLeastT); 197 } 198 199 /** 200 * Check if ACCESS_MEDIA_LOCATION is requested, and that READ_MEDIA_VISUAL_USER_SELECTED is 201 * implicitly requested and fully granted 202 */ checkPermissionAccessMediaCompatGrant(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean isTargetSdkAtLeastT)203 private static boolean checkPermissionAccessMediaCompatGrant(@NonNull Context context, int pid, 204 int uid, @NonNull String packageName, @Nullable String attributionTag, 205 boolean isTargetSdkAtLeastT) { 206 if (!SdkLevel.isAtLeastU() || !isTargetSdkAtLeastT) { 207 return false; 208 } 209 try { 210 PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, 211 PackageManager.GET_PERMISSIONS); 212 if (pi.requestedPermissions == null) { 213 return false; 214 } 215 216 boolean amlRequested = false; 217 boolean userSelectedImplicit = false; 218 for (int i = 0; i < pi.requestedPermissions.length; i++) { 219 if (ACCESS_MEDIA_LOCATION.equals(pi.requestedPermissions[i])) { 220 amlRequested = true; 221 } 222 if (READ_MEDIA_VISUAL_USER_SELECTED.equals(pi.requestedPermissions[i])) { 223 userSelectedImplicit = (pi.requestedPermissionsFlags[i] 224 & PackageInfo.REQUESTED_PERMISSION_IMPLICIT) != 0; 225 } 226 } 227 228 return amlRequested && userSelectedImplicit && checkPermissionReadVisualUserSelected( 229 context, pid, uid, packageName, attributionTag, isTargetSdkAtLeastT, 230 /* forDataDelivery */ true); 231 } catch (PackageManager.NameNotFoundException e) { 232 return false; 233 } 234 } 235 236 /** 237 * Check if the given package has been granted the 238 * android.Manifest.permission#MANAGE_MEDIA permission. 239 */ checkPermissionManageMedia(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)240 public static boolean checkPermissionManageMedia(@NonNull Context context, int pid, int uid, 241 @NonNull String packageName, @Nullable String attributionTag) { 242 return checkPermissionForDataDelivery(context, MANAGE_MEDIA, pid, uid, packageName, 243 attributionTag, generateAppOpMessage(packageName, sOpDescription.get())); 244 } 245 checkIsLegacyStorageGranted(@onNull Context context, int uid, String packageName, boolean isTargetSdkAtLeastV)246 public static boolean checkIsLegacyStorageGranted(@NonNull Context context, int uid, 247 String packageName, boolean isTargetSdkAtLeastV) { 248 if (!isTargetSdkAtLeastV && context.getSystemService(AppOpsManager.class) 249 .unsafeCheckOp(OPSTR_LEGACY_STORAGE, uid, packageName) == MODE_ALLOWED) { 250 return true; 251 } 252 // Check OPSTR_NO_ISOLATED_STORAGE app op. 253 return checkNoIsolatedStorageGranted(context, uid, packageName); 254 } 255 checkPermissionReadAudio( @onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean targetSdkIsAtLeastT, boolean forDataDelivery)256 public static boolean checkPermissionReadAudio( 257 @NonNull Context context, 258 int pid, 259 int uid, 260 @NonNull String packageName, 261 @Nullable String attributionTag, 262 boolean targetSdkIsAtLeastT, 263 boolean forDataDelivery) { 264 265 String permission = targetSdkIsAtLeastT && SdkLevel.isAtLeastT() 266 ? READ_MEDIA_AUDIO : READ_EXTERNAL_STORAGE; 267 268 if (!checkPermissionForPreflight(context, permission, pid, uid, packageName)) { 269 return false; 270 } 271 return checkAppOpAllowingLegacy(context, OPSTR_READ_MEDIA_AUDIO, pid, 272 uid, packageName, attributionTag, 273 generateAppOpMessage(packageName, sOpDescription.get()), forDataDelivery); 274 } 275 checkPermissionWriteAudio(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean forDataDelivery)276 public static boolean checkPermissionWriteAudio(@NonNull Context context, int pid, int uid, 277 @NonNull String packageName, @Nullable String attributionTag, boolean forDataDelivery) { 278 if (!checkPermissionAllowingNonLegacy( 279 context, WRITE_EXTERNAL_STORAGE, pid, uid, packageName)) { 280 return false; 281 } 282 return checkAppOpAllowingLegacy(context, OPSTR_WRITE_MEDIA_AUDIO, pid, 283 uid, packageName, attributionTag, 284 generateAppOpMessage(packageName, sOpDescription.get()), forDataDelivery); 285 } 286 checkPermissionReadVideo( @onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean targetSdkIsAtLeastT, boolean forDataDelivery)287 public static boolean checkPermissionReadVideo( 288 @NonNull Context context, 289 int pid, 290 int uid, 291 @NonNull String packageName, 292 @Nullable String attributionTag, 293 boolean targetSdkIsAtLeastT, 294 boolean forDataDelivery) { 295 String permission = targetSdkIsAtLeastT && SdkLevel.isAtLeastT() 296 ? READ_MEDIA_VIDEO : READ_EXTERNAL_STORAGE; 297 298 if (!checkPermissionForPreflight(context, permission, pid, uid, packageName)) { 299 return false; 300 } 301 302 return checkAppOpAllowingLegacy(context, OPSTR_READ_MEDIA_VIDEO, pid, 303 uid, packageName, attributionTag, 304 generateAppOpMessage(packageName, sOpDescription.get()), forDataDelivery); 305 } 306 checkPermissionWriteVideo(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean forDataDelivery)307 public static boolean checkPermissionWriteVideo(@NonNull Context context, int pid, int uid, 308 @NonNull String packageName, @Nullable String attributionTag, boolean forDataDelivery) { 309 if (!checkPermissionAllowingNonLegacy( 310 context, WRITE_EXTERNAL_STORAGE, pid, uid, packageName)) { 311 return false; 312 } 313 return checkAppOpAllowingLegacy(context, OPSTR_WRITE_MEDIA_VIDEO, pid, 314 uid, packageName, attributionTag, 315 generateAppOpMessage(packageName, sOpDescription.get()), forDataDelivery); 316 } 317 checkPermissionReadImages( @onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean targetSdkIsAtLeastT, boolean forDataDelivery)318 public static boolean checkPermissionReadImages( 319 @NonNull Context context, 320 int pid, 321 int uid, 322 @NonNull String packageName, 323 @Nullable String attributionTag, 324 boolean targetSdkIsAtLeastT, boolean forDataDelivery) { 325 String permission = targetSdkIsAtLeastT && SdkLevel.isAtLeastT() 326 ? READ_MEDIA_IMAGES : READ_EXTERNAL_STORAGE; 327 328 if (!checkPermissionForPreflight(context, permission, pid, uid, packageName)) { 329 return false; 330 } 331 332 return checkAppOpAllowingLegacy(context, OPSTR_READ_MEDIA_IMAGES, pid, 333 uid, packageName, attributionTag, 334 generateAppOpMessage(packageName, sOpDescription.get()), forDataDelivery); 335 } 336 checkPermissionWriteImages(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean forDataDelivery)337 public static boolean checkPermissionWriteImages(@NonNull Context context, int pid, int uid, 338 @NonNull String packageName, @Nullable String attributionTag, boolean forDataDelivery) { 339 if (!checkPermissionAllowingNonLegacy( 340 context, WRITE_EXTERNAL_STORAGE, pid, uid, packageName)) { 341 return false; 342 } 343 return checkAppOpAllowingLegacy(context, OPSTR_WRITE_MEDIA_IMAGES, pid, 344 uid, packageName, attributionTag, 345 generateAppOpMessage(packageName, sOpDescription.get()), forDataDelivery); 346 } 347 348 /** 349 * Check if the given package has been granted the 350 * android.Manifest.permission#READ_MEDIA_VISUAL_USER_SELECTED permission. 351 */ checkPermissionReadVisualUserSelected( @onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean targetSdkIsAtLeastT, boolean forDataDelivery)352 public static boolean checkPermissionReadVisualUserSelected( 353 @NonNull Context context, 354 int pid, 355 int uid, 356 @NonNull String packageName, 357 @Nullable String attributionTag, 358 boolean targetSdkIsAtLeastT, 359 boolean forDataDelivery) { 360 if (!SdkLevel.isAtLeastU() || !targetSdkIsAtLeastT) { 361 return false; 362 } 363 if (forDataDelivery) { 364 return checkPermissionForDataDelivery(context, READ_MEDIA_VISUAL_USER_SELECTED, pid, 365 uid, 366 packageName, attributionTag, 367 generateAppOpMessage(packageName, sOpDescription.get())); 368 } else { 369 return checkPermissionForPreflight(context, READ_MEDIA_VISUAL_USER_SELECTED, pid, 370 uid, 371 packageName); 372 } 373 } 374 375 /** 376 * Check if the given package has been granted the 377 * android.Manifest.permission#QUERY_ALL_PACKAGES permission. 378 */ checkPermissionQueryAllPackages(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)379 public static boolean checkPermissionQueryAllPackages(@NonNull Context context, int pid, 380 int uid, @NonNull String packageName, @Nullable String attributionTag) { 381 return checkPermissionForDataDelivery(context, QUERY_ALL_PACKAGES, pid, 382 uid, packageName, attributionTag, null); 383 } 384 385 /** 386 * Check if the given package has been granted the 387 * android.provider.MediaStore.#ACCESS_MEDIA_OWNER_PACKAGE_NAME_PERMISSION permission. 388 */ checkPermissionAccessMediaOwnerPackageName(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)389 public static boolean checkPermissionAccessMediaOwnerPackageName(@NonNull Context context, 390 int pid, int uid, @NonNull String packageName, @Nullable String attributionTag) { 391 return checkPermissionForDataDelivery(context, 392 MediaStore.ACCESS_MEDIA_OWNER_PACKAGE_NAME_PERMISSION, 393 pid, uid, packageName, attributionTag, null); 394 } 395 396 /** 397 * Check if the given package has been granted the 398 * {@link android.provider.MediaStore#ACCESS_OEM_METADATA_PERMISSION} permission. 399 */ checkPermissionAccessOemMetadata(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)400 public static boolean checkPermissionAccessOemMetadata(@NonNull Context context, 401 int pid, int uid, @NonNull String packageName, @Nullable String attributionTag) { 402 return checkPermissionForDataDelivery(context, MediaStore.ACCESS_OEM_METADATA_PERMISSION, 403 pid, uid, packageName, attributionTag, null); 404 } 405 406 /** 407 * Check if the given package has been granted the 408 * {@link android.provider.MediaStore#UPDATE_OEM_METADATA_PERMISSION} permission. 409 */ checkPermissionUpdateOemMetadata(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)410 public static boolean checkPermissionUpdateOemMetadata(@NonNull Context context, 411 int pid, int uid, @NonNull String packageName, @Nullable String attributionTag) { 412 return checkPermissionForPreflight(context, MediaStore.UPDATE_OEM_METADATA_PERMISSION, 413 pid, uid, packageName); 414 } 415 checkPermissionInstallPackages(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)416 public static boolean checkPermissionInstallPackages(@NonNull Context context, int pid, int uid, 417 @NonNull String packageName, @Nullable String attributionTag) { 418 return checkPermissionForDataDelivery(context, INSTALL_PACKAGES, pid, 419 uid, packageName, attributionTag, null); 420 } 421 checkPermissionAccessMtp(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)422 public static boolean checkPermissionAccessMtp(@NonNull Context context, int pid, int uid, 423 @NonNull String packageName, @Nullable String attributionTag) { 424 return checkPermissionForDataDelivery(context, ACCESS_MTP, pid, 425 uid, packageName, attributionTag, null); 426 } 427 428 /** 429 * Returns {@code true} if the given package has write images or write video app op, which 430 * indicates the package is a system gallery. 431 */ checkWriteImagesOrVideoAppOps(@onNull Context context, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean forDataDelivery)432 public static boolean checkWriteImagesOrVideoAppOps(@NonNull Context context, int uid, 433 @NonNull String packageName, @Nullable String attributionTag, boolean forDataDelivery) { 434 return checkAppOp( 435 context, OPSTR_WRITE_MEDIA_IMAGES, uid, packageName, attributionTag, 436 generateAppOpMessage(packageName, sOpDescription.get()), forDataDelivery) 437 || checkAppOp( 438 context, OPSTR_WRITE_MEDIA_VIDEO, uid, packageName, attributionTag, 439 generateAppOpMessage(packageName, sOpDescription.get()), forDataDelivery); 440 } 441 442 /** 443 * Returns {@code true} if any package for the given uid has request_install_packages app op. 444 */ checkAppOpRequestInstallPackagesForSharedUid(@onNull Context context, int uid, @NonNull String[] sharedPackageNames, @Nullable String attributionTag)445 public static boolean checkAppOpRequestInstallPackagesForSharedUid(@NonNull Context context, 446 int uid, @NonNull String[] sharedPackageNames, @Nullable String attributionTag) { 447 for (String packageName : sharedPackageNames) { 448 if (checkAppOp(context, OPSTR_REQUEST_INSTALL_PACKAGES, uid, packageName, 449 attributionTag, generateAppOpMessage(packageName, sOpDescription.get()), 450 /*forDataDelivery*/ false)) { 451 return true; 452 } 453 } 454 return false; 455 } 456 457 /** 458 * @param context Application context 459 * @param pid calling process ID 460 * @param uid callers UID 461 * @return true if the given uid has MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION permission, 462 * otherwise returns false. 463 */ checkManageCloudMediaProvidersPermission(@onNull Context context, int pid, @UserIdInt int uid)464 public static boolean checkManageCloudMediaProvidersPermission(@NonNull Context context, 465 int pid, @UserIdInt int uid) { 466 return context.checkPermission( 467 MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION, 468 pid, 469 uid 470 ) == PERMISSION_GRANTED; 471 } 472 473 @VisibleForTesting checkNoIsolatedStorageGranted(@onNull Context context, int uid, @NonNull String packageName)474 static boolean checkNoIsolatedStorageGranted(@NonNull Context context, int uid, 475 @NonNull String packageName) { 476 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 477 int ret = appOps.unsafeCheckOpNoThrow(OPSTR_NO_ISOLATED_STORAGE, uid, packageName); 478 return ret == AppOpsManager.MODE_ALLOWED; 479 } 480 481 /** 482 * Generates a message to be used with the different {@link AppOpsManager#noteOp} variations. 483 * If the supplied description is {@code null}, the returned message will be {@code null}. 484 */ generateAppOpMessage( @onNull String packageName, @Nullable String description)485 private static String generateAppOpMessage( 486 @NonNull String packageName, @Nullable String description) { 487 if (description == null) { 488 return null; 489 } 490 return "Package: " + packageName + ". Description: " + description + "."; 491 } 492 493 /** 494 * Similar to {@link #checkPermissionForPreflight(Context, String, int, int, String)}, 495 * but also returns true for non-legacy apps. 496 */ checkPermissionAllowingNonLegacy(@onNull Context context, @NonNull String permission, int pid, int uid, @NonNull String packageName)497 private static boolean checkPermissionAllowingNonLegacy(@NonNull Context context, 498 @NonNull String permission, int pid, int uid, @NonNull String packageName) { 499 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 500 501 // Allowing non legacy apps to bypass this check 502 if (appOps.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE, uid, 503 packageName) != AppOpsManager.MODE_ALLOWED) return true; 504 505 // Seems like it's a legacy app, so it has to pass the permission check 506 return checkPermissionForPreflight(context, permission, pid, uid, packageName); 507 } 508 509 /** 510 * Checks *only* App Ops. 511 */ checkAppOp(@onNull Context context, @NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, @Nullable String opMessage, boolean forDataDelivery)512 private static boolean checkAppOp(@NonNull Context context, 513 @NonNull String op, int uid, @NonNull String packageName, 514 @Nullable String attributionTag, @Nullable String opMessage, boolean forDataDelivery) { 515 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 516 final int mode = forDataDelivery ? appOps.noteOpNoThrow(op, uid, packageName, 517 attributionTag, opMessage) : appOps.unsafeCheckOpNoThrow(op, uid, packageName); 518 switch (mode) { 519 case AppOpsManager.MODE_ALLOWED: 520 return true; 521 case AppOpsManager.MODE_DEFAULT: 522 case AppOpsManager.MODE_IGNORED: 523 case AppOpsManager.MODE_ERRORED: 524 return false; 525 default: 526 throw new IllegalStateException(op + " has unknown mode " + mode); 527 } 528 } 529 530 531 /** 532 * Checks *only* App Ops, also returns true for legacy apps. 533 */ checkAppOpAllowingLegacy(@onNull Context context, @NonNull String op, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, @Nullable String opMessage, boolean forDataDelivery)534 private static boolean checkAppOpAllowingLegacy(@NonNull Context context, 535 @NonNull String op, int pid, int uid, @NonNull String packageName, 536 @Nullable String attributionTag, @Nullable String opMessage, boolean forDataDelivery) { 537 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class); 538 final int mode = forDataDelivery 539 ? appOps.noteOpNoThrow(op, uid, packageName, attributionTag, opMessage) 540 : appOps.unsafeCheckOpNoThrow(op, uid, packageName); 541 switch (mode) { 542 case AppOpsManager.MODE_ALLOWED: 543 return true; 544 case AppOpsManager.MODE_DEFAULT: 545 case AppOpsManager.MODE_IGNORED: 546 case AppOpsManager.MODE_ERRORED: 547 // Legacy apps technically have the access granted by this op, 548 // even when the op is denied 549 if ((appOps.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE, uid, 550 packageName) == AppOpsManager.MODE_ALLOWED)) return true; 551 552 return false; 553 default: 554 throw new IllegalStateException(op + " has unknown mode " + mode); 555 } 556 } 557 558 /** 559 * Checks whether a given package in a UID and PID has a given permission 560 * and whether the app op that corresponds to this permission is allowed. 561 * 562 * <strong>NOTE:</strong> Use this method only for permission checks at the 563 * preflight point where you will not deliver the permission protected data 564 * to clients but schedule permission data delivery, apps register listeners, 565 * etc. 566 * 567 * <p>For example, if an app registers a location listener it should have the location 568 * permission but no data is actually sent to the app at the moment of registration 569 * and you should use this method to determine if the app has or may have location 570 * permission (if app has only foreground location the grant state depends on the app's 571 * fg/gb state) and this check will not leave a trace that permission protected data 572 * was delivered. When you are about to deliver the location data to a registered 573 * listener you should use {@link #checkPermissionForDataDelivery(Context, String, 574 * int, int, String, String, String)} which will evaluate the permission access based on the 575 * current fg/bg state of the app and leave a record that the data was accessed. 576 * 577 * @param context Context for accessing resources. 578 * @param permission The permission to check. 579 * @param pid The process id for which to check. 580 * @param uid The uid for which to check. 581 * @param packageName The package name for which to check. If null the 582 * the first package for the calling UID will be used. 583 * @return boolean if permission is {@link #PERMISSION_GRANTED} 584 * 585 * @see #checkPermissionForDataDelivery(Context, String, int, int, String, String, String) 586 */ checkPermissionForPreflight(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName)587 private static boolean checkPermissionForPreflight(@NonNull Context context, 588 @NonNull String permission, int pid, int uid, @Nullable String packageName) { 589 return checkPermissionCommon(context, permission, pid, uid, packageName, 590 null /*attributionTag*/, null /*message*/, 591 false /*forDataDelivery*/); 592 } 593 594 /** 595 * Checks whether a given package in a UID and PID has a given permission 596 * and whether the app op that corresponds to this permission is allowed. 597 * 598 * <strong>NOTE:</strong> Use this method only for permission checks at the 599 * point where you will deliver the permission protected data to clients. 600 * 601 * <p>For example, if an app registers a location listener it should have the location 602 * permission but no data is actually sent to the app at the moment of registration 603 * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)} 604 * to determine if the app has or may have location permission (if app has only foreground 605 * location the grant state depends on the app's fg/gb state) and this check will not 606 * leave a trace that permission protected data was delivered. When you are about to 607 * deliver the location data to a registered listener you should use this method which 608 * will evaluate the permission access based on the current fg/bg state of the app and 609 * leave a record that the data was accessed. 610 * 611 * @param context Context for accessing resources. 612 * @param permission The permission to check. 613 * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID 614 * is not known. 615 * @param uid The uid for which to check. 616 * @param packageName The package name for which to check. If null the 617 * the first package for the calling UID will be used. 618 * @param attributionTag attribution tag 619 * @return boolean true if {@link #PERMISSION_GRANTED} 620 * @param message A message describing the reason the permission was checked 621 * 622 * @see #checkPermissionForPreflight(Context, String, int, int, String) 623 */ checkPermissionForDataDelivery(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message)624 private static boolean checkPermissionForDataDelivery(@NonNull Context context, 625 @NonNull String permission, int pid, int uid, @Nullable String packageName, 626 @Nullable String attributionTag, @Nullable String message) { 627 return checkPermissionCommon(context, permission, pid, uid, packageName, attributionTag, 628 message, true /*forDataDelivery*/); 629 } 630 checkPermissionCommon(@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 checkPermissionCommon(@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 (packageName == null) { 635 String[] packageNames = context.getPackageManager().getPackagesForUid(uid); 636 if (packageNames != null && packageNames.length > 0) { 637 packageName = packageNames[0]; 638 } 639 } 640 641 if (isAppOpPermission(permission)) { 642 return checkAppOpPermission(context, permission, pid, uid, packageName, attributionTag, 643 message, forDataDelivery); 644 } 645 if (isRuntimePermission(permission)) { 646 return checkRuntimePermission(context, permission, pid, uid, packageName, 647 attributionTag, message, forDataDelivery); 648 } 649 650 return context.checkPermission(permission, pid, uid) == PERMISSION_GRANTED; 651 } 652 isAppOpPermission(String permission)653 private static boolean isAppOpPermission(String permission) { 654 switch (permission) { 655 case MANAGE_EXTERNAL_STORAGE: 656 case MANAGE_MEDIA: 657 return true; 658 } 659 return false; 660 } 661 isRuntimePermission(String permission)662 private static boolean isRuntimePermission(String permission) { 663 switch (permission) { 664 case ACCESS_MEDIA_LOCATION: 665 case READ_EXTERNAL_STORAGE: 666 case WRITE_EXTERNAL_STORAGE: 667 case READ_MEDIA_AUDIO: 668 case READ_MEDIA_VIDEO: 669 case READ_MEDIA_IMAGES: 670 case READ_MEDIA_VISUAL_USER_SELECTED: 671 return true; 672 } 673 return false; 674 } 675 checkAppOpPermission(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)676 private static boolean checkAppOpPermission(@NonNull Context context, 677 @NonNull String permission, int pid, int uid, @Nullable String packageName, 678 @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery) { 679 final String op = AppOpsManager.permissionToOp(permission); 680 if (op == null || packageName == null) { 681 return false; 682 } 683 684 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 685 final int opMode = (forDataDelivery) 686 ? appOpsManager.noteOpNoThrow(op, uid, packageName, attributionTag, message) 687 : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName); 688 689 switch (opMode) { 690 case AppOpsManager.MODE_ALLOWED: 691 case AppOpsManager.MODE_FOREGROUND: 692 return true; 693 case AppOpsManager.MODE_DEFAULT: 694 return context.checkPermission(permission, pid, uid) == PERMISSION_GRANTED; 695 default: 696 return false; 697 } 698 } 699 checkRuntimePermission(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)700 private static boolean checkRuntimePermission(@NonNull Context context, 701 @NonNull String permission, int pid, int uid, @Nullable String packageName, 702 @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery) { 703 if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { 704 return false; 705 } 706 707 final String op = AppOpsManager.permissionToOp(permission); 708 if (op == null || packageName == null) { 709 return true; 710 } 711 712 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 713 final int opMode = (forDataDelivery) 714 ? appOpsManager.noteOpNoThrow(op, uid, packageName, attributionTag, message) 715 : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName); 716 717 switch (opMode) { 718 case AppOpsManager.MODE_ALLOWED: 719 case AppOpsManager.MODE_FOREGROUND: 720 return true; 721 default: 722 return false; 723 } 724 } 725 } 726