summaryrefslogtreecommitdiff
path: root/core/java/android/permission/PermissionControllerService.java
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2018-12-17 20:45:40 -0800
committerPhilip P. Moltmann <moltmann@google.com>2019-01-06 17:51:33 -0800
commit7868952db36a35b5266bb4da4e983cc47b9c5331 (patch)
tree2cd1e09811f9251c8248c1583aa1d46839e40d95 /core/java/android/permission/PermissionControllerService.java
parentbbb539a172db58089d93332ec28790e3b2af6018 (diff)
Allow apps to bulk revoke permissions with the correct semantics
Test: atest --test-mapping frameworks/base/core/java/android/permission/:presubmit Fixes: 120269238 Change-Id: Ib9eb244f1c89c09eee1f39e3abb65c1189f7a6f4
Diffstat (limited to 'core/java/android/permission/PermissionControllerService.java')
-rw-r--r--core/java/android/permission/PermissionControllerService.java78
1 files changed, 78 insertions, 0 deletions
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 5dad07178e53..f621737e5ed4 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -16,6 +16,7 @@
package android.permission;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -26,12 +27,19 @@ import android.annotation.SystemApi;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteCallback;
+import android.util.ArrayMap;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* This service is meant to be implemented by the app controlling permissions.
@@ -60,6 +68,20 @@ public abstract class PermissionControllerService extends Service {
}
/**
+ * Revoke a set of runtime permissions for various apps.
+ *
+ * @param requests The permissions to revoke as {@code Map<packageName, List<permission>>}
+ * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them
+ * @param reason Why the permission should be revoked
+ * @param callerPackageName The package name of the calling app
+ *
+ * @return the actually removed permissions as {@code Map<packageName, List<permission>>}
+ */
+ public abstract @NonNull Map<String, List<String>> onRevokeRuntimePermissions(
+ @NonNull Map<String, List<String>> requests, boolean doDryRun,
+ @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName);
+
+ /**
* Gets the runtime permissions for an app.
*
* @param packageName The package for which to query.
@@ -94,6 +116,41 @@ public abstract class PermissionControllerService extends Service {
public final IBinder onBind(Intent intent) {
return new IPermissionController.Stub() {
@Override
+ public void revokeRuntimePermissions(
+ Bundle bundleizedRequest, boolean doDryRun, int reason,
+ String callerPackageName, RemoteCallback callback) {
+ checkNotNull(bundleizedRequest, "bundleizedRequest");
+ checkNotNull(callerPackageName);
+ checkNotNull(callback);
+
+ Map<String, List<String>> request = new ArrayMap<>();
+ for (String packageName : bundleizedRequest.keySet()) {
+ Preconditions.checkNotNull(packageName);
+
+ ArrayList<String> permissions =
+ bundleizedRequest.getStringArrayList(packageName);
+ Preconditions.checkCollectionElementsNotNull(permissions, "permissions");
+
+ request.put(packageName, permissions);
+ }
+
+ enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+
+ // Verify callerPackageName
+ try {
+ PackageInfo pkgInfo = getPackageManager().getPackageInfo(callerPackageName, 0);
+ checkArgument(getCallingUid() == pkgInfo.applicationInfo.uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+
+ mHandler.sendMessage(obtainMessage(
+ PermissionControllerService::revokeRuntimePermissions,
+ PermissionControllerService.this, request, doDryRun, reason,
+ callerPackageName, callback));
+ }
+
+ @Override
public void getAppPermissions(String packageName, RemoteCallback callback) {
checkNotNull(packageName, "packageName");
checkNotNull(callback, "callback");
@@ -133,6 +190,27 @@ public abstract class PermissionControllerService extends Service {
};
}
+ private void revokeRuntimePermissions(@NonNull Map<String, List<String>> requests,
+ boolean doDryRun, @PermissionControllerManager.Reason int reason,
+ @NonNull String callerPackageName, @NonNull RemoteCallback callback) {
+ Map<String, List<String>> revoked = onRevokeRuntimePermissions(requests,
+ doDryRun, reason, callerPackageName);
+
+ checkNotNull(revoked);
+ Bundle bundledizedRevoked = new Bundle();
+ for (Map.Entry<String, List<String>> appRevocation : revoked.entrySet()) {
+ checkNotNull(appRevocation.getKey());
+ checkCollectionElementsNotNull(appRevocation.getValue(), "permissions");
+
+ bundledizedRevoked.putStringArrayList(appRevocation.getKey(),
+ new ArrayList<>(appRevocation.getValue()));
+ }
+
+ Bundle result = new Bundle();
+ result.putBundle(PermissionControllerManager.KEY_RESULT, bundledizedRevoked);
+ callback.sendResult(result);
+ }
+
private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) {
List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
if (permissions != null && !permissions.isEmpty()) {