Home | History | Annotate | Download | only in permission
      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          */
    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          */
    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          */
    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          */
    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          */
    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      */
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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          */
    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          */
    506         Handler getHandler() {
    507             return mHandler;
    508         }
    509 
    510         @Override
    511         protected @NonNull IPermissionController getServiceInterface(@NonNull IBinder binder) {
    512             return IPermissionController.Stub.asInterface(binder);
    513         }
    514 
    515         @Override
    516         protected long getTimeoutIdleBindMillis() {
    517             return UNBIND_TIMEOUT_MILLIS;
    518         }
    519 
    520         @Override
    521         protected long getRemoteRequestMillis() {
    522             return MESSAGE_TIMEOUT_MILLIS;
    523         }
    524 
    525         @Override
    526         public void scheduleRequest(@NonNull BasePendingRequest<RemoteService,
    527                 IPermissionController> pendingRequest) {
    528             super.scheduleRequest(pendingRequest);
    529         }
    530 
    531         @Override
    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 
    547         FileReaderTask(@NonNull Callback callback) {
    548             mCallback = callback;
    549         }
    550 
    551         @Override
    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          */
    572         ParcelFileDescriptor getRemotePipe() {
    573             return mRemotePipe;
    574         }
    575 
    576         @Override
    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          */
    604         void interruptRead() {
    605             IoUtils.closeQuietly(mLocalPipe);
    606         }
    607 
    608         @Override
    609         protected void onCancelled() {
    610             onPostExecute(new byte[]{});
    611         }
    612 
    613         @Override
    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
    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          */
    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
    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          */
    679         void interruptWrite() {
    680             IoUtils.closeQuietly(mLocalPipe);
    681         }
    682 
    683         @Override
    684         protected void onCancelled() {
    685             onPostExecute(null);
    686         }
    687 
    688         @Override
    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 
    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
    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
    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 
    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
    804         protected void onTimeout(RemoteService remoteService) {
    805             mBackupReader.cancel(true);
    806             mBackupReader.interruptRead();
    807         }
    808 
    809         @Override
    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
    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 
    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
    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
    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 
    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
    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 
    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
    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
    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 
   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
   1037         protected void onTimeout(RemoteService remoteService) {
   1038             mCallback.onGetAppPermissions(Collections.emptyList());
   1039         }
   1040 
   1041         @Override
   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 
   1059         private PendingRevokeAppPermissionRequest(@NonNull String packageName,
   1060                 @NonNull String permissionName) {
   1061             mPackageName = packageName;
   1062             mPermissionName = permissionName;
   1063         }
   1064 
   1065         @Override
   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 
   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
   1110         protected void onTimeout(RemoteService remoteService) {
   1111             mCallback.onCountPermissionApps(0);
   1112         }
   1113 
   1114         @Override
   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 
   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
   1167         protected void onTimeout(RemoteService remoteService) {
   1168             mCallback.onPermissionUsageResult(Collections.emptyList());
   1169         }
   1170 
   1171         @Override
   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 
   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
   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
   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