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