Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 994937ab authored by Eugene Susla's avatar Eugene Susla Committed by Android (Google) Code Review
Browse files

Merge "Migrate RoleControllerManager to ServiceConnector"

parents a2395795 3ee9e923
Loading
Loading
Loading
Loading
+98 −402
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.UserIdInt;
import android.app.ActivityThread;
import android.content.ComponentName;
import android.content.Context;
@@ -29,18 +28,18 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;

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.ServiceConnector;

import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
@@ -53,6 +52,8 @@ public class RoleControllerManager {

    private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();

    private static final long REQUEST_TIMEOUT_MILLIS = 15 * 1000;

    private static volatile ComponentName sRemoteServiceComponentName;

    private static final Object sRemoteServicesLock = new Object();
@@ -61,10 +62,11 @@ public class RoleControllerManager {
     * Global remote services (per user) used by all {@link RoleControllerManager managers}.
     */
    @GuardedBy("sRemoteServicesLock")
    private static final SparseArray<RemoteService> sRemoteServices = new SparseArray<>();
    private static final SparseArray<ServiceConnector<IRoleController>> sRemoteServices =
            new SparseArray<>();

    @NonNull
    private final RemoteService mRemoteService;
    private final ServiceConnector<IRoleController> mRemoteService;

    /**
     * Initialize the remote service component name once so that we can avoid acquiring the
@@ -92,10 +94,19 @@ public class RoleControllerManager {
            @NonNull Handler handler, @NonNull Context context) {
        synchronized (sRemoteServicesLock) {
            int userId = context.getUserId();
            RemoteService remoteService = sRemoteServices.get(userId);
            ServiceConnector<IRoleController> remoteService = sRemoteServices.get(userId);
            if (remoteService == null) {
                remoteService = new RemoteService(ActivityThread.currentApplication(),
                        remoteServiceComponentName, handler, userId);
                remoteService = new ServiceConnector.Impl<IRoleController>(
                        ActivityThread.currentApplication(),
                        new Intent(RoleControllerService.SERVICE_INTERFACE)
                                .setComponent(remoteServiceComponentName),
                        0 /* bindingFlags */, userId, IRoleController.Stub::asInterface) {

                    @Override
                    protected Handler getJobHandler() {
                        return handler;
                    }
                };
                sRemoteServices.put(userId, remoteService);
            }
            mRemoteService = remoteService;
