summaryrefslogtreecommitdiff
path: root/core/java/android/permission/PermissionControllerManager.java
diff options
context:
space:
mode:
authorEugene Susla <eugenesusla@google.com>2019-05-07 18:30:48 -0700
committerEugene Susla <eugenesusla@google.com>2019-05-13 18:56:00 -0700
commitbe4e3af8528fbd16457757b96372e674d25c4204 (patch)
tree7bc4ea346d8942d4b5366ef22f574abb189fb5a9 /core/java/android/permission/PermissionControllerManager.java
parent15b601425213887dde2cdbdd2641d0d9fd8259a1 (diff)
Migrate PermissionControllerManager to ServiceConnector
Test: - atest --test-mapping core/java/com/android/internal/infra - m -j CtsBackupHostTestCases && atest android.backup.cts.PermissionTest Change-Id: I6a590194207d08569f41f3c5ac6d56e63737feaa
Diffstat (limited to 'core/java/android/permission/PermissionControllerManager.java')
-rw-r--r--core/java/android/permission/PermissionControllerManager.java990
1 files changed, 203 insertions, 787 deletions
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 6e83e5a1f8b6..de0bcb628f5e 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -28,8 +28,6 @@ import static com.android.internal.util.Preconditions.checkFlagsArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkStringNotEmpty;
-import static java.lang.Math.min;
-
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -41,41 +39,35 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.app.admin.DevicePolicyManager.PermissionGrantState;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
import android.os.RemoteCallback;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
-import com.android.internal.infra.AbstractRemoteService;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.RemoteStream;
+import com.android.internal.infra.ServiceConnector;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.Preconditions;
-import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -90,14 +82,17 @@ import java.util.function.Consumer;
public final class PermissionControllerManager {
private static final String TAG = PermissionControllerManager.class.getSimpleName();
+ private static final long UNBIND_TIMEOUT_MILLIS = 10000;
+ private static final int CHUNK_SIZE = 4 * 1024;
+
private static final Object sLock = new Object();
/**
* Global remote services (per user) used by all {@link PermissionControllerManager managers}
*/
@GuardedBy("sLock")
- private static ArrayMap<Pair<Integer, Thread>, RemoteService> sRemoteServices
- = new ArrayMap<>(1);
+ private static ArrayMap<Pair<Integer, Thread>, ServiceConnector<IPermissionController>>
+ sRemoteServices = new ArrayMap<>(1);
/**
* The key for retrieving the result from the returned bundle.
@@ -213,7 +208,8 @@ public final class PermissionControllerManager {
}
private final @NonNull Context mContext;
- private final @NonNull RemoteService mRemoteService;
+ private final @NonNull ServiceConnector<IPermissionController> mRemoteService;
+ private final @NonNull Handler mHandler;
/**
* Create a new {@link PermissionControllerManager}.
@@ -227,15 +223,28 @@ public final class PermissionControllerManager {
synchronized (sLock) {
Pair<Integer, Thread> key = new Pair<>(context.getUserId(),
handler.getLooper().getThread());
- RemoteService remoteService = sRemoteServices.get(key);
+ ServiceConnector<IPermissionController> remoteService = sRemoteServices.get(key);
if (remoteService == null) {
Intent intent = new Intent(SERVICE_INTERFACE);
intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
+ remoteService = new ServiceConnector.Impl<IPermissionController>(
+ ActivityThread.currentApplication() /* context */,
+ new Intent(SERVICE_INTERFACE)
+ .setComponent(serviceInfo.getComponentInfo().getComponentName()),
+ 0 /* bindingFlags */, context.getUserId(),
+ IPermissionController.Stub::asInterface) {
+
+ @Override
+ protected Handler getJobHandler() {
+ return handler;
+ }
- remoteService = new RemoteService(ActivityThread.currentApplication(),
- serviceInfo.getComponentInfo().getComponentName(), handler,
- context.getUser());
+ @Override
+ protected long getAutoDisconnectTimeoutMs() {
+ return UNBIND_TIMEOUT_MILLIS;
+ }
+ };
sRemoteServices.put(key, remoteService);
}
@@ -243,6 +252,7 @@ public final class PermissionControllerManager {
}
mContext = context;
+ mHandler = handler;
}
/**
@@ -274,8 +284,46 @@ public final class PermissionControllerManager {
+ " required");
}
- mRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(mRemoteService,
- request, doDryRun, reason, mContext.getPackageName(), executor, callback));
+ mRemoteService.postAsync(service -> {
+ Bundle bundledizedRequest = new Bundle();
+ for (Map.Entry<String, List<String>> appRequest : request.entrySet()) {
+ bundledizedRequest.putStringArrayList(appRequest.getKey(),
+ new ArrayList<>(appRequest.getValue()));
+ }
+
+ AndroidFuture<Bundle> revokeRuntimePermissionsResult = new AndroidFuture<>();
+ service.revokeRuntimePermissions(bundledizedRequest, doDryRun, reason,
+ mContext.getPackageName(),
+ new RemoteCallback(revokeRuntimePermissionsResult::complete));
+ return revokeRuntimePermissionsResult;
+ }).thenApply(revokeRuntimePermissionsResult -> {
+ Map<String, List<String>> revoked = new ArrayMap<>();
+ Bundle bundleizedRevoked = revokeRuntimePermissionsResult.getBundle(KEY_RESULT);
+
+ for (String packageName : bundleizedRevoked.keySet()) {
+ Preconditions.checkNotNull(packageName);
+
+ ArrayList<String> permissions =
+ bundleizedRevoked.getStringArrayList(packageName);
+ Preconditions.checkCollectionElementsNotNull(permissions,
+ "permissions");
+
+ revoked.put(packageName, permissions);
+ }
+ return revoked;
+ }).whenCompleteAsync((revoked, err) -> {
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (err != null) {
+ Log.e(TAG, "Failure when revoking runtime permissions", err);
+ callback.onRevokeRuntimePermissions(Collections.emptyMap());
+ } else {
+ callback.onRevokeRuntimePermissions(revoked);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }, executor);
}
/**
@@ -307,9 +355,28 @@ public final class PermissionControllerManager {
checkNotNull(executor);
checkNotNull(callback);
- mRemoteService.scheduleRequest(new PendingSetRuntimePermissionGrantStateByDeviceAdmin(
- mRemoteService, callerPackageName, packageName, permission, grantState, executor,
- callback));
+ mRemoteService.postAsync(service -> {
+ CompletableFuture<Bundle> setRuntimePermissionGrantStateResult =
+ new CompletableFuture<>();
+ service.setRuntimePermissionGrantStateByDeviceAdmin(
+ callerPackageName, packageName, permission, grantState,
+ new RemoteCallback(setRuntimePermissionGrantStateResult::complete));
+ return setRuntimePermissionGrantStateResult;
+ }).whenCompleteAsync((setRuntimePermissionGrantStateResult, err) -> {
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (err != null) {
+ Log.e(TAG, "Error setting permissions state for device admin " + packageName,
+ err);
+ callback.accept(false);
+ } else {
+ callback.accept(
+ setRuntimePermissionGrantStateResult.getBoolean(KEY_RESULT, false));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }, executor);
}
/**
@@ -329,8 +396,16 @@ public final class PermissionControllerManager {
checkNotNull(executor);
checkNotNull(callback);
- mRemoteService.scheduleRequest(new PendingGetRuntimePermissionBackup(mRemoteService,
- user, executor, callback));
+ mRemoteService.postAsync(service -> RemoteStream.receiveBytes(remotePipe -> {
+ service.getRuntimePermissionBackup(user, remotePipe);
+ })).whenCompleteAsync((bytes, err) -> {
+ if (err != null) {
+ Log.e(TAG, "Error getting permission backup", err);
+ callback.onGetRuntimePermissionsBackup(EmptyArray.BYTE);
+ } else {
+ callback.onGetRuntimePermissionsBackup(bytes);
+ }
+ }, executor);
}
/**
@@ -347,8 +422,14 @@ public final class PermissionControllerManager {
checkNotNull(backup);
checkNotNull(user);
- mRemoteService.scheduleAsyncRequest(
- new PendingRestoreRuntimePermissionBackup(mRemoteService, backup, user));
+ mRemoteService.postAsync(service -> RemoteStream.sendBytes(remotePipe -> {
+ service.restoreRuntimePermissionBackup(user, remotePipe);
+ }, backup))
+ .whenComplete((nullResult, err) -> {
+ if (err != null) {
+ Log.e(TAG, "Error sending permission backup", err);
+ }
+ });
}
/**
@@ -371,9 +452,27 @@ public final class PermissionControllerManager {
checkNotNull(executor);
checkNotNull(callback);
- mRemoteService.scheduleRequest(
- new PendingRestoreDelayedRuntimePermissionBackup(mRemoteService, packageName,
- user, executor, callback));
+ mRemoteService.postAsync(service -> {
+ CompletableFuture<Bundle> restoreDelayedRuntimePermissionBackupResult =
+ new CompletableFuture<>();
+ service.restoreDelayedRuntimePermissionBackup(packageName, user,
+ new RemoteCallback(restoreDelayedRuntimePermissionBackupResult::complete));
+ return restoreDelayedRuntimePermissionBackupResult;
+ }).whenCompleteAsync((restoreDelayedRuntimePermissionBackupResult, err) -> {
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (err != null) {
+ Log.e(TAG, "Error restoring delayed permissions for " + packageName, err);
+ callback.accept(true);
+ } else {
+ callback.accept(
+ restoreDelayedRuntimePermissionBackupResult
+ .getBoolean(KEY_RESULT, false));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }, executor);
}
/**
@@ -390,9 +489,25 @@ public final class PermissionControllerManager {
@NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) {
checkNotNull(packageName);
checkNotNull(callback);
-
- mRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(mRemoteService,
- packageName, callback, handler == null ? mRemoteService.getHandler() : handler));
+ Handler finalHandler = handler != null ? handler : mHandler;
+
+ mRemoteService.postAsync(service -> {
+ CompletableFuture<Bundle> getAppPermissionsResult = new CompletableFuture<>();
+ service.getAppPermissions(packageName,
+ new RemoteCallback(getAppPermissionsResult::complete));
+ return getAppPermissionsResult;
+ }).whenComplete((getAppPermissionsResult, err) -> finalHandler.post(() -> {
+ if (err != null) {
+ Log.e(TAG, "Error getting app permission", err);
+ callback.onGetAppPermissions(Collections.emptyList());
+ } else {
+ List<RuntimePermissionPresentationInfo> permissions = null;
+ if (getAppPermissionsResult != null) {
+ permissions = getAppPermissionsResult.getParcelableArrayList(KEY_RESULT);
+ }
+ callback.onGetAppPermissions(CollectionUtils.emptyIfNull(permissions));
+ }
+ }));
}
/**
@@ -409,8 +524,7 @@ public final class PermissionControllerManager {
checkNotNull(packageName);
checkNotNull(permissionName);
- mRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName,
- permissionName));
+ mRemoteService.run(service -> service.revokeRuntimePermission(packageName, permissionName));
}
/**
@@ -431,10 +545,23 @@ public final class PermissionControllerManager {
checkCollectionElementsNotNull(permissionNames, "permissionNames");
checkFlagsArgument(flags, COUNT_WHEN_SYSTEM | COUNT_ONLY_WHEN_GRANTED);
checkNotNull(callback);
-
- mRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(mRemoteService,
- permissionNames, flags, callback,
- handler == null ? mRemoteService.getHandler() : handler));
+ Handler finalHandler = handler != null ? handler : mHandler;
+
+ mRemoteService.postAsync(service -> {
+ CompletableFuture<Bundle> countPermissionAppsResult = new CompletableFuture<>();
+ service.countPermissionApps(permissionNames, flags,
+ new RemoteCallback(countPermissionAppsResult::complete));
+ return countPermissionAppsResult;
+ }).whenComplete((countPermissionAppsResult, err) -> finalHandler.post(() -> {
+ if (err != null) {
+ Log.e(TAG, "Error counting permission apps", err);
+ callback.onCountPermissionApps(0);
+ } else {
+ callback.onCountPermissionApps(countPermissionAppsResult != null
+ ? countPermissionAppsResult.getInt(KEY_RESULT)
+ : 0);
+ }
+ }));
}
/**
@@ -455,8 +582,27 @@ public final class PermissionControllerManager {
checkNotNull(executor);
checkNotNull(callback);
- mRemoteService.scheduleRequest(new PendingGetPermissionUsagesRequest(mRemoteService,
- countSystem, numMillis, executor, callback));
+
+ mRemoteService.postAsync(service -> {
+ CompletableFuture<Bundle> getPermissionUsagesResult = new CompletableFuture<>();
+ service.getPermissionUsages(countSystem, numMillis,
+ new RemoteCallback(getPermissionUsagesResult::complete));
+ return getPermissionUsagesResult;
+ }).whenCompleteAsync((getPermissionUsagesResult, err) -> {
+ if (err != null) {
+ Log.e(TAG, "Error getting permission usages", err);
+ callback.onPermissionUsageResult(Collections.emptyList());
+ } else {
+ long token = Binder.clearCallingIdentity();
+ try {
+ callback.onPermissionUsageResult(getPermissionUsagesResult != null
+ ? getPermissionUsagesResult.getParcelableArrayList(KEY_RESULT)
+ : Collections.emptyList());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }, executor);
}
/**
@@ -472,749 +618,19 @@ public final class PermissionControllerManager {
@RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY)
public void grantOrUpgradeDefaultRuntimePermissions(
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
- mRemoteService.scheduleRequest(new PendingGrantOrUpgradeDefaultRuntimePermissionsRequest(
- mRemoteService, executor, callback));
- }
-
- /**
- * A connection to the remote service
- */
- static final class RemoteService extends
- AbstractMultiplePendingRequestsRemoteService<RemoteService, IPermissionController> {
- private static final long UNBIND_TIMEOUT_MILLIS = 10000;
- private static final long MESSAGE_TIMEOUT_MILLIS = 30000;
-
- /**
- * Create a connection to the remote service
- *
- * @param context A context to use
- * @param componentName The component of the service to connect to
- * @param user User the remote service should be connected as
- */
- RemoteService(@NonNull Context context, @NonNull ComponentName componentName,
- @NonNull Handler handler, @NonNull UserHandle user) {
- super(context, SERVICE_INTERFACE, componentName, user.getIdentifier(),
- service -> Log.e(TAG, "RemoteService " + service + " died"),
- handler, 0, false, 1);
- }
-
- /**
- * @return The default handler used by this service.
- */
- Handler getHandler() {
- return mHandler;
- }
-
- @Override
- protected @NonNull IPermissionController getServiceInterface(@NonNull IBinder binder) {
- return IPermissionController.Stub.asInterface(binder);
- }
-
- @Override
- protected long getTimeoutIdleBindMillis() {
- return UNBIND_TIMEOUT_MILLIS;
- }
-
- @Override
- protected long getRemoteRequestMillis() {
- return MESSAGE_TIMEOUT_MILLIS;
- }
-
- @Override
- public void scheduleRequest(@NonNull BasePendingRequest<RemoteService,
- IPermissionController> pendingRequest) {
- super.scheduleRequest(pendingRequest);
- }
-
- @Override
- public void scheduleAsyncRequest(@NonNull AsyncRequest<IPermissionController> request) {
- super.scheduleAsyncRequest(request);
- }
- }
-
- /**
- * Task to read a large amount of data from a remote service.
- */
- private static class FileReaderTask<Callback extends Consumer<byte[]>>
- extends AsyncTask<Void, Void, byte[]> {
- private ParcelFileDescriptor mLocalPipe;
- private ParcelFileDescriptor mRemotePipe;
-
- private final @NonNull Callback mCallback;
-
- FileReaderTask(@NonNull Callback callback) {
- mCallback = callback;
- }
-
- @Override
- protected void onPreExecute() {
- ParcelFileDescriptor[] pipe;
- try {
- pipe = ParcelFileDescriptor.createPipe();
- } catch (IOException e) {
- Log.e(TAG, "Could not create pipe needed to get runtime permission backup", e);
- return;
- }
-
- mLocalPipe = pipe[0];
- mRemotePipe = pipe[1];
- }
-
- /**
- * Get the file descriptor the remote service should write the data to.
- *
- * <p>Needs to be closed <u>locally</u> before the FileReader can finish.
- *
- * @return The file the data should be written to
- */
- ParcelFileDescriptor getRemotePipe() {
- return mRemotePipe;
- }
-
- @Override
- protected byte[] doInBackground(Void... ignored) {
- ByteArrayOutputStream combinedBuffer = new ByteArrayOutputStream();
-
- try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(mLocalPipe)) {
- byte[] buffer = new byte[16 * 1024];
-
- while (!isCancelled()) {
- int numRead = in.read(buffer);
- if (numRead == -1) {
- break;
- }
-
- combinedBuffer.write(buffer, 0, numRead);
- }
- } catch (IOException | NullPointerException e) {
- Log.e(TAG, "Error reading runtime permission backup", e);
- combinedBuffer.reset();
- }
-
- return combinedBuffer.toByteArray();
- }
-
- /**
- * Interrupt the reading of the data.
- *
- * <p>Needs to be called when canceling this task as it might be hung.
- */
- void interruptRead() {
- IoUtils.closeQuietly(mLocalPipe);
- }
-
- @Override
- protected void onCancelled() {
- onPostExecute(new byte[]{});
- }
-
- @Override
- protected void onPostExecute(byte[] backup) {
- IoUtils.closeQuietly(mLocalPipe);
- mCallback.accept(backup);
- }
- }
-
- /**
- * Task to send a large amount of data to a remote service.
- */
- private static class FileWriterTask extends AsyncTask<byte[], Void, Void> {
- private static final int CHUNK_SIZE = 4 * 1024;
-
- private ParcelFileDescriptor mLocalPipe;
- private ParcelFileDescriptor mRemotePipe;
-
- @Override
- protected void onPreExecute() {
- ParcelFileDescriptor[] pipe;
- try {
- pipe = ParcelFileDescriptor.createPipe();
- } catch (IOException e) {
- Log.e(TAG, "Could not create pipe needed to send runtime permission backup",
- e);
- return;
- }
-
- mRemotePipe = pipe[0];
- mLocalPipe = pipe[1];
- }
-
- /**
- * Get the file descriptor the remote service should read the data from.
- *
- * @return The file the data should be read from
- */
- ParcelFileDescriptor getRemotePipe() {
- return mRemotePipe;
- }
-
- /**
- * Send the data to the remove service.
- *
- * @param in The data to send
- *
- * @return ignored
- */
- @Override
- protected Void doInBackground(byte[]... in) {
- byte[] buffer = in[0];
- try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(mLocalPipe)) {
- for (int offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {
- out.write(buffer, offset, min(CHUNK_SIZE, buffer.length - offset));
- }
- } catch (IOException | NullPointerException e) {
- Log.e(TAG, "Error sending runtime permission backup", e);
- }
-
- return null;
- }
-
- /**
- * Interrupt the send of the data.
- *
- * <p>Needs to be called when canceling this task as it might be hung.
- */
- void interruptWrite() {
- IoUtils.closeQuietly(mLocalPipe);
- }
-
- @Override
- protected void onCancelled() {
- onPostExecute(null);
- }
-
- @Override
- protected void onPostExecute(Void ignored) {
- IoUtils.closeQuietly(mLocalPipe);
- }
- }
-
- /**
- * Request for {@link #revokeRuntimePermissions}
- */
- private static final class PendingRevokeRuntimePermissionRequest extends
- AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
- private final @NonNull Map<String, List<String>> mRequest;
- private final boolean mDoDryRun;
- private final int mReason;
- private final @NonNull String mCallingPackage;
- private final @NonNull Executor mExecutor;
- private final @NonNull OnRevokeRuntimePermissionsCallback mCallback;
-
- private final @NonNull RemoteCallback mRemoteCallback;
-
- private PendingRevokeRuntimePermissionRequest(@NonNull RemoteService service,
- @NonNull Map<String, List<String>> request, boolean doDryRun,
- @Reason int reason, @NonNull String callingPackage,
- @NonNull @CallbackExecutor Executor executor,
- @NonNull OnRevokeRuntimePermissionsCallback callback) {
- super(service);
-
- mRequest = request;
- mDoDryRun = doDryRun;
- mReason = reason;
- mCallingPackage = callingPackage;
- mExecutor = executor;
- mCallback = callback;
-
- mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
- long token = Binder.clearCallingIdentity();
- try {
- Map<String, List<String>> revoked = new ArrayMap<>();
- try {
- Bundle bundleizedRevoked = result.getBundle(KEY_RESULT);
-
- for (String packageName : bundleizedRevoked.keySet()) {
- Preconditions.checkNotNull(packageName);
-
- ArrayList<String> permissions =
- bundleizedRevoked.getStringArrayList(packageName);
- Preconditions.checkCollectionElementsNotNull(permissions,
- "permissions");
-
- revoked.put(packageName, permissions);
- }
- } catch (Exception e) {
- Log.e(TAG, "Could not read result when revoking runtime permissions", e);
- }
-
- callback.onRevokeRuntimePermissions(revoked);
- } finally {
- Binder.restoreCallingIdentity(token);
-
- finish();
- }
- }), null);
- }
-
- @Override
- protected void onTimeout(RemoteService remoteService) {
- long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(
- () -> mCallback.onRevokeRuntimePermissions(Collections.emptyMap()));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void run() {
- Bundle bundledizedRequest = new Bundle();
- for (Map.Entry<String, List<String>> appRequest : mRequest.entrySet()) {
- bundledizedRequest.putStringArrayList(appRequest.getKey(),
- new ArrayList<>(appRequest.getValue()));
- }
-
- try {
- getService().getServiceInterface().revokeRuntimePermissions(bundledizedRequest,
- mDoDryRun, mReason, mCallingPackage, mRemoteCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Error revoking runtime permission", e);
- }
- }
- }
-
- /**
- * Request for {@link #getRuntimePermissionBackup}
- */
- private static final class PendingGetRuntimePermissionBackup extends
- AbstractRemoteService.PendingRequest<RemoteService, IPermissionController>
- implements Consumer<byte[]> {
- private final @NonNull FileReaderTask<PendingGetRuntimePermissionBackup> mBackupReader;
- private final @NonNull Executor mExecutor;
- private final @NonNull OnGetRuntimePermissionBackupCallback mCallback;
- private final @NonNull UserHandle mUser;
-
- private PendingGetRuntimePermissionBackup(@NonNull RemoteService service,
- @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor,
- @NonNull OnGetRuntimePermissionBackupCallback callback) {
- super(service);
-
- mUser = user;
- mExecutor = executor;
- mCallback = callback;
-
- mBackupReader = new FileReaderTask<>(this);
- }
-
- @Override
- protected void onTimeout(RemoteService remoteService) {
- mBackupReader.cancel(true);
- mBackupReader.interruptRead();
- }
-
- @Override
- public void run() {
- mBackupReader.execute();
-
- ParcelFileDescriptor remotePipe = mBackupReader.getRemotePipe();
- try {
- getService().getServiceInterface().getRuntimePermissionBackup(mUser, remotePipe);
- } catch (RemoteException e) {
- Log.e(TAG, "Error getting runtime permission backup", e);
- } finally {
- // Remote pipe end is duped by binder call. Local copy is not needed anymore
- IoUtils.closeQuietly(remotePipe);
- }
- }
-
- /**
- * Called when the {@link #mBackupReader} finished reading the file.
- *
- * @param backup The data read
- */
- @Override
- public void accept(byte[] backup) {
- long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onGetRuntimePermissionsBackup(backup));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- finish();
- }
- }
-
- /**
- * Request for {@link #getRuntimePermissionBackup}
- */
- private static final class PendingSetRuntimePermissionGrantStateByDeviceAdmin extends
- AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
- private final @NonNull String mCallerPackageName;
- private final @NonNull String mPackageName;
- private final @NonNull String mPermission;
- private final @PermissionGrantState int mGrantState;
-
- private final @NonNull Executor mExecutor;
- private final @NonNull Consumer<Boolean> mCallback;
- private final @NonNull RemoteCallback mRemoteCallback;
-
- private PendingSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull RemoteService service,
- @NonNull String callerPackageName, @NonNull String packageName,
- @NonNull String permission, @PermissionGrantState int grantState,
- @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
- super(service);
-
- mCallerPackageName = callerPackageName;
- mPackageName = packageName;
- mPermission = permission;
- mGrantState = grantState;
- mExecutor = executor;
- mCallback = callback;
-
- mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
- long token = Binder.clearCallingIdentity();
- try {
- callback.accept(result.getBoolean(KEY_RESULT, false));
- } finally {
- Binder.restoreCallingIdentity(token);
-
- finish();
- }
- }), null);
- }
-
- @Override
- protected void onTimeout(RemoteService remoteService) {
- long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.accept(false));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void run() {
- try {
- getService().getServiceInterface().setRuntimePermissionGrantStateByDeviceAdmin(
- mCallerPackageName, mPackageName, mPermission, mGrantState, mRemoteCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Error setting permissions state for device admin " + mPackageName,
- e);
- }
- }
- }
-
- /**
- * Request for {@link #restoreRuntimePermissionBackup}
- */
- private static final class PendingRestoreRuntimePermissionBackup implements
- AbstractRemoteService.AsyncRequest<IPermissionController> {
- private final @NonNull FileWriterTask mBackupSender;
- private final @NonNull byte[] mBackup;
- private final @NonNull UserHandle mUser;
-
- private PendingRestoreRuntimePermissionBackup(@NonNull RemoteService service,
- @NonNull byte[] backup, @NonNull UserHandle user) {
- mBackup = backup;
- mUser = user;
-
- mBackupSender = new FileWriterTask();
- }
-
- @Override
- public void run(@NonNull IPermissionController service) {
- mBackupSender.execute(mBackup);
-
- ParcelFileDescriptor remotePipe = mBackupSender.getRemotePipe();
- try {
- service.restoreRuntimePermissionBackup(mUser, remotePipe);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending runtime permission backup", e);
- mBackupSender.cancel(false);
- mBackupSender.interruptWrite();
- } finally {
- // Remote pipe end is duped by binder call. Local copy is not needed anymore
- IoUtils.closeQuietly(remotePipe);
- }
- }
- }
-
- /**
- * Request for {@link #restoreDelayedRuntimePermissionBackup(String, UserHandle, Executor,
- * Consumer<Boolean>)}
- */
- private static final class PendingRestoreDelayedRuntimePermissionBackup extends
- AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
- private final @NonNull String mPackageName;
- private final @NonNull UserHandle mUser;
- private final @NonNull Executor mExecutor;
- private final @NonNull Consumer<Boolean> mCallback;
-
- private final @NonNull RemoteCallback mRemoteCallback;
-
- private PendingRestoreDelayedRuntimePermissionBackup(@NonNull RemoteService service,
- @NonNull String packageName, @NonNull UserHandle user, @NonNull Executor executor,
- @NonNull Consumer<Boolean> callback) {
- super(service);
-
- mPackageName = packageName;
- mUser = user;
- mExecutor = executor;
- mCallback = callback;
-
- mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
- long token = Binder.clearCallingIdentity();
- try {
- callback.accept(result.getBoolean(KEY_RESULT, false));
- } finally {
- Binder.restoreCallingIdentity(token);
-
- finish();
- }
- }), null);
- }
-
- @Override
- protected void onTimeout(RemoteService remoteService) {
- long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(
- () -> mCallback.accept(true));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void run() {
- try {
- getService().getServiceInterface().restoreDelayedRuntimePermissionBackup(
- mPackageName, mUser, mRemoteCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Error restoring delayed permissions for " + mPackageName, e);
+ mRemoteService.postAsync(service -> {
+ CompletableFuture<Bundle> grantOrUpgradeDefaultRuntimePermissionsResult =
+ new CompletableFuture<>();
+ service.grantOrUpgradeDefaultRuntimePermissions(
+ new RemoteCallback(grantOrUpgradeDefaultRuntimePermissionsResult::complete));
+ return grantOrUpgradeDefaultRuntimePermissionsResult;
+ }).whenCompleteAsync((grantOrUpgradeDefaultRuntimePermissionsResult, err) -> {
+ if (err != null) {
+ Log.e(TAG, "Error granting or upgrading runtime permissions", err);
+ callback.accept(false);
+ } else {
+ callback.accept(grantOrUpgradeDefaultRuntimePermissionsResult != null);
}
- }
- }
-
- /**
- * Request for {@link #getAppPermissions}
- */
- private static final class PendingGetAppPermissionRequest extends
- AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
- private final @NonNull String mPackageName;
- private final @NonNull OnGetAppPermissionResultCallback mCallback;
-
- private final @NonNull RemoteCallback mRemoteCallback;
-
- private PendingGetAppPermissionRequest(@NonNull RemoteService service,
- @NonNull String packageName, @NonNull OnGetAppPermissionResultCallback callback,
- @NonNull Handler handler) {
- super(service);
-
- mPackageName = packageName;
- mCallback = callback;
-
- mRemoteCallback = new RemoteCallback(result -> {
- final List<RuntimePermissionPresentationInfo> reportedPermissions;
- List<RuntimePermissionPresentationInfo> permissions = null;
- if (result != null) {
- permissions = result.getParcelableArrayList(KEY_RESULT);
- }
- if (permissions == null) {
- permissions = Collections.emptyList();
- }
- reportedPermissions = permissions;
-
- callback.onGetAppPermissions(reportedPermissions);
-
- finish();
- }, handler);
- }
-
- @Override
- protected void onTimeout(RemoteService remoteService) {
- mCallback.onGetAppPermissions(Collections.emptyList());
- }
-
- @Override
- public void run() {
- try {
- getService().getServiceInterface().getAppPermissions(mPackageName, mRemoteCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Error getting app permission", e);
- }
- }
- }
-
- /**
- * Request for {@link #revokeRuntimePermission}
- */
- private static final class PendingRevokeAppPermissionRequest
- implements AbstractRemoteService.AsyncRequest<IPermissionController> {
- private final @NonNull String mPackageName;
- private final @NonNull String mPermissionName;
-
- private PendingRevokeAppPermissionRequest(@NonNull String packageName,
- @NonNull String permissionName) {
- mPackageName = packageName;
- mPermissionName = permissionName;
- }
-
- @Override
- public void run(IPermissionController remoteInterface) {
- try {
- remoteInterface.revokeRuntimePermission(mPackageName, mPermissionName);
- } catch (RemoteException e) {
- Log.e(TAG, "Error revoking app permission", e);
- }
- }
- }
-
- /**
- * Request for {@link #countPermissionApps}
- */
- private static final class PendingCountPermissionAppsRequest extends
- AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
- private final @NonNull List<String> mPermissionNames;
- private final @NonNull OnCountPermissionAppsResultCallback mCallback;
- private final @CountPermissionAppsFlag int mFlags;
-
- private final @NonNull RemoteCallback mRemoteCallback;
-
- private PendingCountPermissionAppsRequest(@NonNull RemoteService service,
- @NonNull List<String> permissionNames, @CountPermissionAppsFlag int flags,
- @NonNull OnCountPermissionAppsResultCallback callback, @NonNull Handler handler) {
- super(service);
-
- mPermissionNames = permissionNames;
- mFlags = flags;
- mCallback = callback;
-
- mRemoteCallback = new RemoteCallback(result -> {
- final int numApps;
- if (result != null) {
- numApps = result.getInt(KEY_RESULT);
- } else {
- numApps = 0;
- }
-
- callback.onCountPermissionApps(numApps);
-
- finish();
- }, handler);
- }
-
- @Override
- protected void onTimeout(RemoteService remoteService) {
- mCallback.onCountPermissionApps(0);
- }
-
- @Override
- public void run() {
- try {
- getService().getServiceInterface().countPermissionApps(mPermissionNames,
- mFlags, mRemoteCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Error counting permission apps", e);
- }
- }
- }
-
- /**
- * Request for {@link #getPermissionUsages}
- */
- private static final class PendingGetPermissionUsagesRequest extends
- AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
- private final @NonNull OnPermissionUsageResultCallback mCallback;
- private final boolean mCountSystem;
- private final long mNumMillis;
-
- private final @NonNull RemoteCallback mRemoteCallback;
-
- private PendingGetPermissionUsagesRequest(@NonNull RemoteService service,
- boolean countSystem, long numMillis, @NonNull @CallbackExecutor Executor executor,
- @NonNull OnPermissionUsageResultCallback callback) {
- super(service);
-
- mCountSystem = countSystem;
- mNumMillis = numMillis;
- mCallback = callback;
-
- mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
- long token = Binder.clearCallingIdentity();
- try {
- final List<RuntimePermissionUsageInfo> reportedUsers;
- List<RuntimePermissionUsageInfo> users = null;
- if (result != null) {
- users = result.getParcelableArrayList(KEY_RESULT);
- } else {
- users = Collections.emptyList();
- }
- reportedUsers = users;
-
- callback.onPermissionUsageResult(reportedUsers);
- } finally {
- Binder.restoreCallingIdentity(token);
-
- finish();
- }
- }), null);
- }
-
- @Override
- protected void onTimeout(RemoteService remoteService) {
- mCallback.onPermissionUsageResult(Collections.emptyList());
- }
-
- @Override
- public void run() {
- try {
- getService().getServiceInterface().getPermissionUsages(mCountSystem, mNumMillis,
- mRemoteCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Error counting permission users", e);
- }
- }
- }
-
- /**
- * Request for {@link #grantOrUpgradeDefaultRuntimePermissions(Executor, Consumer)}
- */
- private static final class PendingGrantOrUpgradeDefaultRuntimePermissionsRequest extends
- AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
- private final @NonNull Consumer<Boolean> mCallback;
-
- private final @NonNull RemoteCallback mRemoteCallback;
-
- private PendingGrantOrUpgradeDefaultRuntimePermissionsRequest(
- @NonNull RemoteService service, @NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<Boolean> callback) {
- super(service);
- mCallback = callback;
-
- mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
- long token = Binder.clearCallingIdentity();
- try {
- callback.accept(result != null);
- } finally {
- Binder.restoreCallingIdentity(token);
- finish();
- }
- }), null);
- }
-
- @Override
- protected void onTimeout(RemoteService remoteService) {
- long token = Binder.clearCallingIdentity();
- try {
- mCallback.accept(false);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void run() {
- try {
- getService().getServiceInterface().grantOrUpgradeDefaultRuntimePermissions(
- mRemoteCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Error granting or upgrading runtime permissions", e);
- }
- }
+ }, executor);
}
}