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