1 /* 2 * Copyright (C) 2016 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 static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT; 20 import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED; 21 import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED; 22 import static android.permission.PermissionControllerService.SERVICE_INTERFACE; 23 24 import static com.android.internal.util.Preconditions.checkArgument; 25 import static com.android.internal.util.Preconditions.checkArgumentNonnegative; 26 import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull; 27 import static com.android.internal.util.Preconditions.checkFlagsArgument; 28 import static com.android.internal.util.Preconditions.checkNotNull; 29 import static com.android.internal.util.Preconditions.checkStringNotEmpty; 30 31 import android.Manifest; 32 import android.annotation.CallbackExecutor; 33 import android.annotation.IntDef; 34 import android.annotation.NonNull; 35 import android.annotation.Nullable; 36 import android.annotation.RequiresPermission; 37 import android.annotation.SystemApi; 38 import android.annotation.SystemService; 39 import android.annotation.TestApi; 40 import android.app.ActivityThread; 41 import android.app.admin.DevicePolicyManager.PermissionGrantState; 42 import android.content.Context; 43 import android.content.Intent; 44 import android.content.pm.PackageManager; 45 import android.content.pm.ResolveInfo; 46 import android.os.Binder; 47 import android.os.Bundle; 48 import android.os.Handler; 49 import android.os.Process; 50 import android.os.UserHandle; 51 import android.util.ArrayMap; 52 import android.util.Log; 53 import android.util.Pair; 54 55 import com.android.internal.annotations.GuardedBy; 56 import com.android.internal.infra.AndroidFuture; 57 import com.android.internal.infra.RemoteStream; 58 import com.android.internal.infra.ServiceConnector; 59 import com.android.internal.util.CollectionUtils; 60 61 import libcore.util.EmptyArray; 62 63 import java.io.FileDescriptor; 64 import java.lang.annotation.Retention; 65 import java.lang.annotation.RetentionPolicy; 66 import java.util.ArrayList; 67 import java.util.Arrays; 68 import java.util.Collections; 69 import java.util.List; 70 import java.util.Map; 71 import java.util.concurrent.Executor; 72 import java.util.concurrent.TimeUnit; 73 import java.util.function.Consumer; 74 75 /** 76 * Interface for communicating with the permission controller. 77 * 78 * @hide 79 */ 80 @TestApi 81 @SystemApi 82 @SystemService(Context.PERMISSION_CONTROLLER_SERVICE) 83 public final class PermissionControllerManager { 84 private static final String TAG = PermissionControllerManager.class.getSimpleName(); 85 86 private static final long REQUEST_TIMEOUT_MILLIS = 60000; 87 private static final long UNBIND_TIMEOUT_MILLIS = 10000; 88 private static final int CHUNK_SIZE = 4 * 1024; 89 90 private static final Object sLock = new Object(); 91 92 /** 93 * Global remote services (per user) used by all {@link PermissionControllerManager managers} 94 */ 95 @GuardedBy("sLock") 96 private static ArrayMap<Pair<Integer, Thread>, ServiceConnector<IPermissionController>> 97 sRemoteServices = new ArrayMap<>(1); 98 99 /** @hide */ 100 @IntDef(prefix = { "REASON_" }, value = { 101 REASON_MALWARE, 102 REASON_INSTALLER_POLICY_VIOLATION, 103 }) 104 @Retention(RetentionPolicy.SOURCE) 105 public @interface Reason {} 106 107 /** The permissions are revoked because the apps holding the permissions are malware */ 108 public static final int REASON_MALWARE = 1; 109 110 /** 111 * The permissions are revoked because the apps holding the permissions violate a policy of the 112 * app that installed it. 113 * 114 * <p>If this reason is used only permissions of apps that are installed by the caller of the 115 * API can be revoked. 116 */ 117 public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; 118 119 /** @hide */ 120 @IntDef(prefix = { "COUNT_" }, value = { 121 COUNT_ONLY_WHEN_GRANTED, 122 COUNT_WHEN_SYSTEM, 123 }, flag = true) 124 @Retention(RetentionPolicy.SOURCE) 125 public @interface CountPermissionAppsFlag {} 126 127 /** Count an app only if the permission is granted to the app. */ 128 public static final int COUNT_ONLY_WHEN_GRANTED = 1; 129 130 /** Count and app even if it is a system app. */ 131 public static final int COUNT_WHEN_SYSTEM = 2; 132 133 /** 134 * Callback for delivering the result of {@link #revokeRuntimePermissions}. 135 */ 136 public abstract static class OnRevokeRuntimePermissionsCallback { 137 /** 138 * The result for {@link #revokeRuntimePermissions}. 139 * 140 * @param revoked The actually revoked permissions as 141 * {@code Map<packageName, List<permission>>} 142 */ onRevokeRuntimePermissions(@onNull Map<String, List<String>> revoked)143 public abstract void onRevokeRuntimePermissions(@NonNull Map<String, List<String>> revoked); 144 } 145 146 /** 147 * Callback for delivering the result of {@link #getAppPermissions}. 148 * 149 * @hide 150 */ 151 @TestApi 152 public interface OnGetAppPermissionResultCallback { 153 /** 154 * The result for {@link #getAppPermissions(String, OnGetAppPermissionResultCallback, 155 * Handler)}. 156 * 157 * @param permissions The permissions list. 158 */ onGetAppPermissions(@onNull List<RuntimePermissionPresentationInfo> permissions)159 void onGetAppPermissions(@NonNull List<RuntimePermissionPresentationInfo> permissions); 160 } 161 162 /** 163 * Callback for delivering the result of {@link #countPermissionApps}. 164 * 165 * @hide 166 */ 167 @TestApi 168 public interface OnCountPermissionAppsResultCallback { 169 /** 170 * The result for {@link #countPermissionApps(List, int, 171 * OnCountPermissionAppsResultCallback, Handler)}. 172 * 173 * @param numApps The number of apps that have one of the permissions 174 */ onCountPermissionApps(int numApps)175 void onCountPermissionApps(int numApps); 176 } 177 178 /** 179 * Callback for delivering the result of {@link #getPermissionUsages}. 180 * 181 * @hide 182 */ 183 public interface OnPermissionUsageResultCallback { 184 /** 185 * The result for {@link #getPermissionUsages}. 186 * 187 * @param users The users list. 188 */ onPermissionUsageResult(@onNull List<RuntimePermissionUsageInfo> users)189 void onPermissionUsageResult(@NonNull List<RuntimePermissionUsageInfo> users); 190 } 191 192 private final @NonNull Context mContext; 193 private final @NonNull ServiceConnector<IPermissionController> mRemoteService; 194 private final @NonNull Handler mHandler; 195 196 /** 197 * Create a new {@link PermissionControllerManager}. 198 * 199 * @param context to create the manager for 200 * @param handler handler to schedule work 201 * 202 * @hide 203 */ PermissionControllerManager(@onNull Context context, @NonNull Handler handler)204 public PermissionControllerManager(@NonNull Context context, @NonNull Handler handler) { 205 synchronized (sLock) { 206 Pair<Integer, Thread> key = new Pair<>(context.getUserId(), 207 handler.getLooper().getThread()); 208 ServiceConnector<IPermissionController> remoteService = sRemoteServices.get(key); 209 if (remoteService == null) { 210 Intent intent = new Intent(SERVICE_INTERFACE); 211 intent.setPackage(context.getPackageManager().getPermissionControllerPackageName()); 212 ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0); 213 remoteService = new ServiceConnector.Impl<IPermissionController>( 214 ActivityThread.currentApplication() /* context */, 215 new Intent(SERVICE_INTERFACE) 216 .setComponent(serviceInfo.getComponentInfo().getComponentName()), 217 0 /* bindingFlags */, context.getUserId(), 218 IPermissionController.Stub::asInterface) { 219 220 @Override 221 protected Handler getJobHandler() { 222 return handler; 223 } 224 225 @Override 226 protected long getRequestTimeoutMs() { 227 return REQUEST_TIMEOUT_MILLIS; 228 } 229 230 @Override 231 protected long getAutoDisconnectTimeoutMs() { 232 return UNBIND_TIMEOUT_MILLIS; 233 } 234 }; 235 sRemoteServices.put(key, remoteService); 236 } 237 238 mRemoteService = remoteService; 239 } 240 241 mContext = context; 242 mHandler = handler; 243 } 244 245 /** 246 * Throw a {@link SecurityException} if not at least one of the permissions is granted. 247 * 248 * @param requiredPermissions A list of permissions. Any of of them if sufficient to pass the 249 * check 250 */ enforceSomePermissionsGrantedToSelf(@onNull String... requiredPermissions)251 private void enforceSomePermissionsGrantedToSelf(@NonNull String... requiredPermissions) { 252 for (String requiredPermission : requiredPermissions) { 253 if (mContext.checkSelfPermission(requiredPermission) 254 == PackageManager.PERMISSION_GRANTED) { 255 return; 256 } 257 } 258 259 throw new SecurityException("At lest one of the following permissions is required: " 260 + Arrays.toString(requiredPermissions)); 261 } 262 263 /** 264 * Revoke a set of runtime permissions for various apps. 265 * 266 * @param request The permissions to revoke as {@code Map<packageName, List<permission>>} 267 * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them 268 * @param reason Why the permission should be revoked 269 * @param executor Executor on which to invoke the callback 270 * @param callback Callback to receive the result 271 */ 272 @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) revokeRuntimePermissions(@onNull Map<String, List<String>> request, boolean doDryRun, @Reason int reason, @NonNull @CallbackExecutor Executor executor, @NonNull OnRevokeRuntimePermissionsCallback callback)273 public void revokeRuntimePermissions(@NonNull Map<String, List<String>> request, 274 boolean doDryRun, @Reason int reason, @NonNull @CallbackExecutor Executor executor, 275 @NonNull OnRevokeRuntimePermissionsCallback callback) { 276 // Check input to fail immediately instead of inside the async request 277 checkNotNull(executor); 278 checkNotNull(callback); 279 checkNotNull(request); 280 for (Map.Entry<String, List<String>> appRequest : request.entrySet()) { 281 checkNotNull(appRequest.getKey()); 282 checkCollectionElementsNotNull(appRequest.getValue(), "permissions"); 283 } 284 285 // Check required permission to fail immediately instead of inside the oneway binder call 286 enforceSomePermissionsGrantedToSelf(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS); 287 288 mRemoteService.postAsync(service -> { 289 Bundle bundledizedRequest = new Bundle(); 290 for (Map.Entry<String, List<String>> appRequest : request.entrySet()) { 291 bundledizedRequest.putStringArrayList(appRequest.getKey(), 292 new ArrayList<>(appRequest.getValue())); 293 } 294 295 AndroidFuture<Map<String, List<String>>> revokeRuntimePermissionsResult = 296 new AndroidFuture<>(); 297 service.revokeRuntimePermissions(bundledizedRequest, doDryRun, reason, 298 mContext.getPackageName(), 299 revokeRuntimePermissionsResult); 300 return revokeRuntimePermissionsResult; 301 }).whenCompleteAsync((revoked, err) -> { 302 long token = Binder.clearCallingIdentity(); 303 try { 304 if (err != null) { 305 Log.e(TAG, "Failure when revoking runtime permissions " + revoked, err); 306 callback.onRevokeRuntimePermissions(Collections.emptyMap()); 307 } else { 308 callback.onRevokeRuntimePermissions(revoked); 309 } 310 } finally { 311 Binder.restoreCallingIdentity(token); 312 } 313 }, executor); 314 } 315 316 /** 317 * Set the runtime permission state from a device admin. 318 * 319 * @param callerPackageName The package name of the admin requesting the change 320 * @param packageName Package the permission belongs to 321 * @param permission Permission to change 322 * @param grantState State to set the permission into 323 * @param executor Executor to run the {@code callback} on 324 * @param callback The callback 325 * 326 * @hide 327 */ 328 @RequiresPermission(allOf = {Manifest.permission.GRANT_RUNTIME_PERMISSIONS, 329 Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, 330 Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY}, 331 conditional = true) setRuntimePermissionGrantStateByDeviceAdmin(@onNull String callerPackageName, @NonNull String packageName, @NonNull String permission, @PermissionGrantState int grantState, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)332 public void setRuntimePermissionGrantStateByDeviceAdmin(@NonNull String callerPackageName, 333 @NonNull String packageName, @NonNull String permission, 334 @PermissionGrantState int grantState, @NonNull @CallbackExecutor Executor executor, 335 @NonNull Consumer<Boolean> callback) { 336 checkStringNotEmpty(callerPackageName); 337 checkStringNotEmpty(packageName); 338 checkStringNotEmpty(permission); 339 checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED 340 || grantState == PERMISSION_GRANT_STATE_DENIED 341 || grantState == PERMISSION_GRANT_STATE_DEFAULT); 342 checkNotNull(executor); 343 checkNotNull(callback); 344 345 mRemoteService.postAsync(service -> { 346 AndroidFuture<Boolean> setRuntimePermissionGrantStateResult = new AndroidFuture<>(); 347 service.setRuntimePermissionGrantStateByDeviceAdmin( 348 callerPackageName, packageName, permission, grantState, 349 setRuntimePermissionGrantStateResult); 350 return setRuntimePermissionGrantStateResult; 351 }).whenCompleteAsync((setRuntimePermissionGrantStateResult, err) -> { 352 long token = Binder.clearCallingIdentity(); 353 try { 354 if (err != null) { 355 Log.e(TAG, "Error setting permissions state for device admin " + packageName, 356 err); 357 callback.accept(false); 358 } else { 359 callback.accept(Boolean.TRUE.equals(setRuntimePermissionGrantStateResult)); 360 } 361 } finally { 362 Binder.restoreCallingIdentity(token); 363 } 364 }, executor); 365 } 366 367 /** 368 * Create a backup of the runtime permissions. 369 * 370 * @param user The user to be backed up 371 * @param executor Executor on which to invoke the callback 372 * @param callback Callback to receive the result. The resulting backup-file is opaque and no 373 * guarantees are made other than that the file can be send to 374 * {@link #restoreRuntimePermissionBackup} in this and future versions of 375 * Android. 376 */ 377 @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) getRuntimePermissionBackup(@onNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<byte[]> callback)378 public void getRuntimePermissionBackup(@NonNull UserHandle user, 379 @NonNull @CallbackExecutor Executor executor, 380 @NonNull Consumer<byte[]> callback) { 381 checkNotNull(user); 382 checkNotNull(executor); 383 checkNotNull(callback); 384 385 // Check required permission to fail immediately instead of inside the oneway binder call 386 enforceSomePermissionsGrantedToSelf(Manifest.permission.GET_RUNTIME_PERMISSIONS); 387 388 mRemoteService.postAsync(service -> RemoteStream.receiveBytes(remotePipe -> { 389 service.getRuntimePermissionBackup(user, remotePipe); 390 })).whenCompleteAsync((bytes, err) -> { 391 if (err != null) { 392 Log.e(TAG, "Error getting permission backup", err); 393 callback.accept(EmptyArray.BYTE); 394 } else { 395 callback.accept(bytes); 396 } 397 }, executor); 398 } 399 400 /** 401 * Restore a {@link #getRuntimePermissionBackup backup-file} of the runtime permissions. 402 * 403 * <p>This might leave some part of the backup-file unapplied if an package mentioned in the 404 * backup-file is not yet installed. It is required that 405 * {@link #applyStagedRuntimePermissionBackup} is called after any package is installed to 406 * apply the rest of the backup-file. 407 * 408 * @param backup the backup-file to restore. The backup is sent asynchronously, hence it should 409 * not be modified after calling this method. 410 * @param user The user to be restore 411 */ 412 @RequiresPermission(anyOf = { 413 Manifest.permission.GRANT_RUNTIME_PERMISSIONS, 414 Manifest.permission.RESTORE_RUNTIME_PERMISSIONS 415 }) stageAndApplyRuntimePermissionsBackup(@onNull byte[] backup, @NonNull UserHandle user)416 public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[] backup, 417 @NonNull UserHandle user) { 418 checkNotNull(backup); 419 checkNotNull(user); 420 421 // Check required permission to fail immediately instead of inside the oneway binder call 422 enforceSomePermissionsGrantedToSelf(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, 423 Manifest.permission.RESTORE_RUNTIME_PERMISSIONS); 424 425 mRemoteService.postAsync(service -> RemoteStream.sendBytes(remotePipe -> { 426 service.stageAndApplyRuntimePermissionsBackup(user, remotePipe); 427 }, backup)) 428 .whenComplete((nullResult, err) -> { 429 if (err != null) { 430 Log.e(TAG, "Error sending permission backup", err); 431 } 432 }); 433 } 434 435 /** 436 * Restore unapplied parts of a {@link #stageAndApplyRuntimePermissionsBackup previously staged} 437 * backup-file of the runtime permissions. 438 * 439 * <p>This should be called every time after a package is installed until the callback 440 * reports that there is no more unapplied backup left. 441 * 442 * @param packageName The package that is ready to have it's permissions restored. 443 * @param user The user the package belongs to 444 * @param executor Executor to execute the callback on 445 * @param callback Is called with {@code true} iff there is still more unapplied backup left 446 */ 447 @RequiresPermission(anyOf = { 448 Manifest.permission.GRANT_RUNTIME_PERMISSIONS, 449 Manifest.permission.RESTORE_RUNTIME_PERMISSIONS 450 }) applyStagedRuntimePermissionBackup(@onNull String packageName, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)451 public void applyStagedRuntimePermissionBackup(@NonNull String packageName, 452 @NonNull UserHandle user, 453 @NonNull @CallbackExecutor Executor executor, 454 @NonNull Consumer<Boolean> callback) { 455 checkNotNull(packageName); 456 checkNotNull(user); 457 checkNotNull(executor); 458 checkNotNull(callback); 459 460 // Check required permission to fail immediately instead of inside the oneway binder call 461 enforceSomePermissionsGrantedToSelf(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, 462 Manifest.permission.RESTORE_RUNTIME_PERMISSIONS); 463 464 mRemoteService.postAsync(service -> { 465 AndroidFuture<Boolean> applyStagedRuntimePermissionBackupResult = 466 new AndroidFuture<>(); 467 service.applyStagedRuntimePermissionBackup(packageName, user, 468 applyStagedRuntimePermissionBackupResult); 469 return applyStagedRuntimePermissionBackupResult; 470 }).whenCompleteAsync((applyStagedRuntimePermissionBackupResult, err) -> { 471 long token = Binder.clearCallingIdentity(); 472 try { 473 if (err != null) { 474 Log.e(TAG, "Error restoring delayed permissions for " + packageName, err); 475 callback.accept(true); 476 } else { 477 callback.accept( 478 Boolean.TRUE.equals(applyStagedRuntimePermissionBackupResult)); 479 } 480 } finally { 481 Binder.restoreCallingIdentity(token); 482 } 483 }, executor); 484 } 485 486 /** 487 * Dump permission controller state. 488 * 489 * @hide 490 */ dump(@onNull FileDescriptor fd, @Nullable String[] args)491 public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) { 492 try { 493 mRemoteService.post(service -> service.asBinder().dump(fd, args)) 494 .get(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 495 } catch (Exception e) { 496 Log.e(TAG, "Could not get dump", e); 497 } 498 } 499 500 /** 501 * Gets the runtime permissions for an app. 502 * 503 * @param packageName The package for which to query. 504 * @param callback Callback to receive the result. 505 * @param handler Handler on which to invoke the callback. 506 * 507 * @hide 508 */ 509 @TestApi 510 @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) getAppPermissions(@onNull String packageName, @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler)511 public void getAppPermissions(@NonNull String packageName, 512 @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) { 513 checkNotNull(packageName); 514 checkNotNull(callback); 515 Handler finalHandler = handler != null ? handler : mHandler; 516 517 mRemoteService.postAsync(service -> { 518 AndroidFuture<List<RuntimePermissionPresentationInfo>> getAppPermissionsResult = 519 new AndroidFuture<>(); 520 service.getAppPermissions(packageName, getAppPermissionsResult); 521 return getAppPermissionsResult; 522 }).whenComplete((getAppPermissionsResult, err) -> finalHandler.post(() -> { 523 if (err != null) { 524 Log.e(TAG, "Error getting app permission", err); 525 callback.onGetAppPermissions(Collections.emptyList()); 526 } else { 527 callback.onGetAppPermissions(CollectionUtils.emptyIfNull(getAppPermissionsResult)); 528 } 529 })); 530 } 531 532 /** 533 * Revoke the permission {@code permissionName} for app {@code packageName} 534 * 535 * @param packageName The package for which to revoke 536 * @param permissionName The permission to revoke 537 * 538 * @hide 539 */ 540 @TestApi 541 @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) revokeRuntimePermission(@onNull String packageName, @NonNull String permissionName)542 public void revokeRuntimePermission(@NonNull String packageName, 543 @NonNull String permissionName) { 544 checkNotNull(packageName); 545 checkNotNull(permissionName); 546 547 mRemoteService.run(service -> service.revokeRuntimePermission(packageName, permissionName)); 548 } 549 550 /** 551 * Count how many apps have one of a set of permissions. 552 * 553 * @param permissionNames The permissions the app might have 554 * @param flags Modify which apps to count. By default all non-system apps that request a 555 * permission are counted 556 * @param callback Callback to receive the result 557 * @param handler Handler on which to invoke the callback 558 * 559 * @hide 560 */ 561 @TestApi 562 @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) countPermissionApps(@onNull List<String> permissionNames, @CountPermissionAppsFlag int flags, @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler)563 public void countPermissionApps(@NonNull List<String> permissionNames, 564 @CountPermissionAppsFlag int flags, 565 @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler) { 566 checkCollectionElementsNotNull(permissionNames, "permissionNames"); 567 checkFlagsArgument(flags, COUNT_WHEN_SYSTEM | COUNT_ONLY_WHEN_GRANTED); 568 checkNotNull(callback); 569 Handler finalHandler = handler != null ? handler : mHandler; 570 571 mRemoteService.postAsync(service -> { 572 AndroidFuture<Integer> countPermissionAppsResult = new AndroidFuture<>(); 573 service.countPermissionApps(permissionNames, flags, countPermissionAppsResult); 574 return countPermissionAppsResult; 575 }).whenComplete((countPermissionAppsResult, err) -> finalHandler.post(() -> { 576 if (err != null) { 577 Log.e(TAG, "Error counting permission apps", err); 578 callback.onCountPermissionApps(0); 579 } else { 580 callback.onCountPermissionApps(countPermissionAppsResult); 581 } 582 })); 583 } 584 585 /** 586 * Count how many apps have used permissions. 587 * 588 * @param countSystem Also count system apps 589 * @param numMillis The number of milliseconds in the past to check for uses 590 * @param executor Executor on which to invoke the callback 591 * @param callback Callback to receive the result 592 * 593 * @hide 594 */ 595 @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) getPermissionUsages(boolean countSystem, long numMillis, @NonNull @CallbackExecutor Executor executor, @NonNull OnPermissionUsageResultCallback callback)596 public void getPermissionUsages(boolean countSystem, long numMillis, 597 @NonNull @CallbackExecutor Executor executor, 598 @NonNull OnPermissionUsageResultCallback callback) { 599 checkArgumentNonnegative(numMillis); 600 checkNotNull(executor); 601 checkNotNull(callback); 602 603 604 mRemoteService.postAsync(service -> { 605 AndroidFuture<List<RuntimePermissionUsageInfo>> getPermissionUsagesResult = 606 new AndroidFuture<>(); 607 service.getPermissionUsages(countSystem, numMillis, getPermissionUsagesResult); 608 return getPermissionUsagesResult; 609 }).whenCompleteAsync((getPermissionUsagesResult, err) -> { 610 if (err != null) { 611 Log.e(TAG, "Error getting permission usages", err); 612 callback.onPermissionUsageResult(Collections.emptyList()); 613 } else { 614 long token = Binder.clearCallingIdentity(); 615 try { 616 callback.onPermissionUsageResult( 617 CollectionUtils.emptyIfNull(getPermissionUsagesResult)); 618 } finally { 619 Binder.restoreCallingIdentity(token); 620 } 621 } 622 }, executor); 623 } 624 625 /** 626 * Grant or upgrade runtime permissions. The upgrade could be performed 627 * based on whether the device upgraded, whether the permission database 628 * version is old, or because the permission policy changed. 629 * 630 * @param executor Executor on which to invoke the callback 631 * @param callback Callback to receive the result 632 * 633 * @hide 634 */ 635 @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) grantOrUpgradeDefaultRuntimePermissions( @onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)636 public void grantOrUpgradeDefaultRuntimePermissions( 637 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 638 mRemoteService.postAsync(service -> { 639 AndroidFuture<Boolean> grantOrUpgradeDefaultRuntimePermissionsResult = 640 new AndroidFuture<>(); 641 service.grantOrUpgradeDefaultRuntimePermissions( 642 grantOrUpgradeDefaultRuntimePermissionsResult); 643 return grantOrUpgradeDefaultRuntimePermissionsResult; 644 }).whenCompleteAsync((grantOrUpgradeDefaultRuntimePermissionsResult, err) -> { 645 if (err != null) { 646 Log.e(TAG, "Error granting or upgrading runtime permissions", err); 647 callback.accept(false); 648 } else { 649 callback.accept(Boolean.TRUE.equals(grantOrUpgradeDefaultRuntimePermissionsResult)); 650 } 651 }, executor); 652 } 653 654 /** 655 * @see PermissionControllerManager#updateUserSensitiveForApp 656 * @hide 657 */ updateUserSensitive()658 public void updateUserSensitive() { 659 updateUserSensitiveForApp(Process.INVALID_UID); 660 } 661 662 /** 663 * @see PermissionControllerService#onUpdateUserSensitiveForApp 664 * @hide 665 */ updateUserSensitiveForApp(int uid)666 public void updateUserSensitiveForApp(int uid) { 667 mRemoteService.postAsync(service -> { 668 AndroidFuture<Void> future = new AndroidFuture<>(); 669 service.updateUserSensitiveForApp(uid, future); 670 return future; 671 }).whenComplete((res, err) -> { 672 if (err != null) { 673 Log.e(TAG, "Error updating user_sensitive flags for uid " + uid, err); 674 } 675 }); 676 } 677 678 /** 679 * Called when a package that has permissions registered as "one-time" is considered 680 * inactive. 681 * 682 * @param packageName The package which became inactive 683 * 684 * @hide 685 */ 686 @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) notifyOneTimePermissionSessionTimeout(@onNull String packageName)687 public void notifyOneTimePermissionSessionTimeout(@NonNull String packageName) { 688 mRemoteService.run( 689 service -> service.notifyOneTimePermissionSessionTimeout(packageName)); 690 } 691 } 692