@@ -120,8 +131,12 @@ public class RoleControllerManager {
     */
    public void grantDefaultRoles(@NonNull @CallbackExecutor Executor executor,
            @NonNull Consumer<Boolean> callback) {
        mRemoteService.scheduleRequest(new GrantDefaultRolesRequest(mRemoteService, executor,
                callback));
        AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
            AndroidFuture<Bundle> future = new AndroidFuture<>();
            service.grantDefaultRoles(new RemoteCallback(future::complete));
            return future;
        });
        propagateCallback(operation, "grantDefaultRoles", executor, callback);
    }

    /**
@@ -129,8 +144,13 @@ public class RoleControllerManager {
     */
    public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
            @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
        mRemoteService.scheduleRequest(new OnAddRoleHolderRequest(mRemoteService, roleName,
                packageName, flags, callback));
        AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
            AndroidFuture<Bundle> future = new AndroidFuture<>();
            service.onAddRoleHolder(roleName, packageName, flags,
                    new RemoteCallback(future::complete));
            return future;
        });
        propagateCallback(operation, "onAddRoleHolder", callback);
    }

    /**
@@ -138,8 +158,13 @@ public class RoleControllerManager {
     */
    public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
            @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
        mRemoteService.scheduleRequest(new OnRemoveRoleHolderRequest(mRemoteService, roleName,
                packageName, flags, callback));
        AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
            AndroidFuture<Bundle> future = new AndroidFuture<>();
            service.onRemoveRoleHolder(roleName, packageName, flags,
                    new RemoteCallback(future::complete));
            return future;
        });
        propagateCallback(operation, "onRemoveRoleHolder", callback);
    }

    /**
@@ -147,8 +172,13 @@ public class RoleControllerManager {
     */
    public void onClearRoleHolders(@NonNull String roleName,
            @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
        mRemoteService.scheduleRequest(new OnClearRoleHoldersRequest(mRemoteService, roleName,
                flags, callback));
        AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
            AndroidFuture<Bundle> future = new AndroidFuture<>();
            service.onClearRoleHolders(roleName, flags,
                    new RemoteCallback(future::complete));
            return future;
        });
        propagateCallback(operation, "onClearRoleHolders", callback);
    }

    /**
@@ -157,8 +187,13 @@ public class RoleControllerManager {
    @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
    public void isApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName,
            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
        mRemoteService.scheduleRequest(new IsApplicationQualifiedForRoleRequest(mRemoteService,
                roleName, packageName, executor, callback));
        AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
            AndroidFuture<Bundle> future = new AndroidFuture<>();
            service.isApplicationQualifiedForRole(roleName, packageName,
                    new RemoteCallback(future::complete));
            return future;
        });
        propagateCallback(operation, "isApplicationQualifiedForRole", executor, callback);
    }

    /**
@@ -167,387 +202,48 @@ public class RoleControllerManager {
    @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
    public void isRoleVisible(@NonNull String roleName,
            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
        mRemoteService.scheduleRequest(new IsRoleVisibleRequest(mRemoteService, roleName, executor,
                callback));
    }

    /**
     * Connection to the remote service.
     */
    private static final class RemoteService extends AbstractMultiplePendingRequestsRemoteService<
            RemoteService, IRoleController> {

        private static final long UNBIND_DELAY_MILLIS = 15 * 1000;
        private static final long REQUEST_TIMEOUT_MILLIS = 15 * 1000;

        /**
         * Create a connection to the remote service
         *
         * @param context the context to use
         * @param componentName the component of the service to connect to
         * @param handler the handler for binding service and callbacks
         * @param userId the user whom remote service should be connected as
         */
        RemoteService(@NonNull Context context, @NonNull ComponentName componentName,
                @NonNull Handler handler, @UserIdInt int userId) {
            super(context, RoleControllerService.SERVICE_INTERFACE, componentName, userId,
                    service -> Log.e(LOG_TAG, "RemoteService " + service + " died"), handler, 0,
                    false, 1);
        }

        /**
         * @return The default handler used by this service.
         */
        @NonNull
        public Handler getHandler() {
            return mHandler;
        }

        @Override
        protected @NonNull IRoleController getServiceInterface(@NonNull IBinder binder) {
            return IRoleController.Stub.asInterface(binder);
        }

        @Override
        protected long getTimeoutIdleBindMillis() {
            return UNBIND_DELAY_MILLIS;
        }

        @Override
        protected long getRemoteRequestMillis() {
            return REQUEST_TIMEOUT_MILLIS;
        }

        @Override
        public void scheduleRequest(
                @NonNull BasePendingRequest<RemoteService, IRoleController> pendingRequest) {
            super.scheduleRequest(pendingRequest);
        }

        @Override
        public void scheduleAsyncRequest(@NonNull AsyncRequest<IRoleController> request) {
            super.scheduleAsyncRequest(request);
        }
    }

    /**
     * Request for {@link #grantDefaultRoles(Executor, Consumer)}.
     */
    private static final class GrantDefaultRolesRequest
            extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {

        @NonNull
        private final Executor mExecutor;
        @NonNull
        private final Consumer<Boolean> mCallback;

        @NonNull
        private final RemoteCallback mRemoteCallback;

        private GrantDefaultRolesRequest(@NonNull RemoteService service,
                @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
            super(service);

            mExecutor = executor;
            mCallback = callback;

            mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
                long token = Binder.clearCallingIdentity();
                try {
                    boolean successful = result != null;
                    mCallback.accept(successful);
                } finally {
                    Binder.restoreCallingIdentity(token);
                    finish();
                }
            }));
        }

        @Override
        protected void onTimeout(@NonNull RemoteService remoteService) {
            mExecutor.execute(() -> mCallback.accept(false));
        }

        @Override
        public void run() {
            try {
                getService().getServiceInterface().grantDefaultRoles(mRemoteCallback);
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "Error calling grantDefaultRoles()", e);
            }
        }

        @Override
        protected void onFailed() {
            mRemoteCallback.sendResult(null);
        }
    }

    /**
     * Request for {@link #onAddRoleHolder(String, String, int, RemoteCallback)}.
     */
    private static final class OnAddRoleHolderRequest
            extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {

        @NonNull
        private final String mRoleName;
        @NonNull
        private final String mPackageName;
        @RoleManager.ManageHoldersFlags
        private final int mFlags;
        @NonNull
        private final RemoteCallback mCallback;

        @NonNull
        private final RemoteCallback mRemoteCallback;

        private OnAddRoleHolderRequest(@NonNull RemoteService service, @NonNull String roleName,
                @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags,
                @NonNull RemoteCallback callback) {
            super(service);

            mRoleName = roleName;
            mPackageName = packageName;
            mFlags = flags;
            mCallback = callback;

            mRemoteCallback = new RemoteCallback(result -> {
                long token = Binder.clearCallingIdentity();
                try {
                    mCallback.sendResult(result);
                } finally {
                    Binder.restoreCallingIdentity(token);
                    finish();
                }
            });
        }

        @Override
        protected void onTimeout(@NonNull RemoteService remoteService) {
            mCallback.sendResult(null);
        }

        @Override
        public void run() {
            try {
                getService().getServiceInterface().onAddRoleHolder(mRoleName, mPackageName, mFlags,
                        mRemoteCallback);
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "Error calling onAddRoleHolder()", e);
            }
        }
    }

    /**
     * Request for {@link #onRemoveRoleHolder(String, String, int, RemoteCallback)}.
     */
    private static final class OnRemoveRoleHolderRequest
            extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {

        @NonNull
        private final String mRoleName;
        @NonNull
        private final String mPackageName;
        @RoleManager.ManageHoldersFlags
        private final int mFlags;
        @NonNull
        private final RemoteCallback mCallback;

        @NonNull
        private final RemoteCallback mRemoteCallback;

        private OnRemoveRoleHolderRequest(@NonNull RemoteService service, @NonNull String roleName,
                @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags,
                @NonNull RemoteCallback callback) {
            super(service);

            mRoleName = roleName;
            mPackageName = packageName;
            mFlags = flags;
            mCallback = callback;

            mRemoteCallback = new RemoteCallback(result -> {
                long token = Binder.clearCallingIdentity();
                try {
                    mCallback.sendResult(result);
                } finally {
                    Binder.restoreCallingIdentity(token);
                    finish();
                }
        AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
            AndroidFuture<Bundle> future = new AndroidFuture<>();
            service.isRoleVisible(roleName, new RemoteCallback(future::complete));
            return future;
        });
        propagateCallback(operation, "isRoleVisible", executor, callback);
    }

        @Override
        protected void onTimeout(@NonNull RemoteService remoteService) {
            mCallback.sendResult(null);
        }

        @Override
        public void run() {
            try {
                getService().getServiceInterface().onRemoveRoleHolder(mRoleName, mPackageName,
                        mFlags, mRemoteCallback);
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "Error calling onRemoveRoleHolder()", e);
            }
        }
    }

    /**
     * Request for {@link #onClearRoleHolders(String, int, RemoteCallback)}.
     */
    private static final class OnClearRoleHoldersRequest
            extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {

        @NonNull
        private final String mRoleName;
        @RoleManager.ManageHoldersFlags
        private final int mFlags;
        @NonNull
        private final RemoteCallback mCallback;

        @NonNull
        private final RemoteCallback mRemoteCallback;

        private OnClearRoleHoldersRequest(@NonNull RemoteService service, @NonNull String roleName,
                @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
            super(service);

            mRoleName = roleName;
            mFlags = flags;
            mCallback = callback;

            mRemoteCallback = new RemoteCallback(result -> {
    private void propagateCallback(AndroidFuture<Bundle> operation, String opName,
            @CallbackExecutor @NonNull Executor executor,
            Consumer<Boolean> destination) {
        operation.orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .whenComplete((res, err) -> executor.execute(() -> {
                    long token = Binder.clearCallingIdentity();
                    try {
                    mCallback.sendResult(result);
                } finally {
                    Binder.restoreCallingIdentity(token);
                    finish();
                }
            });
        }

        @Override
        protected void onTimeout(@NonNull RemoteService remoteService) {
            mCallback.sendResult(null);
        }

        @Override
        public void run() {
            try {
                getService().getServiceInterface().onClearRoleHolders(mRoleName, mFlags,
                        mRemoteCallback);
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "Error calling onClearRoleHolders()", e);
                        if (err != null) {
                            Log.e(LOG_TAG, "Error calling " + opName + "()", err);
                            destination.accept(false);
                        } else {
                            destination.accept(res != null);
                        }
        }
    }

    /**
     * Request for {@link #isApplicationQualifiedForRole(String, String, Executor, Consumer)}
     */
    private static final class IsApplicationQualifiedForRoleRequest extends
            AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {

        @NonNull
        private final String mRoleName;
        @NonNull
        private final String mPackageName;
        @NonNull
        private final Executor mExecutor;
        @NonNull
        private final Consumer<Boolean> mCallback;

        @NonNull
        private final RemoteCallback mRemoteCallback;

        private IsApplicationQualifiedForRoleRequest(@NonNull RemoteService service,
                @NonNull String roleName, @NonNull String packageName,
                @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
            super(service);

            mRoleName = roleName;
            mPackageName = packageName;
            mExecutor = executor;
            mCallback = callback;

            mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
                long token = Binder.clearCallingIdentity();
                try {
                    boolean qualified = result != null;
                    mCallback.accept(qualified);
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    finish();
                    }
                }));
    }

        @Override
        protected void onTimeout(RemoteService remoteService) {
            mExecutor.execute(() -> mCallback.accept(false));
        }

        @Override
        public void run() {
            try {
                getService().getServiceInterface().isApplicationQualifiedForRole(mRoleName,
                        mPackageName, mRemoteCallback);
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "Error calling isApplicationQualifiedForRole()", e);
            }
        }
    }

    /**
     * Request for {@link #isRoleVisible(String, Executor, Consumer)}
     */
    private static final class IsRoleVisibleRequest
            extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {

        @NonNull
        private final String mRoleName;
        @NonNull
        private final Executor mExecutor;
        @NonNull
        private final Consumer<Boolean> mCallback;

        @NonNull
        private final RemoteCallback mRemoteCallback;

        private IsRoleVisibleRequest(@NonNull RemoteService service, @NonNull String roleName,
                @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
            super(service);

            mRoleName = roleName;
            mExecutor = executor;
            mCallback = callback;

            mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
    private void propagateCallback(AndroidFuture<Bundle> operation, String opName,
            RemoteCallback destination) {
        operation.orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .whenComplete((res, err) -> {
                    long token = Binder.clearCallingIdentity();
                    try {
                    boolean visible = result != null;
                    mCallback.accept(visible);
                        if (err != null) {
                            Log.e(LOG_TAG, "Error calling " + opName + "()", err);
                            destination.sendResult(null);
                        } else {
                            destination.sendResult(res);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    finish();
                }
            }));
        }

        @Override
        protected void onTimeout(RemoteService remoteService) {
            mExecutor.execute(() -> mCallback.accept(false));
        }

        @Override
        public void run() {
            try {
                getService().getServiceInterface().isRoleVisible(mRoleName, mRemoteCallback);
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "Error calling isRoleVisible()", e);
            }
                    }
                });
    }
}