blob: 8ad35e7eb37dfc6ae9740d264d6021962e243cb6 [file] [log] [blame]
Alan Viverette3da604b2020-06-10 18:34:39 +00001/*
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
17package android.permission;
18
19import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
20import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
21import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
22import static android.permission.PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED;
23import static android.permission.PermissionControllerManager.COUNT_WHEN_SYSTEM;
24
25import static com.android.internal.util.Preconditions.checkArgument;
26import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
27import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
28import static com.android.internal.util.Preconditions.checkFlagsArgument;
29import static com.android.internal.util.Preconditions.checkNotNull;
30import static com.android.internal.util.Preconditions.checkStringNotEmpty;
31
32import android.Manifest;
33import android.annotation.BinderThread;
34import android.annotation.NonNull;
35import android.annotation.SystemApi;
36import android.app.Service;
37import android.app.admin.DevicePolicyManager.PermissionGrantState;
38import android.content.Intent;
39import android.content.pm.PackageInfo;
40import android.content.pm.PackageManager;
41import android.os.Bundle;
42import android.os.IBinder;
43import android.os.ParcelFileDescriptor;
44import android.os.UserHandle;
45import android.permission.PermissionControllerManager.CountPermissionAppsFlag;
46import android.util.ArrayMap;
47import android.util.Log;
48
49import com.android.internal.infra.AndroidFuture;
50import com.android.internal.util.CollectionUtils;
51import com.android.internal.util.Preconditions;
52
53import java.io.FileDescriptor;
54import java.io.IOException;
55import java.io.InputStream;
56import java.io.OutputStream;
57import java.io.PrintWriter;
58import java.util.ArrayList;
59import java.util.Arrays;
60import java.util.List;
61import java.util.Map;
62import java.util.concurrent.CountDownLatch;
63import java.util.concurrent.Executor;
64import java.util.function.Consumer;
65import java.util.function.IntConsumer;
66
67/**
68 * This service is meant to be implemented by the app controlling permissions.
69 *
70 * @see PermissionControllerManager
71 *
72 * @hide
73 */
74@SystemApi
75public abstract class PermissionControllerService extends Service {
76 private static final String LOG_TAG = PermissionControllerService.class.getSimpleName();
77
78 /**
79 * The {@link Intent} action that must be declared as handled by a service
80 * in its manifest for the system to recognize it as a runtime permission
81 * presenter service.
82 */
83 public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
84
85 /**
86 * Revoke a set of runtime permissions for various apps.
87 *
88 * @param requests The permissions to revoke as {@code Map<packageName, List<permission>>}
89 * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them
90 * @param reason Why the permission should be revoked
91 * @param callerPackageName The package name of the calling app
92 * @param callback Callback waiting for the actually removed permissions as
93 * {@code Map<packageName, List<permission>>}
94 */
95 @BinderThread
96 public abstract void onRevokeRuntimePermissions(
97 @NonNull Map<String, List<String>> requests, boolean doDryRun,
98 @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName,
99 @NonNull Consumer<Map<String, List<String>>> callback);
100
101 /**
102 * Create a backup of the runtime permissions.
103 *
104 * @param user The user to back up
105 * @param backup The stream to write the backup to
106 * @param callback Callback waiting for operation to be complete
107 */
108 @BinderThread
109 public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user,
110 @NonNull OutputStream backup, @NonNull Runnable callback);
111
112
113 /**
114 * @deprecated Implement {@link #onStageAndApplyRuntimePermissionsBackup} instead
115 */
116 @Deprecated
117 @BinderThread
118 public void onRestoreRuntimePermissionsBackup(@NonNull UserHandle user,
119 @NonNull InputStream backup, @NonNull Runnable callback) {
120 }
121
122 /**
123 * Restore a backup of the runtime permissions.
124 *
125 * <p>If an app mentioned in the backup is not installed the state should be saved to later
126 * be restored via {@link #onApplyStagedRuntimePermissionBackup}.
127 *
128 * @param user The user to restore
129 * @param backup The stream to read the backup from
130 * @param callback Callback waiting for operation to be complete
131 */
132 @BinderThread
133 public void onStageAndApplyRuntimePermissionsBackup(@NonNull UserHandle user,
134 @NonNull InputStream backup, @NonNull Runnable callback) {
135 onRestoreRuntimePermissionsBackup(user, backup, callback);
136 }
137
138 /**
139 * @deprecated Implement {@link #onApplyStagedRuntimePermissionBackup} instead
140 */
141 @Deprecated
142 @BinderThread
143 public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String packageName,
144 @NonNull UserHandle user, @NonNull Consumer<Boolean> callback) {
145 }
146
147 /**
148 * Restore the permission state of an app that was provided in
149 * {@link #onStageAndApplyRuntimePermissionsBackup} but could not be restored back then.
150 *
151 * @param packageName The app to restore
152 * @param user The user to restore
153 * @param callback Callback waiting for whether there is still delayed backup left
154 */
155 @BinderThread
156 public void onApplyStagedRuntimePermissionBackup(@NonNull String packageName,
157 @NonNull UserHandle user, @NonNull Consumer<Boolean> callback) {
158 onRestoreDelayedRuntimePermissionsBackup(packageName, user, callback);
159 }
160
161 /**
162 * Gets the runtime permissions for an app.
163 *
164 * @param packageName The package for which to query.
165 * @param callback Callback waiting for the descriptions of the runtime permissions of the app
166 */
167 @BinderThread
168 public abstract void onGetAppPermissions(@NonNull String packageName,
169 @NonNull Consumer<List<RuntimePermissionPresentationInfo>> callback);
170
171 /**
172 * Revokes the permission {@code permissionName} for app {@code packageName}
173 *
174 * @param packageName The package for which to revoke
175 * @param permissionName The permission to revoke
176 * @param callback Callback waiting for operation to be complete
177 */
178 @BinderThread
179 public abstract void onRevokeRuntimePermission(@NonNull String packageName,
180 @NonNull String permissionName, @NonNull Runnable callback);
181
182 /**
183 * Count how many apps have one of a set of permissions.
184 *
185 * @param permissionNames The permissions the app might have
186 * @param flags Modify which apps to count. By default all non-system apps that request a
187 * permission are counted
188 * @param callback Callback waiting for the number of apps that have one of the permissions
189 */
190 @BinderThread
191 public abstract void onCountPermissionApps(@NonNull List<String> permissionNames,
192 @CountPermissionAppsFlag int flags, @NonNull IntConsumer callback);
193
194 /**
195 * Count how many apps have used permissions.
196 *
197 * @param countSystem Also count system apps
198 * @param numMillis The number of milliseconds in the past to check for uses
199 * @param callback Callback waiting for the descriptions of the users of permissions
200 */
201 @BinderThread
202 public abstract void onGetPermissionUsages(boolean countSystem, long numMillis,
203 @NonNull Consumer<List<RuntimePermissionUsageInfo>> callback);
204
205 /**
206 * Grant or upgrade runtime permissions. The upgrade could be performed
207 * based on whether the device upgraded, whether the permission database
208 * version is old, because the permission policy changed, or because the
209 * permission controller has updated.
210 *
211 * @param callback Callback waiting for operation to be complete
212 *
213 * @see PackageManager#isDeviceUpgrading()
214 * @see PermissionManager#getRuntimePermissionsVersion()
215 * @see PermissionManager#setRuntimePermissionsVersion(int)
216 */
217 @BinderThread
218 public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable callback);
219
220
221 /**
222 * Called by system to update the
223 * {@link PackageManager}{@code .FLAG_PERMISSION_USER_SENSITIVE_WHEN_*} flags for permissions.
224 * <p>
225 *
226 * If uid is -1, updates the permission flags for all packages.
227 *
228 * Typically called by the system when a new app is installed or updated or when creating a
229 * new user or upgrading either system or permission controller package.
230 *
231 * The callback will be executed by the provided Executor.
232 */
233 @BinderThread
234 public void onUpdateUserSensitivePermissionFlags(int uid, @NonNull Executor executor,
235 @NonNull Runnable callback) {
236 throw new AbstractMethodError("Must be overridden in implementing class");
237 }
238
239 /**
240 * Runs {@link #onUpdateUserSensitivePermissionFlags(int, Executor, Runnable)} with the main
241 * executor.
242 */
243 @BinderThread
244 public void onUpdateUserSensitivePermissionFlags(int uid, @NonNull Runnable callback) {
245 onUpdateUserSensitivePermissionFlags(uid, getMainExecutor(), callback);
246 }
247
248 /**
249 * Set the runtime permission state from a device admin.
250 *
251 * @param callerPackageName The package name of the admin requesting the change
252 * @param packageName Package the permission belongs to
253 * @param permission Permission to change
254 * @param grantState State to set the permission into
255 * @param callback Callback waiting for whether the state could be set or not
256 */
257 @BinderThread
258 public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(
259 @NonNull String callerPackageName, @NonNull String packageName,
260 @NonNull String permission, @PermissionGrantState int grantState,
261 @NonNull Consumer<Boolean> callback);
262
263 /**
264 * Called when a package is considered inactive based on the criteria given by
265 * {@link PermissionManager#startOneTimePermissionSession(String, long, int, int)}.
266 * This method is called at the end of a one-time permission session
267 *
268 * @param packageName The package that has been inactive
269 */
270 @BinderThread
271 public void onOneTimePermissionSessionTimeout(@NonNull String packageName) {
272 throw new AbstractMethodError("Must be overridden in implementing class");
273 }
274
275 @Override
276 public final @NonNull IBinder onBind(Intent intent) {
277 return new IPermissionController.Stub() {
278 @Override
279 public void revokeRuntimePermissions(
280 Bundle bundleizedRequest, boolean doDryRun, int reason,
281 String callerPackageName, AndroidFuture callback) {
282 checkNotNull(bundleizedRequest, "bundleizedRequest");
283 checkNotNull(callerPackageName);
284 checkNotNull(callback);
285
286 Map<String, List<String>> request = new ArrayMap<>();
287 for (String packageName : bundleizedRequest.keySet()) {
288 Preconditions.checkNotNull(packageName);
289
290 ArrayList<String> permissions =
291 bundleizedRequest.getStringArrayList(packageName);
292 Preconditions.checkCollectionElementsNotNull(permissions, "permissions");
293
294 request.put(packageName, permissions);
295 }
296
297 enforceSomePermissionsGrantedToCaller(
298 Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
299
300 // Verify callerPackageName
301 try {
302 PackageInfo pkgInfo = getPackageManager().getPackageInfo(callerPackageName, 0);
303 checkArgument(getCallingUid() == pkgInfo.applicationInfo.uid);
304 } catch (PackageManager.NameNotFoundException e) {
305 throw new RuntimeException(e);
306 }
307
308 onRevokeRuntimePermissions(request,
309 doDryRun, reason, callerPackageName, revoked -> {
310 CollectionUtils.forEach(revoked, (pkg, perms) -> {
311 Preconditions.checkNotNull(pkg);
312 Preconditions.checkCollectionElementsNotNull(perms, "permissions");
313 });
314 callback.complete(revoked);
315 });
316 }
317
318 /**
319 * Throw a {@link SecurityException} if not at least one of the permissions is granted.
320 *
321 * @param requiredPermissions A list of permissions. Any of of them if sufficient to
322 * pass the check
323 */
324 private void enforceSomePermissionsGrantedToCaller(
325 @NonNull String... requiredPermissions) {
326 for (String requiredPermission : requiredPermissions) {
327 if (checkCallingPermission(requiredPermission)
328 == PackageManager.PERMISSION_GRANTED) {
329 return;
330 }
331 }
332
333 throw new SecurityException(
334 "At lest one of the following permissions is required: " + Arrays.toString(
335 requiredPermissions));
336 }
337
338
339 @Override
340 public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
341 checkNotNull(user);
342 checkNotNull(pipe);
343
344 enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
345
346 try (OutputStream backup = new ParcelFileDescriptor.AutoCloseOutputStream(pipe)) {
347 CountDownLatch latch = new CountDownLatch(1);
348 onGetRuntimePermissionsBackup(user, backup, latch::countDown);
349 latch.await();
350 } catch (IOException e) {
351 Log.e(LOG_TAG, "Could not open pipe to write backup to", e);
352 } catch (InterruptedException e) {
353 Log.e(LOG_TAG, "getRuntimePermissionBackup timed out", e);
354 }
355 }
356
357 @Override
358 public void stageAndApplyRuntimePermissionsBackup(UserHandle user,
359 ParcelFileDescriptor pipe) {
360 checkNotNull(user);
361 checkNotNull(pipe);
362
363 enforceSomePermissionsGrantedToCaller(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
364 Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
365
366 try (InputStream backup = new ParcelFileDescriptor.AutoCloseInputStream(pipe)) {
367 CountDownLatch latch = new CountDownLatch(1);
368 onStageAndApplyRuntimePermissionsBackup(user, backup, latch::countDown);
369 latch.await();
370 } catch (IOException e) {
371 Log.e(LOG_TAG, "Could not open pipe to read backup from", e);
372 } catch (InterruptedException e) {
373 Log.e(LOG_TAG, "restoreRuntimePermissionBackup timed out", e);
374 }
375 }
376
377 @Override
378 public void applyStagedRuntimePermissionBackup(String packageName, UserHandle user,
379 AndroidFuture callback) {
380 checkNotNull(packageName);
381 checkNotNull(user);
382 checkNotNull(callback);
383
384 enforceSomePermissionsGrantedToCaller(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
385 Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
386
387 onApplyStagedRuntimePermissionBackup(packageName, user, callback::complete);
388 }
389
390 @Override
391 public void getAppPermissions(String packageName, AndroidFuture callback) {
392 checkNotNull(packageName, "packageName");
393 checkNotNull(callback, "callback");
394
395 enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
396
397 onGetAppPermissions(packageName, callback::complete);
398 }
399
400 @Override
401 public void revokeRuntimePermission(String packageName, String permissionName) {
402 checkNotNull(packageName, "packageName");
403 checkNotNull(permissionName, "permissionName");
404
405 enforceSomePermissionsGrantedToCaller(
406 Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
407
408 CountDownLatch latch = new CountDownLatch(1);
409 PermissionControllerService.this.onRevokeRuntimePermission(packageName,
410 permissionName, latch::countDown);
411 try {
412 latch.await();
413 } catch (InterruptedException e) {
414 Log.e(LOG_TAG, "revokeRuntimePermission timed out", e);
415 }
416 }
417
418 @Override
419 public void countPermissionApps(List<String> permissionNames, int flags,
420 AndroidFuture callback) {
421 checkCollectionElementsNotNull(permissionNames, "permissionNames");
422 checkFlagsArgument(flags, COUNT_WHEN_SYSTEM | COUNT_ONLY_WHEN_GRANTED);
423 checkNotNull(callback, "callback");
424
425 enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
426
427 onCountPermissionApps(permissionNames, flags, callback::complete);
428 }
429
430 @Override
431 public void getPermissionUsages(boolean countSystem, long numMillis,
432 AndroidFuture callback) {
433 checkArgumentNonnegative(numMillis);
434 checkNotNull(callback, "callback");
435
436 enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
437
438 onGetPermissionUsages(countSystem, numMillis, callback::complete);
439 }
440
441 @Override
442 public void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName,
443 String packageName, String permission, int grantState,
444 AndroidFuture callback) {
445 checkStringNotEmpty(callerPackageName);
446 checkStringNotEmpty(packageName);
447 checkStringNotEmpty(permission);
448 checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED
449 || grantState == PERMISSION_GRANT_STATE_DENIED
450 || grantState == PERMISSION_GRANT_STATE_DEFAULT);
451 checkNotNull(callback);
452
453 if (grantState == PERMISSION_GRANT_STATE_DENIED) {
454 enforceSomePermissionsGrantedToCaller(
455 Manifest.permission.GRANT_RUNTIME_PERMISSIONS);
456 }
457
458 if (grantState == PERMISSION_GRANT_STATE_DENIED) {
459 enforceSomePermissionsGrantedToCaller(
460 Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
461 }
462
463 enforceSomePermissionsGrantedToCaller(
464 Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
465
466 onSetRuntimePermissionGrantStateByDeviceAdmin(callerPackageName,
467 packageName, permission, grantState, callback::complete);
468 }
469
470 @Override
471 public void grantOrUpgradeDefaultRuntimePermissions(@NonNull AndroidFuture callback) {
472 checkNotNull(callback, "callback");
473
474 enforceSomePermissionsGrantedToCaller(
475 Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
476
477 onGrantOrUpgradeDefaultRuntimePermissions(() -> callback.complete(true));
478 }
479
480 @Override
481 public void updateUserSensitiveForApp(int uid, @NonNull AndroidFuture callback) {
482 Preconditions.checkNotNull(callback, "callback cannot be null");
483
484 try {
485 onUpdateUserSensitivePermissionFlags(uid, () -> callback.complete(null));
486 } catch (Exception e) {
487 callback.completeExceptionally(e);
488 }
489 }
490
491 @Override
492 public void notifyOneTimePermissionSessionTimeout(String packageName) {
493 enforceSomePermissionsGrantedToCaller(
494 Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
495 packageName = Preconditions.checkNotNull(packageName,
496 "packageName cannot be null");
497 onOneTimePermissionSessionTimeout(packageName);
498 }
499
500 @Override
501 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
502 checkNotNull(fd, "fd");
503 checkNotNull(writer, "writer");
504
505 enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
506
507 PermissionControllerService.this.dump(fd, writer, args);
508 }
509 };
510 }
511}