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 static java.lang.Math.min; 32 33 import android.Manifest; 34 import android.annotation.CallbackExecutor; 35 import android.annotation.IntDef; 36 import android.annotation.NonNull; 37 import android.annotation.Nullable; 38 import android.annotation.RequiresPermission; 39 import android.annotation.SystemApi; 40 import android.annotation.SystemService; 41 import android.annotation.TestApi; 42 import android.app.ActivityThread; 43 import android.app.admin.DevicePolicyManager.PermissionGrantState; 44 import android.content.ComponentName; 45 import android.content.Context; 46 import android.content.Intent; 47 import android.content.pm.PackageManager; 48 import android.content.pm.ResolveInfo; 49 import android.os.AsyncTask; 50 import android.os.Binder; 51 import android.os.Bundle; 52 import android.os.Handler; 53 import android.os.IBinder; 54 import android.os.ParcelFileDescriptor; 55 import android.os.RemoteCallback; 56 import android.os.RemoteException; 57 import android.os.UserHandle; 58 import android.util.ArrayMap; 59 import android.util.Log; 60 import android.util.Pair; 61 62 import com.android.internal.annotations.GuardedBy; 63 import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; 64 import com.android.internal.infra.AbstractRemoteService; 65 import com.android.internal.util.Preconditions; 66 67 import libcore.io.IoUtils; 68 69 import java.io.ByteArrayOutputStream; 70 import java.io.IOException; 71 import java.io.InputStream; 72 import java.io.OutputStream; 73 import java.lang.annotation.Retention; 74 import java.lang.annotation.RetentionPolicy; 75 import java.util.ArrayList; 76 import java.util.Collections; 77 import java.util.List; 78 import java.util.Map; 79 import java.util.concurrent.Executor; 80 import java.util.function.Consumer; 81 82 /** 83 * Interface for communicating with the permission controller. 84 * 85 * @hide 86 */ 87 @TestApi 88 @SystemApi 89 @SystemService(Context.PERMISSION_CONTROLLER_SERVICE) 90 public final class PermissionControllerManager { 91 private static final String TAG = PermissionControllerManager.class.getSimpleName(); 92 93 private static final Object sLock = new Object(); 94 95 /** 96 * Global remote services (per user) used by all {@link PermissionControllerManager managers} 97 */ 98 @GuardedBy("sLock") 99 private static ArrayMap<Pair<Integer, Thread>, RemoteService> sRemoteServices 100 = new ArrayMap<>(1); 101 102 /** 103 * The key for retrieving the result from the returned bundle. 104 * 105 * @hide 106 */ 107 public static final String KEY_RESULT = 108 "android.permission.PermissionControllerManager.key.result"; 109 110 /** @hide */ 111 @IntDef(prefix = { "REASON_" }, value = { 112 REASON_MALWARE, 113 REASON_INSTALLER_POLICY_VIOLATION, 114 }) 115 @Retention(RetentionPolicy.SOURCE) 116 public @interface Reason {} 117 118 /** The permissions are revoked because the apps holding the permissions are malware */ 119 public static final int REASON_MALWARE = 1; 120 121 /** 122 * The permissions are revoked because the apps holding the permissions violate a policy of the 123 * app that installed it. 124 * 125 * <p>If this reason is used only permissions of apps that are installed by the caller of the 126 * API can be revoked. 127 */ 128 public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; 129 130 /** @hide */ 131 @IntDef(prefix = { "COUNT_" }, value = { 132 COUNT_ONLY_WHEN_GRANTED, 133 COUNT_WHEN_SYSTEM, 134 }, flag = true) 135 @Retention(RetentionPolicy.SOURCE) 136 public @interface CountPermissionAppsFlag {} 137 138 /** Count an app only if the permission is granted to the app. */ 139 public static final int COUNT_ONLY_WHEN_GRANTED = 1; 140 141 /** Count and app even if it is a system app. */ 142 public static final int COUNT_WHEN_SYSTEM = 2; 143 144 /** 145 * Callback for delivering the result of {@link #revokeRuntimePermissions}. 146 */ 147 public abstract static class OnRevokeRuntimePermissionsCallback { 148 /** 149 * The result for {@link #revokeRuntimePermissions}. 150 * 151 * @param revoked The actually revoked permissions as 152 * {@code Map<packageName, List<permission>>} 153 */ onRevokeRuntimePermissions(@onNull Map<String, List<String>> revoked)154 public abstract void onRevokeRuntimePermissions(@NonNull Map<String, List<String>> revoked); 155 } 156 157 /** 158 * Callback for delivering the result of {@link #getRuntimePermissionBackup}. 159 * 160 * @hide 161 */ 162 public interface OnGetRuntimePermissionBackupCallback { 163 /** 164 * The result for {@link #getRuntimePermissionBackup}. 165 * 166 * @param backup The backup file 167 */ onGetRuntimePermissionsBackup(@onNull byte[] backup)168 void onGetRuntimePermissionsBackup(@NonNull byte[] backup); 169 } 170 171 /** 172 * Callback for delivering the result of {@link #getAppPermissions}. 173 * 174 * @hide 175 */ 176 @TestApi 177 public interface OnGetAppPermissionResultCallback { 178 /** 179 * The result for {@link #getAppPermissions(String, OnGetAppPermissionResultCallback, 180 * Handler)}. 181 * 182 * @param permissions The permissions list. 183 */ onGetAppPermissions(@onNull List<RuntimePermissionPresentationInfo> permissions)184 void onGetAppPermissions(@NonNull List<RuntimePermissionPresentationInfo> permissions); 185 } 186 187 /** 188 * Callback for delivering the result of {@link #countPermissionApps}. 189 * 190 * @hide 191 */ 192 public interface OnCountPermissionAppsResultCallback { 193 /** 194 * The result for {@link #countPermissionApps(List, int, 195 * OnCountPermissionAppsResultCallback, Handler)}. 196 * 197 * @param numApps The number of apps that have one of the permissions 198 */ onCountPermissionApps(int numApps)199 void onCountPermissionApps(int numApps); 200 } 201 202 /** 203 * Callback for delivering the result of {@link #getPermissionUsages}. 204 * 205 * @hide 206 */ 207 public interface OnPermissionUsageResultCallback { 208 /** 209 * The result for {@link #getPermissionUsages}. 210 * 211 * @param users The users list. 212 */ onPermissionUsageResult(@onNull List<RuntimePermissionUsageInfo> users)213 void onPermissionUsageResult(@NonNull List<RuntimePermissionUsageInfo> users); 214 } 215 216 private final @NonNull Context mContext; 217 private final @NonNull RemoteService mRemoteService; 218 219 /** 220 * Create a new {@link PermissionControllerManager}. 221 * 222 * @param context to create the manager for 223 * @param handler handler to schedule work 224 * 225 * @hide 226 */ PermissionControllerManager(@onNull Context context, @NonNull Handler handler)227 public PermissionControllerManager(@NonNull Context context, @NonNull Handler handler) { 228 synchronized (sLock) { 229 Pair<Integer, Thread> key = new Pair<>(context.getUserId(), 230 handler.getLooper().getThread()); 231 RemoteService remoteService = sRemoteServices.get(key); 232 if (remoteService == null) { 233 Intent intent = new Intent(SERVICE_INTERFACE); 234 intent.setPackage(context.getPackageManager().getPermissionControllerPackageName()); 235 ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0); 236 237 remoteService = new RemoteService(ActivityThread.currentApplication(), 238 serviceInfo.getComponentInfo().getComponentName(), handler, 239 context.getUser()); 240 sRemoteServices.put(key, remoteService); 241 } 242 243 mRemoteService = remoteService; 244 } 245 246 mContext = context; 247 } 248 249 /** 250 * Revoke a set of runtime permissions for various apps. 251 * 252 * @param request The permissions to revoke as {@code Map<packageName, List<permission>>} 253 * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them 254 * @param reason Why the permission should be revoked 255 * @param executor Executor on which to invoke the callback 256 * @param callback Callback to receive the result 257 */ 258 @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)259 public void revokeRuntimePermissions(@NonNull Map<String, List<String>> request, 260 boolean doDryRun, @Reason int reason, @NonNull @CallbackExecutor Executor executor, 261 @NonNull OnRevokeRuntimePermissionsCallback callback) { 262 // Check input to fail immediately instead of inside the async request 263 checkNotNull(executor); 264 checkNotNull(callback); 265 checkNotNull(request); 266 for (Map.Entry<String, List<String>> appRequest : request.entrySet()) { 267 checkNotNull(appRequest.getKey()); 268 checkCollectionElementsNotNull(appRequest.getValue(), "permissions"); 269 } 270 271 // Check required permission to fail immediately instead of inside the oneway binder call 272 if (mContext.checkSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) 273 != PackageManager.PERMISSION_GRANTED) { 274 throw new SecurityException(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS 275 + " required"); 276 } 277 278 mRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(mRemoteService, 279 request, doDryRun, reason, mContext.getPackageName(), executor, callback)); 280 } 281 282 /** 283 * Set the runtime permission state from a device admin. 284 * 285 * @param callerPackageName The package name of the admin requesting the change 286 * @param packageName Package the permission belongs to 287 * @param permission Permission to change 288 * @param grantState State to set the permission into 289 * @param executor Executor to run the {@code callback} on 290 * @param callback The callback 291 * 292 * @hide 293 */ 294 @RequiresPermission(allOf = {Manifest.permission.GRANT_RUNTIME_PERMISSIONS, 295 Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, 296 Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY}, 297 conditional = true) setRuntimePermissionGrantStateByDeviceAdmin(@onNull String callerPackageName, @NonNull String packageName, @NonNull String permission, @PermissionGrantState int grantState, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)298 public void setRuntimePermissionGrantStateByDeviceAdmin(@NonNull String callerPackageName, 299 @NonNull String packageName, @NonNull String permission, 300 @PermissionGrantState int grantState, @NonNull @CallbackExecutor Executor executor, 301 @NonNull Consumer<Boolean> callback) { 302 checkStringNotEmpty(callerPackageName); 303 checkStringNotEmpty(packageName); 304 checkStringNotEmpty(permission); 305 checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED 306 || grantState == PERMISSION_GRANT_STATE_DENIED 307 || grantState == PERMISSION_GRANT_STATE_DEFAULT); 308 checkNotNull(executor); 309 checkNotNull(callback); 310 311 mRemoteService.scheduleRequest(new PendingSetRuntimePermissionGrantStateByDeviceAdmin( 312 mRemoteService, callerPackageName, packageName, permission, grantState, executor, 313 callback)); 314 } 315 316 /** 317 * Create a backup of the runtime permissions. 318 * 319 * @param user The user to be backed up 320 * @param executor Executor on which to invoke the callback 321 * @param callback Callback to receive the result 322 * 323 * @hide 324 */ 325 @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) getRuntimePermissionBackup(@onNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull OnGetRuntimePermissionBackupCallback callback)326 public void getRuntimePermissionBackup(@NonNull UserHandle user, 327 @NonNull @CallbackExecutor Executor executor, 328 @NonNull OnGetRuntimePermissionBackupCallback callback) { 329 checkNotNull(user); 330 checkNotNull(executor); 331 checkNotNull(callback); 332 333 mRemoteService.scheduleRequest(new PendingGetRuntimePermissionBackup(mRemoteService, 334 user, executor, callback)); 335 } 336 337 /** 338 * Restore a backup of the runtime permissions. 339 * 340 * @param backup the backup to restore. The backup is sent asynchronously, hence it should not 341 * be modified after calling this method. 342 * @param user The user to be restore 343 * 344 * @hide 345 */ 346 @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS) restoreRuntimePermissionBackup(@onNull byte[] backup, @NonNull UserHandle user)347 public void restoreRuntimePermissionBackup(@NonNull byte[] backup, @NonNull UserHandle user) { 348 checkNotNull(backup); 349 checkNotNull(user); 350 351 mRemoteService.scheduleAsyncRequest( 352 new PendingRestoreRuntimePermissionBackup(mRemoteService, backup, user)); 353 } 354 355 /** 356 * Restore a backup of the runtime permissions that has been delayed. 357 * 358 * @param packageName The package that is ready to have it's permissions restored. 359 * @param user The user to restore 360 * @param executor Executor to execute the callback on 361 * @param callback Is called with {@code true} iff there is still more delayed backup left 362 * 363 * @hide 364 */ 365 @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS) restoreDelayedRuntimePermissionBackup(@onNull String packageName, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)366 public void restoreDelayedRuntimePermissionBackup(@NonNull String packageName, 367 @NonNull UserHandle user, 368 @NonNull @CallbackExecutor Executor executor, 369 @NonNull Consumer<Boolean> callback) { 370 checkNotNull(packageName); 371 checkNotNull(user); 372 checkNotNull(executor); 373 checkNotNull(callback); 374 375 mRemoteService.scheduleRequest( 376 new PendingRestoreDelayedRuntimePermissionBackup(mRemoteService, packageName, 377 user, executor, callback)); 378 } 379 380 /** 381 * Gets the runtime permissions for an app. 382 * 383 * @param packageName The package for which to query. 384 * @param callback Callback to receive the result. 385 * @param handler Handler on which to invoke the callback. 386 * 387 * @hide 388 */ 389 @TestApi 390 @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) getAppPermissions(@onNull String packageName, @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler)391 public void getAppPermissions(@NonNull String packageName, 392 @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) { 393 checkNotNull(packageName); 394 checkNotNull(callback); 395 396 mRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(mRemoteService, 397 packageName, callback, handler == null ? mRemoteService.getHandler() : handler)); 398 } 399 400 /** 401 * Revoke the permission {@code permissionName} for app {@code packageName} 402 * 403 * @param packageName The package for which to revoke 404 * @param permissionName The permission to revoke 405 * 406 * @hide 407 */ 408 @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) revokeRuntimePermission(@onNull String packageName, @NonNull String permissionName)409 public void revokeRuntimePermission(@NonNull String packageName, 410 @NonNull String permissionName) { 411 checkNotNull(packageName); 412 checkNotNull(permissionName); 413 414 mRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName, 415 permissionName)); 416 } 417 418 /** 419 * Count how many apps have one of a set of permissions. 420 * 421 * @param permissionNames The permissions the app might have 422 * @param flags Modify which apps to count. By default all non-system apps that request a 423 * permission are counted 424 * @param callback Callback to receive the result 425 * @param handler Handler on which to invoke the callback 426 * 427 * @hide 428 */ 429 @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) countPermissionApps(@onNull List<String> permissionNames, @CountPermissionAppsFlag int flags, @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler)430 public void countPermissionApps(@NonNull List<String> permissionNames, 431 @CountPermissionAppsFlag int flags, 432 @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler) { 433 checkCollectionElementsNotNull(permissionNames, "permissionNames"); 434 checkFlagsArgument(flags, COUNT_WHEN_SYSTEM | COUNT_ONLY_WHEN_GRANTED); 435 checkNotNull(callback); 436 437 mRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(mRemoteService, 438 permissionNames, flags, callback, 439 handler == null ? mRemoteService.getHandler() : handler)); 440 } 441 442 /** 443 * Count how many apps have used permissions. 444 * 445 * @param countSystem Also count system apps 446 * @param numMillis The number of milliseconds in the past to check for uses 447 * @param executor Executor on which to invoke the callback 448 * @param callback Callback to receive the result 449 * 450 * @hide 451 */ 452 @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) getPermissionUsages(boolean countSystem, long numMillis, @NonNull @CallbackExecutor Executor executor, @NonNull OnPermissionUsageResultCallback callback)453 public void getPermissionUsages(boolean countSystem, long numMillis, 454 @NonNull @CallbackExecutor Executor executor, 455 @NonNull OnPermissionUsageResultCallback callback) { 456 checkArgumentNonnegative(numMillis); 457 checkNotNull(executor); 458 checkNotNull(callback); 459 460 mRemoteService.scheduleRequest(new PendingGetPermissionUsagesRequest(mRemoteService, 461 countSystem, numMillis, executor, callback)); 462 } 463 464 /** 465 * Grant or upgrade runtime permissions. The upgrade could be performed 466 * based on whether the device upgraded, whether the permission database 467 * version is old, or because the permission policy changed. 468 * 469 * @param executor Executor on which to invoke the callback 470 * @param callback Callback to receive the result 471 * 472 * @hide 473 */ 474 @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) grantOrUpgradeDefaultRuntimePermissions( @onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)475 public void grantOrUpgradeDefaultRuntimePermissions( 476 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 477 mRemoteService.scheduleRequest(new PendingGrantOrUpgradeDefaultRuntimePermissionsRequest( 478 mRemoteService, executor, callback)); 479 } 480 481 /** 482 * A connection to the remote service 483 */ 484 static final class RemoteService extends 485 AbstractMultiplePendingRequestsRemoteService<RemoteService, IPermissionController> { 486 private static final long UNBIND_TIMEOUT_MILLIS = 10000; 487 private static final long MESSAGE_TIMEOUT_MILLIS = 30000; 488 489 /** 490 * Create a connection to the remote service 491 * 492 * @param context A context to use 493 * @param componentName The component of the service to connect to 494 * @param user User the remote service should be connected as 495 */ RemoteService(@onNull Context context, @NonNull ComponentName componentName, @NonNull Handler handler, @NonNull UserHandle user)496 RemoteService(@NonNull Context context, @NonNull ComponentName componentName, 497 @NonNull Handler handler, @NonNull UserHandle user) { 498 super(context, SERVICE_INTERFACE, componentName, user.getIdentifier(), 499 service -> Log.e(TAG, "RemoteService " + service + " died"), 500 handler, 0, false, 1); 501 } 502 503 /** 504 * @return The default handler used by this service. 505 */ getHandler()506 Handler getHandler() { 507 return mHandler; 508 } 509 510 @Override getServiceInterface(@onNull IBinder binder)511 protected @NonNull IPermissionController getServiceInterface(@NonNull IBinder binder) { 512 return IPermissionController.Stub.asInterface(binder); 513 } 514 515 @Override getTimeoutIdleBindMillis()516 protected long getTimeoutIdleBindMillis() { 517 return UNBIND_TIMEOUT_MILLIS; 518 } 519 520 @Override getRemoteRequestMillis()521 protected long getRemoteRequestMillis() { 522 return MESSAGE_TIMEOUT_MILLIS; 523 } 524 525 @Override scheduleRequest(@onNull BasePendingRequest<RemoteService, IPermissionController> pendingRequest)526 public void scheduleRequest(@NonNull BasePendingRequest<RemoteService, 527 IPermissionController> pendingRequest) { 528 super.scheduleRequest(pendingRequest); 529 } 530 531 @Override scheduleAsyncRequest(@onNull AsyncRequest<IPermissionController> request)532 public void scheduleAsyncRequest(@NonNull AsyncRequest<IPermissionController> request) { 533 super.scheduleAsyncRequest(request); 534 } 535 } 536 537 /** 538 * Task to read a large amount of data from a remote service. 539 */ 540 private static class FileReaderTask<Callback extends Consumer<byte[]>> 541 extends AsyncTask<Void, Void, byte[]> { 542 private ParcelFileDescriptor mLocalPipe; 543 private ParcelFileDescriptor mRemotePipe; 544 545 private final @NonNull Callback mCallback; 546 FileReaderTask(@onNull Callback callback)547 FileReaderTask(@NonNull Callback callback) { 548 mCallback = callback; 549 } 550 551 @Override onPreExecute()552 protected void onPreExecute() { 553 ParcelFileDescriptor[] pipe; 554 try { 555 pipe = ParcelFileDescriptor.createPipe(); 556 } catch (IOException e) { 557 Log.e(TAG, "Could not create pipe needed to get runtime permission backup", e); 558 return; 559 } 560 561 mLocalPipe = pipe[0]; 562 mRemotePipe = pipe[1]; 563 } 564 565 /** 566 * Get the file descriptor the remote service should write the data to. 567 * 568 * <p>Needs to be closed <u>locally</u> before the FileReader can finish. 569 * 570 * @return The file the data should be written to 571 */ getRemotePipe()572 ParcelFileDescriptor getRemotePipe() { 573 return mRemotePipe; 574 } 575 576 @Override doInBackground(Void... ignored)577 protected byte[] doInBackground(Void... ignored) { 578 ByteArrayOutputStream combinedBuffer = new ByteArrayOutputStream(); 579 580 try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(mLocalPipe)) { 581 byte[] buffer = new byte[16 * 1024]; 582 583 while (!isCancelled()) { 584 int numRead = in.read(buffer); 585 if (numRead == -1) { 586 break; 587 } 588 589 combinedBuffer.write(buffer, 0, numRead); 590 } 591 } catch (IOException | NullPointerException e) { 592 Log.e(TAG, "Error reading runtime permission backup", e); 593 combinedBuffer.reset(); 594 } 595 596 return combinedBuffer.toByteArray(); 597 } 598 599 /** 600 * Interrupt the reading of the data. 601 * 602 * <p>Needs to be called when canceling this task as it might be hung. 603 */ interruptRead()604 void interruptRead() { 605 IoUtils.closeQuietly(mLocalPipe); 606 } 607 608 @Override onCancelled()609 protected void onCancelled() { 610 onPostExecute(new byte[]{}); 611 } 612 613 @Override onPostExecute(byte[] backup)614 protected void onPostExecute(byte[] backup) { 615 IoUtils.closeQuietly(mLocalPipe); 616 mCallback.accept(backup); 617 } 618 } 619 620 /** 621 * Task to send a large amount of data to a remote service. 622 */ 623 private static class FileWriterTask extends AsyncTask<byte[], Void, Void> { 624 private static final int CHUNK_SIZE = 4 * 1024; 625 626 private ParcelFileDescriptor mLocalPipe; 627 private ParcelFileDescriptor mRemotePipe; 628 629 @Override onPreExecute()630 protected void onPreExecute() { 631 ParcelFileDescriptor[] pipe; 632 try { 633 pipe = ParcelFileDescriptor.createPipe(); 634 } catch (IOException e) { 635 Log.e(TAG, "Could not create pipe needed to send runtime permission backup", 636 e); 637 return; 638 } 639 640 mRemotePipe = pipe[0]; 641 mLocalPipe = pipe[1]; 642 } 643 644 /** 645 * Get the file descriptor the remote service should read the data from. 646 * 647 * @return The file the data should be read from 648 */ getRemotePipe()649 ParcelFileDescriptor getRemotePipe() { 650 return mRemotePipe; 651 } 652 653 /** 654 * Send the data to the remove service. 655 * 656 * @param in The data to send 657 * 658 * @return ignored 659 */ 660 @Override doInBackground(byte[]... in)661 protected Void doInBackground(byte[]... in) { 662 byte[] buffer = in[0]; 663 try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(mLocalPipe)) { 664 for (int offset = 0; offset < buffer.length; offset += CHUNK_SIZE) { 665 out.write(buffer, offset, min(CHUNK_SIZE, buffer.length - offset)); 666 } 667 } catch (IOException | NullPointerException e) { 668 Log.e(TAG, "Error sending runtime permission backup", e); 669 } 670 671 return null; 672 } 673 674 /** 675 * Interrupt the send of the data. 676 * 677 * <p>Needs to be called when canceling this task as it might be hung. 678 */ interruptWrite()679 void interruptWrite() { 680 IoUtils.closeQuietly(mLocalPipe); 681 } 682 683 @Override onCancelled()684 protected void onCancelled() { 685 onPostExecute(null); 686 } 687 688 @Override onPostExecute(Void ignored)689 protected void onPostExecute(Void ignored) { 690 IoUtils.closeQuietly(mLocalPipe); 691 } 692 } 693 694 /** 695 * Request for {@link #revokeRuntimePermissions} 696 */ 697 private static final class PendingRevokeRuntimePermissionRequest extends 698 AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> { 699 private final @NonNull Map<String, List<String>> mRequest; 700 private final boolean mDoDryRun; 701 private final int mReason; 702 private final @NonNull String mCallingPackage; 703 private final @NonNull Executor mExecutor; 704 private final @NonNull OnRevokeRuntimePermissionsCallback mCallback; 705 706 private final @NonNull RemoteCallback mRemoteCallback; 707 PendingRevokeRuntimePermissionRequest(@onNull RemoteService service, @NonNull Map<String, List<String>> request, boolean doDryRun, @Reason int reason, @NonNull String callingPackage, @NonNull @CallbackExecutor Executor executor, @NonNull OnRevokeRuntimePermissionsCallback callback)708 private PendingRevokeRuntimePermissionRequest(@NonNull RemoteService service, 709 @NonNull Map<String, List<String>> request, boolean doDryRun, 710 @Reason int reason, @NonNull String callingPackage, 711 @NonNull @CallbackExecutor Executor executor, 712 @NonNull OnRevokeRuntimePermissionsCallback callback) { 713 super(service); 714 715 mRequest = request; 716 mDoDryRun = doDryRun; 717 mReason = reason; 718 mCallingPackage = callingPackage; 719 mExecutor = executor; 720 mCallback = callback; 721 722 mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> { 723 long token = Binder.clearCallingIdentity(); 724 try { 725 Map<String, List<String>> revoked = new ArrayMap<>(); 726 try { 727 Bundle bundleizedRevoked = result.getBundle(KEY_RESULT); 728 729 for (String packageName : bundleizedRevoked.keySet()) { 730 Preconditions.checkNotNull(packageName); 731 732 ArrayList<String> permissions = 733 bundleizedRevoked.getStringArrayList(packageName); 734 Preconditions.checkCollectionElementsNotNull(permissions, 735 "permissions"); 736 737 revoked.put(packageName, permissions); 738 } 739 } catch (Exception e) { 740 Log.e(TAG, "Could not read result when revoking runtime permissions", e); 741 } 742 743 callback.onRevokeRuntimePermissions(revoked); 744 } finally { 745 Binder.restoreCallingIdentity(token); 746 747 finish(); 748 } 749 }), null); 750 } 751 752 @Override onTimeout(RemoteService remoteService)753 protected void onTimeout(RemoteService remoteService) { 754 long token = Binder.clearCallingIdentity(); 755 try { 756 mExecutor.execute( 757 () -> mCallback.onRevokeRuntimePermissions(Collections.emptyMap())); 758 } finally { 759 Binder.restoreCallingIdentity(token); 760 } 761 } 762 763 @Override run()764 public void run() { 765 Bundle bundledizedRequest = new Bundle(); 766 for (Map.Entry<String, List<String>> appRequest : mRequest.entrySet()) { 767 bundledizedRequest.putStringArrayList(appRequest.getKey(), 768 new ArrayList<>(appRequest.getValue())); 769 } 770 771 try { 772 getService().getServiceInterface().revokeRuntimePermissions(bundledizedRequest, 773 mDoDryRun, mReason, mCallingPackage, mRemoteCallback); 774 } catch (RemoteException e) { 775 Log.e(TAG, "Error revoking runtime permission", e); 776 } 777 } 778 } 779 780 /** 781 * Request for {@link #getRuntimePermissionBackup} 782 */ 783 private static final class PendingGetRuntimePermissionBackup extends 784 AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> 785 implements Consumer<byte[]> { 786 private final @NonNull FileReaderTask<PendingGetRuntimePermissionBackup> mBackupReader; 787 private final @NonNull Executor mExecutor; 788 private final @NonNull OnGetRuntimePermissionBackupCallback mCallback; 789 private final @NonNull UserHandle mUser; 790 PendingGetRuntimePermissionBackup(@onNull RemoteService service, @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, @NonNull OnGetRuntimePermissionBackupCallback callback)791 private PendingGetRuntimePermissionBackup(@NonNull RemoteService service, 792 @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, 793 @NonNull OnGetRuntimePermissionBackupCallback callback) { 794 super(service); 795 796 mUser = user; 797 mExecutor = executor; 798 mCallback = callback; 799 800 mBackupReader = new FileReaderTask<>(this); 801 } 802 803 @Override onTimeout(RemoteService remoteService)804 protected void onTimeout(RemoteService remoteService) { 805 mBackupReader.cancel(true); 806 mBackupReader.interruptRead(); 807 } 808 809 @Override run()810 public void run() { 811 if (mBackupReader.getStatus() != AsyncTask.Status.PENDING) { 812 return; 813 } 814 mBackupReader.execute(); 815 816 ParcelFileDescriptor remotePipe = mBackupReader.getRemotePipe(); 817 try { 818 getService().getServiceInterface().getRuntimePermissionBackup(mUser, remotePipe); 819 } catch (RemoteException e) { 820 Log.e(TAG, "Error getting runtime permission backup", e); 821 } finally { 822 // Remote pipe end is duped by binder call. Local copy is not needed anymore 823 IoUtils.closeQuietly(remotePipe); 824 } 825 } 826 827 /** 828 * Called when the {@link #mBackupReader} finished reading the file. 829 * 830 * @param backup The data read 831 */ 832 @Override accept(byte[] backup)833 public void accept(byte[] backup) { 834 long token = Binder.clearCallingIdentity(); 835 try { 836 mExecutor.execute(() -> mCallback.onGetRuntimePermissionsBackup(backup)); 837 } finally { 838 Binder.restoreCallingIdentity(token); 839 } 840 841 finish(); 842 } 843 } 844 845 /** 846 * Request for {@link #getRuntimePermissionBackup} 847 */ 848 private static final class PendingSetRuntimePermissionGrantStateByDeviceAdmin extends 849 AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> { 850 private final @NonNull String mCallerPackageName; 851 private final @NonNull String mPackageName; 852 private final @NonNull String mPermission; 853 private final @PermissionGrantState int mGrantState; 854 855 private final @NonNull Executor mExecutor; 856 private final @NonNull Consumer<Boolean> mCallback; 857 private final @NonNull RemoteCallback mRemoteCallback; 858 PendingSetRuntimePermissionGrantStateByDeviceAdmin(@onNull RemoteService service, @NonNull String callerPackageName, @NonNull String packageName, @NonNull String permission, @PermissionGrantState int grantState, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)859 private PendingSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull RemoteService service, 860 @NonNull String callerPackageName, @NonNull String packageName, 861 @NonNull String permission, @PermissionGrantState int grantState, 862 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 863 super(service); 864 865 mCallerPackageName = callerPackageName; 866 mPackageName = packageName; 867 mPermission = permission; 868 mGrantState = grantState; 869 mExecutor = executor; 870 mCallback = callback; 871 872 mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> { 873 long token = Binder.clearCallingIdentity(); 874 try { 875 callback.accept(result.getBoolean(KEY_RESULT, false)); 876 } finally { 877 Binder.restoreCallingIdentity(token); 878 879 finish(); 880 } 881 }), null); 882 } 883 884 @Override onTimeout(RemoteService remoteService)885 protected void onTimeout(RemoteService remoteService) { 886 long token = Binder.clearCallingIdentity(); 887 try { 888 mExecutor.execute(() -> mCallback.accept(false)); 889 } finally { 890 Binder.restoreCallingIdentity(token); 891 } 892 } 893 894 @Override run()895 public void run() { 896 try { 897 getService().getServiceInterface().setRuntimePermissionGrantStateByDeviceAdmin( 898 mCallerPackageName, mPackageName, mPermission, mGrantState, mRemoteCallback); 899 } catch (RemoteException e) { 900 Log.e(TAG, "Error setting permissions state for device admin " + mPackageName, 901 e); 902 } 903 } 904 } 905 906 /** 907 * Request for {@link #restoreRuntimePermissionBackup} 908 */ 909 private static final class PendingRestoreRuntimePermissionBackup implements 910 AbstractRemoteService.AsyncRequest<IPermissionController> { 911 private final @NonNull FileWriterTask mBackupSender; 912 private final @NonNull byte[] mBackup; 913 private final @NonNull UserHandle mUser; 914 PendingRestoreRuntimePermissionBackup(@onNull RemoteService service, @NonNull byte[] backup, @NonNull UserHandle user)915 private PendingRestoreRuntimePermissionBackup(@NonNull RemoteService service, 916 @NonNull byte[] backup, @NonNull UserHandle user) { 917 mBackup = backup; 918 mUser = user; 919 920 mBackupSender = new FileWriterTask(); 921 } 922 923 @Override run(@onNull IPermissionController service)924 public void run(@NonNull IPermissionController service) { 925 if (mBackupSender.getStatus() != AsyncTask.Status.PENDING) { 926 return; 927 } 928 mBackupSender.execute(mBackup); 929 930 ParcelFileDescriptor remotePipe = mBackupSender.getRemotePipe(); 931 try { 932 service.restoreRuntimePermissionBackup(mUser, remotePipe); 933 } catch (RemoteException e) { 934 Log.e(TAG, "Error sending runtime permission backup", e); 935 mBackupSender.cancel(false); 936 mBackupSender.interruptWrite(); 937 } finally { 938 // Remote pipe end is duped by binder call. Local copy is not needed anymore 939 IoUtils.closeQuietly(remotePipe); 940 } 941 } 942 } 943 944 /** 945 * Request for {@link #restoreDelayedRuntimePermissionBackup(String, UserHandle, Executor, 946 * Consumer<Boolean>)} 947 */ 948 private static final class PendingRestoreDelayedRuntimePermissionBackup extends 949 AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> { 950 private final @NonNull String mPackageName; 951 private final @NonNull UserHandle mUser; 952 private final @NonNull Executor mExecutor; 953 private final @NonNull Consumer<Boolean> mCallback; 954 955 private final @NonNull RemoteCallback mRemoteCallback; 956 PendingRestoreDelayedRuntimePermissionBackup(@onNull RemoteService service, @NonNull String packageName, @NonNull UserHandle user, @NonNull Executor executor, @NonNull Consumer<Boolean> callback)957 private PendingRestoreDelayedRuntimePermissionBackup(@NonNull RemoteService service, 958 @NonNull String packageName, @NonNull UserHandle user, @NonNull Executor executor, 959 @NonNull Consumer<Boolean> callback) { 960 super(service); 961 962 mPackageName = packageName; 963 mUser = user; 964 mExecutor = executor; 965 mCallback = callback; 966 967 mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> { 968 long token = Binder.clearCallingIdentity(); 969 try { 970 callback.accept(result.getBoolean(KEY_RESULT, false)); 971 } finally { 972 Binder.restoreCallingIdentity(token); 973 974 finish(); 975 } 976 }), null); 977 } 978 979 @Override onTimeout(RemoteService remoteService)980 protected void onTimeout(RemoteService remoteService) { 981 long token = Binder.clearCallingIdentity(); 982 try { 983 mExecutor.execute( 984 () -> mCallback.accept(true)); 985 } finally { 986 Binder.restoreCallingIdentity(token); 987 } 988 } 989 990 @Override run()991 public void run() { 992 try { 993 getService().getServiceInterface().restoreDelayedRuntimePermissionBackup( 994 mPackageName, mUser, mRemoteCallback); 995 } catch (RemoteException e) { 996 Log.e(TAG, "Error restoring delayed permissions for " + mPackageName, e); 997 } 998 } 999 } 1000 1001 /** 1002 * Request for {@link #getAppPermissions} 1003 */ 1004 private static final class PendingGetAppPermissionRequest extends 1005 AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> { 1006 private final @NonNull String mPackageName; 1007 private final @NonNull OnGetAppPermissionResultCallback mCallback; 1008 1009 private final @NonNull RemoteCallback mRemoteCallback; 1010 PendingGetAppPermissionRequest(@onNull RemoteService service, @NonNull String packageName, @NonNull OnGetAppPermissionResultCallback callback, @NonNull Handler handler)1011 private PendingGetAppPermissionRequest(@NonNull RemoteService service, 1012 @NonNull String packageName, @NonNull OnGetAppPermissionResultCallback callback, 1013 @NonNull Handler handler) { 1014 super(service); 1015 1016 mPackageName = packageName; 1017 mCallback = callback; 1018 1019 mRemoteCallback = new RemoteCallback(result -> { 1020 final List<RuntimePermissionPresentationInfo> reportedPermissions; 1021 List<RuntimePermissionPresentationInfo> permissions = null; 1022 if (result != null) { 1023 permissions = result.getParcelableArrayList(KEY_RESULT); 1024 } 1025 if (permissions == null) { 1026 permissions = Collections.emptyList(); 1027 } 1028 reportedPermissions = permissions; 1029 1030 callback.onGetAppPermissions(reportedPermissions); 1031 1032 finish(); 1033 }, handler); 1034 } 1035 1036 @Override onTimeout(RemoteService remoteService)1037 protected void onTimeout(RemoteService remoteService) { 1038 mCallback.onGetAppPermissions(Collections.emptyList()); 1039 } 1040 1041 @Override run()1042 public void run() { 1043 try { 1044 getService().getServiceInterface().getAppPermissions(mPackageName, mRemoteCallback); 1045 } catch (RemoteException e) { 1046 Log.e(TAG, "Error getting app permission", e); 1047 } 1048 } 1049 } 1050 1051 /** 1052 * Request for {@link #revokeRuntimePermission} 1053 */ 1054 private static final class PendingRevokeAppPermissionRequest 1055 implements AbstractRemoteService.AsyncRequest<IPermissionController> { 1056 private final @NonNull String mPackageName; 1057 private final @NonNull String mPermissionName; 1058 PendingRevokeAppPermissionRequest(@onNull String packageName, @NonNull String permissionName)1059 private PendingRevokeAppPermissionRequest(@NonNull String packageName, 1060 @NonNull String permissionName) { 1061 mPackageName = packageName; 1062 mPermissionName = permissionName; 1063 } 1064 1065 @Override run(IPermissionController remoteInterface)1066 public void run(IPermissionController remoteInterface) { 1067 try { 1068 remoteInterface.revokeRuntimePermission(mPackageName, mPermissionName); 1069 } catch (RemoteException e) { 1070 Log.e(TAG, "Error revoking app permission", e); 1071 } 1072 } 1073 } 1074 1075 /** 1076 * Request for {@link #countPermissionApps} 1077 */ 1078 private static final class PendingCountPermissionAppsRequest extends 1079 AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> { 1080 private final @NonNull List<String> mPermissionNames; 1081 private final @NonNull OnCountPermissionAppsResultCallback mCallback; 1082 private final @CountPermissionAppsFlag int mFlags; 1083 1084 private final @NonNull RemoteCallback mRemoteCallback; 1085 PendingCountPermissionAppsRequest(@onNull RemoteService service, @NonNull List<String> permissionNames, @CountPermissionAppsFlag int flags, @NonNull OnCountPermissionAppsResultCallback callback, @NonNull Handler handler)1086 private PendingCountPermissionAppsRequest(@NonNull RemoteService service, 1087 @NonNull List<String> permissionNames, @CountPermissionAppsFlag int flags, 1088 @NonNull OnCountPermissionAppsResultCallback callback, @NonNull Handler handler) { 1089 super(service); 1090 1091 mPermissionNames = permissionNames; 1092 mFlags = flags; 1093 mCallback = callback; 1094 1095 mRemoteCallback = new RemoteCallback(result -> { 1096 final int numApps; 1097 if (result != null) { 1098 numApps = result.getInt(KEY_RESULT); 1099 } else { 1100 numApps = 0; 1101 } 1102 1103 callback.onCountPermissionApps(numApps); 1104 1105 finish(); 1106 }, handler); 1107 } 1108 1109 @Override onTimeout(RemoteService remoteService)1110 protected void onTimeout(RemoteService remoteService) { 1111 mCallback.onCountPermissionApps(0); 1112 } 1113 1114 @Override run()1115 public void run() { 1116 try { 1117 getService().getServiceInterface().countPermissionApps(mPermissionNames, 1118 mFlags, mRemoteCallback); 1119 } catch (RemoteException e) { 1120 Log.e(TAG, "Error counting permission apps", e); 1121 } 1122 } 1123 } 1124 1125 /** 1126 * Request for {@link #getPermissionUsages} 1127 */ 1128 private static final class PendingGetPermissionUsagesRequest extends 1129 AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> { 1130 private final @NonNull OnPermissionUsageResultCallback mCallback; 1131 private final boolean mCountSystem; 1132 private final long mNumMillis; 1133 1134 private final @NonNull RemoteCallback mRemoteCallback; 1135 PendingGetPermissionUsagesRequest(@onNull RemoteService service, boolean countSystem, long numMillis, @NonNull @CallbackExecutor Executor executor, @NonNull OnPermissionUsageResultCallback callback)1136 private PendingGetPermissionUsagesRequest(@NonNull RemoteService service, 1137 boolean countSystem, long numMillis, @NonNull @CallbackExecutor Executor executor, 1138 @NonNull OnPermissionUsageResultCallback callback) { 1139 super(service); 1140 1141 mCountSystem = countSystem; 1142 mNumMillis = numMillis; 1143 mCallback = callback; 1144 1145 mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> { 1146 long token = Binder.clearCallingIdentity(); 1147 try { 1148 final List<RuntimePermissionUsageInfo> reportedUsers; 1149 List<RuntimePermissionUsageInfo> users = null; 1150 if (result != null) { 1151 users = result.getParcelableArrayList(KEY_RESULT); 1152 } else { 1153 users = Collections.emptyList(); 1154 } 1155 reportedUsers = users; 1156 1157 callback.onPermissionUsageResult(reportedUsers); 1158 } finally { 1159 Binder.restoreCallingIdentity(token); 1160 1161 finish(); 1162 } 1163 }), null); 1164 } 1165 1166 @Override onTimeout(RemoteService remoteService)1167 protected void onTimeout(RemoteService remoteService) { 1168 mCallback.onPermissionUsageResult(Collections.emptyList()); 1169 } 1170 1171 @Override run()1172 public void run() { 1173 try { 1174 getService().getServiceInterface().getPermissionUsages(mCountSystem, mNumMillis, 1175 mRemoteCallback); 1176 } catch (RemoteException e) { 1177 Log.e(TAG, "Error counting permission users", e); 1178 } 1179 } 1180 } 1181 1182 /** 1183 * Request for {@link #grantOrUpgradeDefaultRuntimePermissions(Executor, Consumer)} 1184 */ 1185 private static final class PendingGrantOrUpgradeDefaultRuntimePermissionsRequest extends 1186 AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> { 1187 private final @NonNull Consumer<Boolean> mCallback; 1188 1189 private final @NonNull RemoteCallback mRemoteCallback; 1190 PendingGrantOrUpgradeDefaultRuntimePermissionsRequest( @onNull RemoteService service, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)1191 private PendingGrantOrUpgradeDefaultRuntimePermissionsRequest( 1192 @NonNull RemoteService service, @NonNull @CallbackExecutor Executor executor, 1193 @NonNull Consumer<Boolean> callback) { 1194 super(service); 1195 mCallback = callback; 1196 1197 mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> { 1198 long token = Binder.clearCallingIdentity(); 1199 try { 1200 callback.accept(result != null); 1201 } finally { 1202 Binder.restoreCallingIdentity(token); 1203 finish(); 1204 } 1205 }), null); 1206 } 1207 1208 @Override onTimeout(RemoteService remoteService)1209 protected void onTimeout(RemoteService remoteService) { 1210 long token = Binder.clearCallingIdentity(); 1211 try { 1212 mCallback.accept(false); 1213 } finally { 1214 Binder.restoreCallingIdentity(token); 1215 } 1216 } 1217 1218 @Override run()1219 public void run() { 1220 try { 1221 getService().getServiceInterface().grantOrUpgradeDefaultRuntimePermissions( 1222 mRemoteCallback); 1223 } catch (RemoteException e) { 1224 Log.e(TAG, "Error granting or upgrading runtime permissions", e); 1225 } 1226 } 1227 } 1228 } 1229