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

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

Merge "Groundwork for default grants in RoleController"

parents d930e7f4 a4200f82
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -30,4 +30,6 @@ oneway interface IRoleControllerService {
                           in IRoleManagerCallback callback);

    void onClearRoleHolders(in String roleName, in IRoleManagerCallback callback);

    void onGrantDefaultRoles(in IRoleManagerCallback callback);
}
+17 −0
Original line number Diff line number Diff line
@@ -89,6 +89,13 @@ public abstract class RoleControllerService extends Service {
                RoleControllerService.this.onClearRoleHolders(roleName,
                        new RoleManagerCallbackDelegate(callback));
            }

            @Override
            public void onGrantDefaultRoles(IRoleManagerCallback callback) {
                Preconditions.checkNotNull(callback, "callback cannot be null");
                RoleControllerService.this.onGrantDefaultRoles(
                        new RoleManagerCallbackDelegate(callback));
            }
        };
    }

@@ -133,6 +140,16 @@ public abstract class RoleControllerService extends Service {
    public abstract void onClearRoleHolders(@NonNull String roleName,
            @NonNull RoleManagerCallback callback);

    /**
     * Called by system to grant default permissions and roles.
     * <p>
     * This is typically when creating a new user or upgrading either system or
     * permission controller package
     *
     * @param callback the callback for whether this call is successful
     */
    public abstract void onGrantDefaultRoles(@NonNull RoleManagerCallback callback);

    private static class RoleManagerCallbackDelegate implements RoleManagerCallback {

        private IRoleManagerCallback mCallback;
+56 −27
Original line number Diff line number Diff line
@@ -16,10 +16,10 @@

package com.android.server.role;

import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.role.IRoleManagerCallback;
import android.app.role.RoleManagerCallback;
import android.content.ComponentName;
@@ -34,6 +34,7 @@ import android.rolecontrollerservice.IRoleControllerService;
import android.rolecontrollerservice.RoleControllerService;
import android.util.Slog;

import com.android.internal.os.BackgroundThread;
import com.android.internal.util.function.pooled.PooledLambda;

import java.util.ArrayDeque;
@@ -44,8 +45,12 @@ import java.util.Queue;
 */
public class RemoteRoleControllerService {

    static final boolean DEBUG = false;
    private static final String LOG_TAG = RemoteRoleControllerService.class.getSimpleName();

    @NonNull
    private static final Handler sCallbackHandler = BackgroundThread.getHandler();

    @NonNull
    private final Connection mConnection;

@@ -87,6 +92,16 @@ public class RemoteRoleControllerService {
                service.onClearRoleHolders(roleName, callbackDelegate), callback));
    }

    /**
     * Performs granting of default roles and permissions and appops
     *
     * @see RoleControllerService#onGrantDefaultRoles(RoleManagerCallback)
     */
    public void onGrantDefaultRoles(@NonNull IRoleManagerCallback callback) {
        mConnection.enqueueCall(
                new Connection.Call(IRoleControllerService::onGrantDefaultRoles, callback));
    }

    private static final class Connection implements ServiceConnection {

        private static final long UNBIND_DELAY_MILLIS = 15 * 1000;
@@ -105,9 +120,6 @@ public class RemoteRoleControllerService {
        @NonNull
        private final Queue<Call> mPendingCalls = new ArrayDeque<>();

        @NonNull
        private final Handler mMainHandler = Handler.getMain();

        @NonNull
        private final Runnable mUnbindRunnable = this::unbind;

@@ -116,14 +128,14 @@ public class RemoteRoleControllerService {
            mContext = context;
        }

        @MainThread
        @Override
        @WorkerThread
        public void onServiceConnected(@NonNull ComponentName name, @NonNull IBinder service) {
            mService = IRoleControllerService.Stub.asInterface(service);
            executePendingCalls();
        }

        @MainThread
        @WorkerThread
        private void executePendingCalls() {
            while (!mPendingCalls.isEmpty()) {
                Call call = mPendingCalls.poll();
@@ -132,26 +144,33 @@ public class RemoteRoleControllerService {
            scheduleUnbind();
        }

        @MainThread
        @Override
        @WorkerThread
        public void onServiceDisconnected(@NonNull ComponentName name) {
            mService = null;
        }

        @MainThread
        @Override
        @WorkerThread
        public void onBindingDied(@NonNull ComponentName name) {
            unbind();
        }

        public void enqueueCall(@NonNull Call call) {
            mMainHandler.post(PooledLambda.obtainRunnable(this::executeCall, call));
            if (DEBUG) {
                Slog.i(LOG_TAG, "Enqueue " + call);
            }
            sCallbackHandler.executeOrSendMessage(PooledLambda.obtainMessage(
                    Connection::executeCall, this, call));
        }

        @MainThread
        @WorkerThread
        private void executeCall(@NonNull Call call) {
            ensureBound();
            if (mService == null) {
                if (DEBUG) {
                    Slog.i(LOG_TAG, "Delaying until service connected: " + call);
                }
                mPendingCalls.offer(call);
                return;
            }
@@ -159,24 +178,28 @@ public class RemoteRoleControllerService {
            scheduleUnbind();
        }

        @MainThread
        @WorkerThread
        private void ensureBound() {
            mMainHandler.removeCallbacks(mUnbindRunnable);
            sCallbackHandler.removeCallbacks(mUnbindRunnable);
            if (!mBound) {
                Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
                intent.setPackage(mContext.getPackageManager()
                        .getPermissionControllerPackageName());
                // Use direct handler to ensure onServiceConnected callback happens in the same
                // call frame, as required by onGrantDefaultRoles
                //
                // Note that as a result, onServiceConnected may happen not on main thread!
                mBound = mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE,
                        UserHandle.of(mUserId));
                        sCallbackHandler, UserHandle.of(mUserId));
            }
        }

        private void scheduleUnbind() {
            mMainHandler.removeCallbacks(mUnbindRunnable);
            mMainHandler.postDelayed(mUnbindRunnable, UNBIND_DELAY_MILLIS);
            sCallbackHandler.removeCallbacks(mUnbindRunnable);
            sCallbackHandler.postDelayed(mUnbindRunnable, UNBIND_DELAY_MILLIS);
        }

        @MainThread
        @WorkerThread
        private void unbind() {
            if (mBound) {
                mService = null;
@@ -195,9 +218,6 @@ public class RemoteRoleControllerService {
            @NonNull
            private final IRoleManagerCallback mCallback;

            @NonNull
            private final Handler mMainHandler = Handler.getMain();

            @NonNull
            private final Runnable mTimeoutRunnable = () -> notifyCallback(false);

@@ -209,10 +229,13 @@ public class RemoteRoleControllerService {
                mCallback = callback;
            }

            @MainThread
            @WorkerThread
            public void execute(IRoleControllerService service) {
                if (DEBUG) {
                    Slog.i(LOG_TAG, "Executing " + this);
                }
                try {
                    mMainHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MILLIS);
                    sCallbackHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MILLIS);
                    mCallExecutor.execute(service, new CallbackDelegate());
                } catch (RemoteException e) {
                    Slog.e(LOG_TAG, "Error calling RoleControllerService", e);
@@ -220,13 +243,13 @@ public class RemoteRoleControllerService {
                }
            }

            @MainThread
            @WorkerThread
            private void notifyCallback(boolean success) {
                if (mCallbackNotified) {
                    return;
                }
                mCallbackNotified = true;
                mMainHandler.removeCallbacks(mTimeoutRunnable);
                sCallbackHandler.removeCallbacks(mTimeoutRunnable);
                try {
                    if (success) {
                        mCallback.onSuccess();
@@ -239,10 +262,15 @@ public class RemoteRoleControllerService {
                }
            }

            @Override
            public String toString() {
                return "Call with callback: " + mCallback;
            }

            @FunctionalInterface
            public interface CallExecutor {

                @MainThread
                @WorkerThread
                void execute(IRoleControllerService service, IRoleManagerCallback callbackDelegate)
                        throws RemoteException;
            }
@@ -251,13 +279,14 @@ public class RemoteRoleControllerService {

                @Override
                public void onSuccess() throws RemoteException {
                    mMainHandler.post(PooledLambda.obtainRunnable(Call.this::notifyCallback, true));
                    sCallbackHandler.sendMessage(PooledLambda.obtainMessage(
                            Call::notifyCallback, Call.this, true));
                }

                @Override
                public void onFailure() throws RemoteException {
                    mMainHandler.post(PooledLambda.obtainRunnable(Call.this::notifyCallback,
                            false));
                    sCallbackHandler.sendMessage(PooledLambda.obtainMessage(
                            Call::notifyCallback, Call.this, false));
                }
            }
        }
+27 −3
Original line number Diff line number Diff line
@@ -45,6 +45,10 @@ import com.android.server.SystemService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Service for role management.
@@ -105,17 +109,37 @@ public class RoleManagerService extends SystemService {
    public void onStart() {
        publishBinderService(Context.ROLE_SERVICE, new Stub());
        //TODO add watch for new user creation and run default grants for them
        //TODO add package update watch to detect PermissionController upgrade and run def. grants
    }

    @Override
    public void onStartUser(@UserIdInt int userId) {
        synchronized (mLock) {
            //TODO only call into PermissionController if it or system upgreaded (for boot time)
            // (add package changes watch;
            //     we can detect upgrade using build fingerprint and app version)
            getUserStateLocked(userId);
            //TODO call permission grant policy here
        }
        //TODO consider calling grants only when certain conditions are met
        // such as OS or PermissionController upgrade
        if (RemoteRoleControllerService.DEBUG) {
            Slog.i(LOG_TAG, "Granting default permissions...");
            CompletableFuture<Void> result = new CompletableFuture<>();
            getControllerService(userId).onGrantDefaultRoles(
                    new IRoleManagerCallback.Stub() {
                        @Override
                        public void onSuccess() {
                            result.complete(null);
                        }

                        @Override
                        public void onFailure() {
                            result.completeExceptionally(new RuntimeException());
                        }
                    });
            try {
                result.get(5, TimeUnit.SECONDS);
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
                Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e);
            }
        }
    }