1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.permission; 18 19 import android.Manifest; 20 import android.annotation.CallbackExecutor; 21 import android.annotation.IntRange; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.RequiresPermission; 25 import android.annotation.SystemApi; 26 import android.annotation.SystemService; 27 import android.annotation.TestApi; 28 import android.app.ActivityManager; 29 import android.app.ActivityThread; 30 import android.app.IActivityManager; 31 import android.app.PropertyInvalidatedCache; 32 import android.content.Context; 33 import android.content.pm.IPackageManager; 34 import android.content.pm.PackageManager; 35 import android.content.pm.permission.SplitPermissionInfoParcelable; 36 import android.os.Process; 37 import android.os.RemoteException; 38 import android.os.ServiceManager; 39 import android.os.UserHandle; 40 import android.util.Slog; 41 42 import com.android.internal.annotations.Immutable; 43 import com.android.internal.annotations.VisibleForTesting; 44 import com.android.internal.util.CollectionUtils; 45 46 import java.util.ArrayList; 47 import java.util.Collections; 48 import java.util.List; 49 import java.util.Objects; 50 import java.util.Set; 51 import java.util.concurrent.Executor; 52 import java.util.function.Consumer; 53 54 /** 55 * System level service for accessing the permission capabilities of the platform. 56 * 57 * @hide 58 */ 59 @TestApi 60 @SystemApi 61 @SystemService(Context.PERMISSION_SERVICE) 62 public final class PermissionManager { 63 private static final String TAG = PermissionManager.class.getName(); 64 65 /** @hide */ 66 public static final String KILL_APP_REASON_PERMISSIONS_REVOKED = 67 "permissions revoked"; 68 /** @hide */ 69 public static final String KILL_APP_REASON_GIDS_CHANGED = 70 "permission grant or revoke changed gids"; 71 72 private final @NonNull Context mContext; 73 74 private final IPackageManager mPackageManager; 75 76 private final IPermissionManager mPermissionManager; 77 78 private List<SplitPermissionInfo> mSplitPermissionInfos; 79 80 /** 81 * Creates a new instance. 82 * 83 * @param context The current context in which to operate. 84 * @hide 85 */ PermissionManager(@onNull Context context, IPackageManager packageManager)86 public PermissionManager(@NonNull Context context, IPackageManager packageManager) 87 throws ServiceManager.ServiceNotFoundException { 88 this(context, packageManager, IPermissionManager.Stub.asInterface( 89 ServiceManager.getServiceOrThrow("permissionmgr"))); 90 } 91 92 /** 93 * Creates a new instance with the provided instantiation of the IPermissionManager. 94 * 95 * @param context the current context in which to operate 96 * @param packageManager package manager service to be used for package related permission 97 * requests 98 * @param permissionManager injectable permission manager service 99 * @hide 100 */ 101 @VisibleForTesting PermissionManager(@onNull Context context, IPackageManager packageManager, IPermissionManager permissionManager)102 public PermissionManager(@NonNull Context context, IPackageManager packageManager, 103 IPermissionManager permissionManager) { 104 mContext = context; 105 mPackageManager = packageManager; 106 mPermissionManager = permissionManager; 107 } 108 109 /** 110 * Gets the version of the runtime permission database. 111 * 112 * @return The database version, -1 when this is an upgrade from pre-Q, 0 when this is a fresh 113 * install. 114 * 115 * @hide 116 */ 117 @TestApi 118 @SystemApi 119 @RequiresPermission(anyOf = { 120 Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, 121 Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS 122 }) getRuntimePermissionsVersion()123 public @IntRange(from = 0) int getRuntimePermissionsVersion() { 124 try { 125 return mPackageManager.getRuntimePermissionsVersion(mContext.getUserId()); 126 } catch (RemoteException e) { 127 throw e.rethrowFromSystemServer(); 128 } 129 } 130 131 /** 132 * Sets the version of the runtime permission database. 133 * 134 * @param version The new version. 135 * 136 * @hide 137 */ 138 @TestApi 139 @SystemApi 140 @RequiresPermission(anyOf = { 141 Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, 142 Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS 143 }) setRuntimePermissionsVersion(@ntRangefrom = 0) int version)144 public void setRuntimePermissionsVersion(@IntRange(from = 0) int version) { 145 try { 146 mPackageManager.setRuntimePermissionsVersion(version, mContext.getUserId()); 147 } catch (RemoteException e) { 148 throw e.rethrowFromSystemServer(); 149 } 150 } 151 152 /** 153 * Get set of permissions that have been split into more granular or dependent permissions. 154 * 155 * <p>E.g. before {@link android.os.Build.VERSION_CODES#Q} an app that was granted 156 * {@link Manifest.permission#ACCESS_COARSE_LOCATION} could access he location while it was in 157 * foreground and background. On platforms after {@link android.os.Build.VERSION_CODES#Q} 158 * the location permission only grants location access while the app is in foreground. This 159 * would break apps that target before {@link android.os.Build.VERSION_CODES#Q}. Hence whenever 160 * such an old app asks for a location permission (i.e. the 161 * {@link SplitPermissionInfo#getSplitPermission()}), then the 162 * {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside 163 * {@link SplitPermissionInfo#getNewPermissions}) is added. 164 * 165 * <p>Note: Regular apps do not have to worry about this. The platform and permission controller 166 * automatically add the new permissions where needed. 167 * 168 * @return All permissions that are split. 169 */ getSplitPermissions()170 public @NonNull List<SplitPermissionInfo> getSplitPermissions() { 171 if (mSplitPermissionInfos != null) { 172 return mSplitPermissionInfos; 173 } 174 175 List<SplitPermissionInfoParcelable> parcelableList; 176 try { 177 parcelableList = ActivityThread.getPermissionManager().getSplitPermissions(); 178 } catch (RemoteException e) { 179 Slog.e(TAG, "Error getting split permissions", e); 180 return Collections.emptyList(); 181 } 182 183 mSplitPermissionInfos = splitPermissionInfoListToNonParcelableList(parcelableList); 184 185 return mSplitPermissionInfos; 186 } 187 188 /** 189 * Grant default permissions to currently active LUI app 190 * @param packageName The package name for the LUI app 191 * @param user The user handle 192 * @param executor The executor for the callback 193 * @param callback The callback provided by caller to be notified when grant completes 194 * @hide 195 */ 196 @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) grantDefaultPermissionsToLuiApp( @onNull String packageName, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)197 public void grantDefaultPermissionsToLuiApp( 198 @NonNull String packageName, @NonNull UserHandle user, 199 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 200 try { 201 mPermissionManager.grantDefaultPermissionsToActiveLuiApp( 202 packageName, user.getIdentifier()); 203 executor.execute(() -> callback.accept(true)); 204 } catch (RemoteException e) { 205 e.rethrowFromSystemServer(); 206 } 207 } 208 209 /** 210 * Revoke default permissions to currently active LUI app 211 * @param packageNames The package names for the LUI apps 212 * @param user The user handle 213 * @param executor The executor for the callback 214 * @param callback The callback provided by caller to be notified when grant completes 215 * @hide 216 */ 217 @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) revokeDefaultPermissionsFromLuiApps( @onNull String[] packageNames, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)218 public void revokeDefaultPermissionsFromLuiApps( 219 @NonNull String[] packageNames, @NonNull UserHandle user, 220 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 221 try { 222 mPermissionManager.revokeDefaultPermissionsFromLuiApps( 223 packageNames, user.getIdentifier()); 224 executor.execute(() -> callback.accept(true)); 225 } catch (RemoteException e) { 226 e.rethrowFromSystemServer(); 227 } 228 } 229 230 /** 231 * Grant default permissions to currently active Ims services 232 * @param packageNames The package names for the Ims services 233 * @param user The user handle 234 * @param executor The executor for the callback 235 * @param callback The callback provided by caller to be notified when grant completes 236 * @hide 237 */ 238 @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) grantDefaultPermissionsToEnabledImsServices( @onNull String[] packageNames, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)239 public void grantDefaultPermissionsToEnabledImsServices( 240 @NonNull String[] packageNames, @NonNull UserHandle user, 241 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 242 try { 243 mPermissionManager.grantDefaultPermissionsToEnabledImsServices( 244 packageNames, user.getIdentifier()); 245 executor.execute(() -> callback.accept(true)); 246 } catch (RemoteException e) { 247 e.rethrowFromSystemServer(); 248 } 249 } 250 251 /** 252 * Grant default permissions to currently enabled telephony data services 253 * @param packageNames The package name for the services 254 * @param user The user handle 255 * @param executor The executor for the callback 256 * @param callback The callback provided by caller to be notified when grant completes 257 * @hide 258 */ 259 @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) grantDefaultPermissionsToEnabledTelephonyDataServices( @onNull String[] packageNames, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)260 public void grantDefaultPermissionsToEnabledTelephonyDataServices( 261 @NonNull String[] packageNames, @NonNull UserHandle user, 262 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 263 try { 264 mPermissionManager.grantDefaultPermissionsToEnabledTelephonyDataServices( 265 packageNames, user.getIdentifier()); 266 executor.execute(() -> callback.accept(true)); 267 } catch (RemoteException e) { 268 e.rethrowFromSystemServer(); 269 } 270 } 271 272 /** 273 * Revoke default permissions to currently active telephony data services 274 * @param packageNames The package name for the services 275 * @param user The user handle 276 * @param executor The executor for the callback 277 * @param callback The callback provided by caller to be notified when revoke completes 278 * @hide 279 */ 280 @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) revokeDefaultPermissionsFromDisabledTelephonyDataServices( @onNull String[] packageNames, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)281 public void revokeDefaultPermissionsFromDisabledTelephonyDataServices( 282 @NonNull String[] packageNames, @NonNull UserHandle user, 283 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 284 try { 285 mPermissionManager.revokeDefaultPermissionsFromDisabledTelephonyDataServices( 286 packageNames, user.getIdentifier()); 287 executor.execute(() -> callback.accept(true)); 288 } catch (RemoteException e) { 289 e.rethrowFromSystemServer(); 290 } 291 } 292 293 /** 294 * Grant default permissions to currently enabled carrier apps 295 * @param packageNames Package names of the apps to be granted permissions 296 * @param user The user handle 297 * @param executor The executor for the callback 298 * @param callback The callback provided by caller to be notified when grant completes 299 * @hide 300 */ 301 @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) grantDefaultPermissionsToEnabledCarrierApps(@onNull String[] packageNames, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)302 public void grantDefaultPermissionsToEnabledCarrierApps(@NonNull String[] packageNames, 303 @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, 304 @NonNull Consumer<Boolean> callback) { 305 try { 306 mPermissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, 307 user.getIdentifier()); 308 executor.execute(() -> callback.accept(true)); 309 } catch (RemoteException e) { 310 e.rethrowFromSystemServer(); 311 } 312 } 313 314 /** 315 * Gets the list of packages that have permissions that specified 316 * {@code requestDontAutoRevokePermissions=true} in their 317 * {@code application} manifest declaration. 318 * 319 * @return the list of packages for current user 320 * @hide 321 */ 322 @SystemApi 323 @NonNull 324 @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) getAutoRevokeExemptionRequestedPackages()325 public Set<String> getAutoRevokeExemptionRequestedPackages() { 326 try { 327 return CollectionUtils.toSet(mPermissionManager.getAutoRevokeExemptionRequestedPackages( 328 mContext.getUser().getIdentifier())); 329 } catch (RemoteException e) { 330 throw e.rethrowFromSystemServer(); 331 } 332 } 333 334 /** 335 * Gets the list of packages that have permissions that specified 336 * {@code autoRevokePermissions=disallowed} in their 337 * {@code application} manifest declaration. 338 * 339 * @return the list of packages for current user 340 * @hide 341 */ 342 @SystemApi 343 @NonNull 344 @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) getAutoRevokeExemptionGrantedPackages()345 public Set<String> getAutoRevokeExemptionGrantedPackages() { 346 try { 347 return CollectionUtils.toSet(mPermissionManager.getAutoRevokeExemptionGrantedPackages( 348 mContext.getUser().getIdentifier())); 349 } catch (RemoteException e) { 350 throw e.rethrowFromSystemServer(); 351 } 352 } 353 splitPermissionInfoListToNonParcelableList( List<SplitPermissionInfoParcelable> parcelableList)354 private List<SplitPermissionInfo> splitPermissionInfoListToNonParcelableList( 355 List<SplitPermissionInfoParcelable> parcelableList) { 356 final int size = parcelableList.size(); 357 List<SplitPermissionInfo> list = new ArrayList<>(size); 358 for (int i = 0; i < size; i++) { 359 list.add(new SplitPermissionInfo(parcelableList.get(i))); 360 } 361 return list; 362 } 363 364 /** 365 * Converts a {@link List} of {@link SplitPermissionInfo} into a List of 366 * {@link SplitPermissionInfoParcelable} and returns it. 367 * @hide 368 */ splitPermissionInfoListToParcelableList( List<SplitPermissionInfo> splitPermissionsList)369 public static List<SplitPermissionInfoParcelable> splitPermissionInfoListToParcelableList( 370 List<SplitPermissionInfo> splitPermissionsList) { 371 final int size = splitPermissionsList.size(); 372 List<SplitPermissionInfoParcelable> outList = new ArrayList<>(size); 373 for (int i = 0; i < size; i++) { 374 SplitPermissionInfo info = splitPermissionsList.get(i); 375 outList.add(new SplitPermissionInfoParcelable( 376 info.getSplitPermission(), info.getNewPermissions(), info.getTargetSdk())); 377 } 378 return outList; 379 } 380 381 /** 382 * A permission that was added in a previous API level might have split into several 383 * permissions. This object describes one such split. 384 */ 385 @Immutable 386 public static final class SplitPermissionInfo { 387 private @NonNull final SplitPermissionInfoParcelable mSplitPermissionInfoParcelable; 388 389 @Override equals(@ullable Object o)390 public boolean equals(@Nullable Object o) { 391 if (this == o) return true; 392 if (o == null || getClass() != o.getClass()) return false; 393 SplitPermissionInfo that = (SplitPermissionInfo) o; 394 return mSplitPermissionInfoParcelable.equals(that.mSplitPermissionInfoParcelable); 395 } 396 397 @Override hashCode()398 public int hashCode() { 399 return mSplitPermissionInfoParcelable.hashCode(); 400 } 401 402 /** 403 * Get the permission that is split. 404 */ getSplitPermission()405 public @NonNull String getSplitPermission() { 406 return mSplitPermissionInfoParcelable.getSplitPermission(); 407 } 408 409 /** 410 * Get the permissions that are added. 411 */ getNewPermissions()412 public @NonNull List<String> getNewPermissions() { 413 return mSplitPermissionInfoParcelable.getNewPermissions(); 414 } 415 416 /** 417 * Get the target API level when the permission was split. 418 */ getTargetSdk()419 public int getTargetSdk() { 420 return mSplitPermissionInfoParcelable.getTargetSdk(); 421 } 422 423 /** 424 * Constructs a split permission. 425 * 426 * @param splitPerm old permission that will be split 427 * @param newPerms list of new permissions that {@code rootPerm} will be split into 428 * @param targetSdk apps targetting SDK versions below this will have {@code rootPerm} 429 * split into {@code newPerms} 430 * @hide 431 */ SplitPermissionInfo(@onNull String splitPerm, @NonNull List<String> newPerms, int targetSdk)432 public SplitPermissionInfo(@NonNull String splitPerm, @NonNull List<String> newPerms, 433 int targetSdk) { 434 this(new SplitPermissionInfoParcelable(splitPerm, newPerms, targetSdk)); 435 } 436 SplitPermissionInfo(@onNull SplitPermissionInfoParcelable parcelable)437 private SplitPermissionInfo(@NonNull SplitPermissionInfoParcelable parcelable) { 438 mSplitPermissionInfoParcelable = parcelable; 439 } 440 } 441 442 /** 443 * Starts a one-time permission session for a given package. A one-time permission session is 444 * ended if app becomes inactive. Inactivity is defined as the package's uid importance level 445 * staying > importanceToResetTimer for timeoutMillis milliseconds. If the package's uid 446 * importance level goes <= importanceToResetTimer then the timer is reset and doesn't start 447 * until going > importanceToResetTimer. 448 * <p> 449 * When this timeoutMillis is reached if the importance level is <= importanceToKeepSessionAlive 450 * then the session is extended until either the importance goes above 451 * importanceToKeepSessionAlive which will end the session or <= importanceToResetTimer which 452 * will continue the session and reset the timer. 453 * </p> 454 * <p> 455 * Importance levels are defined in {@link android.app.ActivityManager.RunningAppProcessInfo}. 456 * </p> 457 * <p> 458 * Once the session ends 459 * {@link PermissionControllerService#onOneTimePermissionSessionTimeout(String)} is invoked. 460 * </p> 461 * <p> 462 * Note that if there is currently an active session for a package a new one isn't created and 463 * the existing one isn't changed. 464 * </p> 465 * @param packageName The package to start a one-time permission session for 466 * @param timeoutMillis Number of milliseconds for an app to be in an inactive state 467 * @param importanceToResetTimer The least important level to uid must be to reset the timer 468 * @param importanceToKeepSessionAlive The least important level the uid must be to keep the 469 * session alive 470 * 471 * @hide 472 */ 473 @SystemApi 474 @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) startOneTimePermissionSession(@onNull String packageName, long timeoutMillis, @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer, @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive)475 public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis, 476 @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer, 477 @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) { 478 try { 479 mPermissionManager.startOneTimePermissionSession(packageName, mContext.getUserId(), 480 timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive); 481 } catch (RemoteException e) { 482 e.rethrowFromSystemServer(); 483 } 484 } 485 486 /** 487 * Stops the one-time permission session for the package. The callback to the end of session is 488 * not invoked. If there is no one-time session for the package then nothing happens. 489 * 490 * @param packageName Package to stop the one-time permission session for 491 * 492 * @hide 493 */ 494 @SystemApi 495 @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) stopOneTimePermissionSession(@onNull String packageName)496 public void stopOneTimePermissionSession(@NonNull String packageName) { 497 try { 498 mPermissionManager.stopOneTimePermissionSession(packageName, 499 mContext.getUserId()); 500 } catch (RemoteException e) { 501 e.rethrowFromSystemServer(); 502 } 503 } 504 505 /** 506 * Checks whether the package with the given pid/uid can read device identifiers. 507 * 508 * @param packageName the name of the package to be checked for identifier access 509 * @param message the message to be used for logging during identifier access 510 * verification 511 * @param callingFeatureId the feature in the package 512 * @param pid the process id of the package to be checked 513 * @param uid the uid of the package to be checked 514 * @return {@link PackageManager#PERMISSION_GRANTED} if the package is allowed identifier 515 * access, {@link PackageManager#PERMISSION_DENIED} otherwise 516 * @hide 517 */ 518 @SystemApi checkDeviceIdentifierAccess(@ullable String packageName, @Nullable String message, @Nullable String callingFeatureId, int pid, int uid)519 public int checkDeviceIdentifierAccess(@Nullable String packageName, @Nullable String message, 520 @Nullable String callingFeatureId, int pid, int uid) { 521 try { 522 return mPermissionManager.checkDeviceIdentifierAccess(packageName, message, 523 callingFeatureId, pid, uid); 524 } catch (RemoteException e) { 525 throw e.rethrowFromSystemServer(); 526 } 527 } 528 529 /* @hide */ checkPermissionUncached(@ullable String permission, int pid, int uid)530 private static int checkPermissionUncached(@Nullable String permission, int pid, int uid) { 531 final IActivityManager am = ActivityManager.getService(); 532 if (am == null) { 533 // Well this is super awkward; we somehow don't have an active ActivityManager 534 // instance. If we're testing a root or system UID, then they totally have whatever 535 // permission this is. 536 final int appId = UserHandle.getAppId(uid); 537 if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) { 538 Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission); 539 return PackageManager.PERMISSION_GRANTED; 540 } 541 Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold " 542 + permission); 543 return PackageManager.PERMISSION_DENIED; 544 } 545 try { 546 return am.checkPermission(permission, pid, uid); 547 } catch (RemoteException e) { 548 throw e.rethrowFromSystemServer(); 549 } 550 } 551 552 /** 553 * Identifies a permission query. 554 * 555 * N.B. we include the checking pid for tracking purposes but don't include it in the equality 556 * comparison: we use only uid for the actual security check, so comparing pid would result 557 * in spurious misses. 558 * 559 * @hide 560 */ 561 @Immutable 562 private static final class PermissionQuery { 563 final String permission; 564 final int pid; 565 final int uid; 566 PermissionQuery(@ullable String permission, int pid, int uid)567 PermissionQuery(@Nullable String permission, int pid, int uid) { 568 this.permission = permission; 569 this.pid = pid; 570 this.uid = uid; 571 } 572 573 @Override toString()574 public String toString() { 575 return String.format("PermissionQuery(permission=\"%s\", pid=%s, uid=%s)", 576 permission, pid, uid); 577 } 578 579 @Override hashCode()580 public int hashCode() { 581 // N.B. pid doesn't count toward equality and therefore shouldn't count for 582 // hashing either. 583 int hash = Objects.hashCode(permission); 584 hash = hash * 13 + Objects.hashCode(uid); 585 return hash; 586 } 587 588 @Override equals(Object rval)589 public boolean equals(Object rval) { 590 // N.B. pid doesn't count toward equality! 591 if (rval == null) { 592 return false; 593 } 594 PermissionQuery other; 595 try { 596 other = (PermissionQuery) rval; 597 } catch (ClassCastException ex) { 598 return false; 599 } 600 return uid == other.uid 601 && Objects.equals(permission, other.permission); 602 } 603 } 604 605 /** @hide */ 606 public static final String CACHE_KEY_PACKAGE_INFO = "cache_key.package_info"; 607 608 /** @hide */ 609 private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache = 610 new PropertyInvalidatedCache<PermissionQuery, Integer>( 611 16, CACHE_KEY_PACKAGE_INFO) { 612 @Override 613 protected Integer recompute(PermissionQuery query) { 614 return checkPermissionUncached(query.permission, query.pid, query.uid); 615 } 616 }; 617 618 /** @hide */ checkPermission(@ullable String permission, int pid, int uid)619 public static int checkPermission(@Nullable String permission, int pid, int uid) { 620 return sPermissionCache.query(new PermissionQuery(permission, pid, uid)); 621 } 622 623 /** 624 * Make checkPermission() above bypass the permission cache in this process. 625 * 626 * @hide 627 */ disablePermissionCache()628 public static void disablePermissionCache() { 629 sPermissionCache.disableLocal(); 630 } 631 632 /** 633 * Like PermissionQuery, but for permission checks based on a package name instead of 634 * a UID. 635 */ 636 @Immutable 637 private static final class PackageNamePermissionQuery { 638 final String permName; 639 final String pkgName; 640 final int uid; 641 PackageNamePermissionQuery(@ullable String permName, @Nullable String pkgName, int uid)642 PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName, int uid) { 643 this.permName = permName; 644 this.pkgName = pkgName; 645 this.uid = uid; 646 } 647 648 @Override toString()649 public String toString() { 650 return String.format( 651 "PackageNamePermissionQuery(pkgName=\"%s\", permName=\"%s, uid=%s\")", 652 pkgName, permName, uid); 653 } 654 655 @Override hashCode()656 public int hashCode() { 657 return Objects.hash(permName, pkgName, uid); 658 } 659 660 @Override equals(Object rval)661 public boolean equals(Object rval) { 662 if (rval == null) { 663 return false; 664 } 665 PackageNamePermissionQuery other; 666 try { 667 other = (PackageNamePermissionQuery) rval; 668 } catch (ClassCastException ex) { 669 return false; 670 } 671 return Objects.equals(permName, other.permName) 672 && Objects.equals(pkgName, other.pkgName) 673 && uid == other.uid; 674 } 675 } 676 677 /* @hide */ checkPackageNamePermissionUncached( String permName, String pkgName, int uid)678 private static int checkPackageNamePermissionUncached( 679 String permName, String pkgName, int uid) { 680 try { 681 return ActivityThread.getPermissionManager().checkPermission( 682 permName, pkgName, uid); 683 } catch (RemoteException e) { 684 throw e.rethrowFromSystemServer(); 685 } 686 } 687 688 /* @hide */ 689 private static PropertyInvalidatedCache<PackageNamePermissionQuery, Integer> 690 sPackageNamePermissionCache = 691 new PropertyInvalidatedCache<PackageNamePermissionQuery, Integer>( 692 16, CACHE_KEY_PACKAGE_INFO) { 693 @Override 694 protected Integer recompute(PackageNamePermissionQuery query) { 695 return checkPackageNamePermissionUncached( 696 query.permName, query.pkgName, query.uid); 697 } 698 }; 699 700 /** 701 * Check whether a package has a permission. 702 * 703 * @hide 704 */ checkPackageNamePermission(String permName, String pkgName, int uid)705 public static int checkPackageNamePermission(String permName, String pkgName, int uid) { 706 return sPackageNamePermissionCache.query( 707 new PackageNamePermissionQuery(permName, pkgName, uid)); 708 } 709 710 /** 711 * Make checkPackageNamePermission() bypass the cache in this process. 712 * 713 * @hide 714 */ disablePackageNamePermissionCache()715 public static void disablePackageNamePermissionCache() { 716 sPackageNamePermissionCache.disableLocal(); 717 } 718 719 } 720