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.PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED;
     23 import static android.permission.PermissionControllerManager.COUNT_WHEN_SYSTEM;
     24 
     25 import static com.android.internal.util.Preconditions.checkArgument;
     26 import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
     27 import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
     28 import static com.android.internal.util.Preconditions.checkFlagsArgument;
     29 import static com.android.internal.util.Preconditions.checkNotNull;
     30 import static com.android.internal.util.Preconditions.checkStringNotEmpty;
     31 
     32 import android.Manifest;
     33 import android.annotation.BinderThread;
     34 import android.annotation.NonNull;
     35 import android.annotation.SystemApi;
     36 import android.app.Service;
     37 import android.app.admin.DevicePolicyManager.PermissionGrantState;
     38 import android.content.Intent;
     39 import android.content.pm.PackageInfo;
     40 import android.content.pm.PackageManager;
     41 import android.os.Bundle;
     42 import android.os.IBinder;
     43 import android.os.ParcelFileDescriptor;
     44 import android.os.RemoteCallback;
     45 import android.os.UserHandle;
     46 import android.permission.PermissionControllerManager.CountPermissionAppsFlag;
     47 import android.util.ArrayMap;
     48 import android.util.Log;
     49 
     50 import com.android.internal.util.Preconditions;
     51 
     52 import java.io.IOException;
     53 import java.io.InputStream;
     54 import java.io.OutputStream;
     55 import java.util.ArrayList;
     56 import java.util.List;
     57 import java.util.Map;
     58 import java.util.concurrent.CountDownLatch;
     59 import java.util.function.Consumer;
     60 import java.util.function.IntConsumer;
     61 
     62 /**
     63  * This service is meant to be implemented by the app controlling permissions.
     64  *
     65  * @see PermissionControllerManager
     66  *
     67  * @hide
     68  */
     69 @SystemApi
     70 public abstract class PermissionControllerService extends Service {
     71     private static final String LOG_TAG = PermissionControllerService.class.getSimpleName();
     72 
     73     /**
     74      * The {@link Intent} action that must be declared as handled by a service
     75      * in its manifest for the system to recognize it as a runtime permission
     76      * presenter service.
     77      */
     78     public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
     79 
     80     /**
     81      * Revoke a set of runtime permissions for various apps.
     82      *
     83      * @param requests The permissions to revoke as {@code Map<packageName, List<permission>>}
     84      * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them
     85      * @param reason Why the permission should be revoked
     86      * @param callerPackageName The package name of the calling app
     87      * @param callback Callback waiting for the actually removed permissions as
     88      * {@code Map<packageName, List<permission>>}
     89      */
     90     @BinderThread
     91     public abstract void onRevokeRuntimePermissions(
     92             @NonNull Map<String, List<String>> requests, boolean doDryRun,
     93             @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName,
     94             @NonNull Consumer<Map<String, List<String>>> callback);
     95 
     96     /**
     97      * Create a backup of the runtime permissions.
     98      *
     99      * @param user The user to back up
    100      * @param backup The stream to write the backup to
    101      * @param callback Callback waiting for operation to be complete
    102      */
    103     @BinderThread
    104     public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user,
    105             @NonNull OutputStream backup, @NonNull Runnable callback);
    106 
    107     /**
    108      * Restore a backup of the runtime permissions.
    109      *
    110      * <p>If an app mentioned in the backup is not installed the state should be saved to later
    111      * be restored via {@link #onRestoreDelayedRuntimePermissionsBackup}.
    112      *
    113      * @param user The user to restore
    114      * @param backup The stream to read the backup from
    115      * @param callback Callback waiting for operation to be complete
    116      */
    117     @BinderThread
    118     public abstract void onRestoreRuntimePermissionsBackup(@NonNull UserHandle user,
    119             @NonNull InputStream backup, @NonNull Runnable callback);
    120 
    121     /**
    122      * Restore the permission state of an app that was provided in
    123      * {@link #onRestoreRuntimePermissionsBackup} but could not be restored back then.
    124      *
    125      * @param packageName The app to restore
    126      * @param user The user to restore
    127      * @param callback Callback waiting for whether there is still delayed backup left
    128      */
    129     @BinderThread
    130     public abstract void onRestoreDelayedRuntimePermissionsBackup(@NonNull String packageName,
    131             @NonNull UserHandle user, @NonNull Consumer<Boolean> callback);
    132 
    133     /**
    134      * Gets the runtime permissions for an app.
    135      *
    136      * @param packageName The package for which to query.
    137      * @param callback Callback waiting for the descriptions of the runtime permissions of the app
    138      */
    139     @BinderThread
    140     public abstract void onGetAppPermissions(@NonNull String packageName,
    141             @NonNull Consumer<List<RuntimePermissionPresentationInfo>> callback);
    142 
    143     /**
    144      * Revokes the permission {@code permissionName} for app {@code packageName}
    145      *
    146      * @param packageName The package for which to revoke
    147      * @param permissionName The permission to revoke
    148      * @param callback Callback waiting for operation to be complete
    149      */
    150     @BinderThread
    151     public abstract void onRevokeRuntimePermission(@NonNull String packageName,
    152             @NonNull String permissionName, @NonNull Runnable callback);
    153 
    154     /**
    155      * Count how many apps have one of a set of permissions.
    156      *
    157      * @param permissionNames The permissions the app might have
    158      * @param flags Modify which apps to count. By default all non-system apps that request a
    159      *              permission are counted
    160      * @param callback Callback waiting for the number of apps that have one of the permissions
    161      */
    162     @BinderThread
    163     public abstract void onCountPermissionApps(@NonNull List<String> permissionNames,
    164             @CountPermissionAppsFlag int flags, @NonNull IntConsumer callback);
    165 
    166     /**
    167      * Count how many apps have used permissions.
    168      *
    169      * @param countSystem Also count system apps
    170      * @param numMillis The number of milliseconds in the past to check for uses
    171      * @param callback Callback waiting for the descriptions of the users of permissions
    172      */
    173     @BinderThread
    174     public abstract void onGetPermissionUsages(boolean countSystem, long numMillis,
    175             @NonNull Consumer<List<RuntimePermissionUsageInfo>> callback);
    176 
    177     /**
    178      * Grant or upgrade runtime permissions. The upgrade could be performed
    179      * based on whether the device upgraded, whether the permission database
    180      * version is old, or because the permission policy changed.
    181      *
    182      * @param callback Callback waiting for operation to be complete
    183      *
    184      * @see PackageManager#isDeviceUpgrading()
    185      * @see PermissionManager#getRuntimePermissionsVersion()
    186      * @see PermissionManager#setRuntimePermissionsVersion(int)
    187      */
    188     @BinderThread
    189     public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable callback);
    190 
    191     /**
    192      * Set the runtime permission state from a device admin.
    193      *
    194      * @param callerPackageName The package name of the admin requesting the change
    195      * @param packageName Package the permission belongs to
    196      * @param permission Permission to change
    197      * @param grantState State to set the permission into
    198      * @param callback Callback waiting for whether the state could be set or not
    199      */
    200     @BinderThread
    201     public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(
    202             @NonNull String callerPackageName, @NonNull String packageName,
    203             @NonNull String permission, @PermissionGrantState int grantState,
    204             @NonNull Consumer<Boolean> callback);
    205 
    206     @Override
    207     public final @NonNull IBinder onBind(Intent intent) {
    208         return new IPermissionController.Stub() {
    209             @Override
    210             public void revokeRuntimePermissions(
    211                     Bundle bundleizedRequest, boolean doDryRun, int reason,
    212                     String callerPackageName, RemoteCallback callback) {
    213                 checkNotNull(bundleizedRequest, "bundleizedRequest");
    214                 checkNotNull(callerPackageName);
    215                 checkNotNull(callback);
    216 
    217                 Map<String, List<String>> request = new ArrayMap<>();
    218                 for (String packageName : bundleizedRequest.keySet()) {
    219                     Preconditions.checkNotNull(packageName);
    220 
    221                     ArrayList<String> permissions =
    222                             bundleizedRequest.getStringArrayList(packageName);
    223                     Preconditions.checkCollectionElementsNotNull(permissions, "permissions");
    224 
    225                     request.put(packageName, permissions);
    226                 }
    227 
    228                 enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
    229 
    230                 // Verify callerPackageName
    231                 try {
    232                     PackageInfo pkgInfo = getPackageManager().getPackageInfo(callerPackageName, 0);
    233                     checkArgument(getCallingUid() == pkgInfo.applicationInfo.uid);
    234                 } catch (PackageManager.NameNotFoundException e) {
    235                     throw new RuntimeException(e);
    236                 }
    237 
    238                 onRevokeRuntimePermissions(request,
    239                         doDryRun, reason, callerPackageName, revoked -> {
    240                             checkNotNull(revoked);
    241                             Bundle bundledizedRevoked = new Bundle();
    242                             for (Map.Entry<String, List<String>> appRevocation :
    243                                     revoked.entrySet()) {
    244                                 checkNotNull(appRevocation.getKey());
    245                                 checkCollectionElementsNotNull(appRevocation.getValue(),
    246                                         "permissions");
    247 
    248                                 bundledizedRevoked.putStringArrayList(appRevocation.getKey(),
    249                                         new ArrayList<>(appRevocation.getValue()));
    250                             }
    251 
    252                             Bundle result = new Bundle();
    253                             result.putBundle(PermissionControllerManager.KEY_RESULT,
    254                                     bundledizedRevoked);
    255                             callback.sendResult(result);
    256                         });
    257             }
    258 
    259             @Override
    260             public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
    261                 checkNotNull(user);
    262                 checkNotNull(pipe);
    263 
    264                 enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
    265 
    266                 try (OutputStream backup = new ParcelFileDescriptor.AutoCloseOutputStream(pipe)) {
    267                     CountDownLatch latch = new CountDownLatch(1);
    268                     onGetRuntimePermissionsBackup(user, backup, latch::countDown);
    269                     latch.await();
    270                 } catch (IOException e) {
    271                     Log.e(LOG_TAG, "Could not open pipe to write backup to", e);
    272                 } catch (InterruptedException e) {
    273                     Log.e(LOG_TAG, "getRuntimePermissionBackup timed out", e);
    274                 }
    275             }
    276 
    277             @Override
    278             public void restoreRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
    279                 checkNotNull(user);
    280                 checkNotNull(pipe);
    281 
    282                 enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
    283 
    284                 try (InputStream backup = new ParcelFileDescriptor.AutoCloseInputStream(pipe)) {
    285                     CountDownLatch latch = new CountDownLatch(1);
    286                     onRestoreRuntimePermissionsBackup(user, backup, latch::countDown);
    287                     latch.await();
    288                 } catch (IOException e) {
    289                     Log.e(LOG_TAG, "Could not open pipe to read backup from", e);
    290                 } catch (InterruptedException e) {
    291                     Log.e(LOG_TAG, "restoreRuntimePermissionBackup timed out", e);
    292                 }
    293             }
    294 
    295             @Override
    296             public void restoreDelayedRuntimePermissionBackup(String packageName, UserHandle user,
    297                     RemoteCallback callback) {
    298                 checkNotNull(packageName);
    299                 checkNotNull(user);
    300                 checkNotNull(callback);
    301 
    302                 enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
    303 
    304                 onRestoreDelayedRuntimePermissionsBackup(packageName, user,
    305                         hasMoreBackup -> {
    306                             Bundle result = new Bundle();
    307                             result.putBoolean(PermissionControllerManager.KEY_RESULT,
    308                                     hasMoreBackup);
    309                             callback.sendResult(result);
    310                         });
    311             }
    312 
    313             @Override
    314             public void getAppPermissions(String packageName, RemoteCallback callback) {
    315                 checkNotNull(packageName, "packageName");
    316                 checkNotNull(callback, "callback");
    317 
    318                 enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
    319 
    320                 onGetAppPermissions(packageName,
    321                         permissions -> {
    322                             if (permissions != null && !permissions.isEmpty()) {
    323                                 Bundle result = new Bundle();
    324                                 result.putParcelableList(PermissionControllerManager.KEY_RESULT,
    325                                         permissions);
    326                                 callback.sendResult(result);
    327                             } else {
    328                                 callback.sendResult(null);
    329                             }
    330                         });
    331             }
    332 
    333             @Override
    334             public void revokeRuntimePermission(String packageName, String permissionName) {
    335                 checkNotNull(packageName, "packageName");
    336                 checkNotNull(permissionName, "permissionName");
    337 
    338                 enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
    339 
    340                 CountDownLatch latch = new CountDownLatch(1);
    341                 PermissionControllerService.this.onRevokeRuntimePermission(packageName,
    342                         permissionName, latch::countDown);
    343                 try {
    344                     latch.await();
    345                 } catch (InterruptedException e) {
    346                     Log.e(LOG_TAG, "revokeRuntimePermission timed out", e);
    347                 }
    348             }
    349 
    350             @Override
    351             public void countPermissionApps(List<String> permissionNames, int flags,
    352                     RemoteCallback callback) {
    353                 checkCollectionElementsNotNull(permissionNames, "permissionNames");
    354                 checkFlagsArgument(flags, COUNT_WHEN_SYSTEM | COUNT_ONLY_WHEN_GRANTED);
    355                 checkNotNull(callback, "callback");
    356 
    357                 enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
    358 
    359                 onCountPermissionApps(permissionNames, flags, numApps -> {
    360                     Bundle result = new Bundle();
    361                     result.putInt(PermissionControllerManager.KEY_RESULT, numApps);
    362                     callback.sendResult(result);
    363                 });
    364             }
    365 
    366             @Override
    367             public void getPermissionUsages(boolean countSystem, long numMillis,
    368                     RemoteCallback callback) {
    369                 checkArgumentNonnegative(numMillis);
    370                 checkNotNull(callback, "callback");
    371 
    372                 enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
    373 
    374                 onGetPermissionUsages(countSystem, numMillis, users -> {
    375                     if (users != null && !users.isEmpty()) {
    376                         Bundle result = new Bundle();
    377                         result.putParcelableList(PermissionControllerManager.KEY_RESULT, users);
    378                         callback.sendResult(result);
    379                     } else {
    380                         callback.sendResult(null);
    381                     }
    382                 });
    383             }
    384 
    385             @Override
    386             public void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName,
    387                     String packageName, String permission, int grantState,
    388                     RemoteCallback callback) {
    389                 checkStringNotEmpty(callerPackageName);
    390                 checkStringNotEmpty(packageName);
    391                 checkStringNotEmpty(permission);
    392                 checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED
    393                         || grantState == PERMISSION_GRANT_STATE_DENIED
    394                         || grantState == PERMISSION_GRANT_STATE_DEFAULT);
    395                 checkNotNull(callback);
    396 
    397                 if (grantState == PERMISSION_GRANT_STATE_DENIED) {
    398                     enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
    399                 }
    400 
    401                 if (grantState == PERMISSION_GRANT_STATE_DENIED) {
    402                     enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
    403                 }
    404 
    405                 enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
    406                         null);
    407 
    408                 onSetRuntimePermissionGrantStateByDeviceAdmin(callerPackageName,
    409                         packageName, permission, grantState, wasSet -> {
    410                             Bundle result = new Bundle();
    411                             result.putBoolean(PermissionControllerManager.KEY_RESULT, wasSet);
    412                             callback.sendResult(result);
    413                         });
    414             }
    415 
    416             @Override
    417             public void grantOrUpgradeDefaultRuntimePermissions(@NonNull RemoteCallback callback) {
    418                 checkNotNull(callback, "callback");
    419 
    420                 enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
    421                         null);
    422 
    423                 onGrantOrUpgradeDefaultRuntimePermissions(() -> callback.sendResult(Bundle.EMPTY));
    424             }
    425         };
    426     }
    427 }
    428