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

Commit eb651eda authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add controller APIs for RoleManager."

parents 8c2aef9f 87ed09ae
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -810,9 +810,12 @@ package android.app.role {

  public final class RoleManager {
    method public void addRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
    method public boolean addRoleHolderFromController(java.lang.String, java.lang.String);
    method public void clearRoleHoldersAsUser(java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
    method public java.util.Set<java.lang.String> getRoleHoldersAsUser(java.lang.String, android.os.UserHandle);
    method public java.util.List<java.lang.String> getRoleHolders(java.lang.String);
    method public java.util.List<java.lang.String> getRoleHoldersAsUser(java.lang.String, android.os.UserHandle);
    method public void removeRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
    method public boolean removeRoleHolderFromController(java.lang.String, java.lang.String);
    field public static final java.lang.String EXTRA_REQUEST_ROLE_NAME = "android.app.role.extra.REQUEST_ROLE_NAME";
  }

+4 −0
Original line number Diff line number Diff line
@@ -36,4 +36,8 @@ interface IRoleManager {
            in IRoleManagerCallback callback);

    void clearRoleHoldersAsUser(in String roleName, int userId, in IRoleManagerCallback callback);

    boolean addRoleHolderFromController(in String roleName, in String packageName);

    boolean removeRoleHolderFromController(in String roleName, in String packageName);
}
+114 −18
Original line number Diff line number Diff line
@@ -22,19 +22,16 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.ArraySet;

import com.android.internal.util.Preconditions;

import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

/**
@@ -51,8 +48,8 @@ import java.util.concurrent.Executor;
 * role holders. To qualify for a role, an application must meet certain requirements, including
 * defining certain components in its manifest. These requirements can be found in the AndroidX
 * Libraries. Then the application will need user consent to become a role holder, which can be
 * requested using {@link Activity#startActivityForResult(Intent, int)} with the {@code Intent}
 * obtained from {@link #createRequestRoleIntent(String)}.
 * requested using {@link android.app.Activity#startActivityForResult(Intent, int)} with the
 * {@code Intent} obtained from {@link #createRequestRoleIntent(String)}.
 * <p>
 * Upon becoming a role holder, the application may be granted certain privileges that are role
 * specific. When the application loses its role, these privileges will also be revoked.
@@ -89,6 +86,14 @@ public final class RoleManager {
    @SystemApi
    public static final String EXTRA_REQUEST_ROLE_NAME = "android.app.role.extra.REQUEST_ROLE_NAME";

    /**
     * The permission required to manage records of role holders in {@link RoleManager} directly.
     *
     * @hide
     */
    public static final String PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER =
            "com.android.permissioncontroller.permission.MANAGE_ROLE_HOLDERS_FROM_CONTROLLER";

    @NonNull
    private final Context mContext;

@@ -105,11 +110,13 @@ public final class RoleManager {
    }

    /**
     * Returns an {@code Intent} suitable for passing to {@link Activity#startActivityForResult(
     * Intent, int)} which prompts the user to grant a role to this application.
     * Returns an {@code Intent} suitable for passing to
     * {@link android.app.Activity#startActivityForResult(Intent, int)} which prompts the user to
     * grant a role to this application.
     * <p>
     * If the role is granted, the {@code resultCode} will be {@link Activity#RESULT_OK}, otherwise
     * it will be {@link Activity#RESULT_CANCELED}.
     * If the role is granted, the {@code resultCode} will be
     * {@link android.app.Activity#RESULT_OK}, otherwise it will be
     * {@link android.app.Activity#RESULT_CANCELED}.
     *
     * @param roleName the name of requested role
     *
@@ -162,6 +169,29 @@ public final class RoleManager {
        }
    }

    /**
     * Get package names of the applications holding the role.
     * <p>
     * <strong>Note:</strong> Using this API requires holding
     * {@code android.permission.MANAGE_ROLE_HOLDERS}.
     *
     * @param roleName the name of the role to get the role holder for
     *
     * @return a list of package names of the role holders, or an empty list if none.
     *
     * @throws IllegalArgumentException if the role name is {@code null} or empty.
     *
     * @see #getRoleHoldersAsUser(String, UserHandle)
     *
     * @hide
     */
    @NonNull
    @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
    @SystemApi
    public List<String> getRoleHolders(@NonNull String roleName) {
        return getRoleHoldersAsUser(roleName, UserHandle.of(UserHandle.getCallingUserId()));
    }

    /**
     * Get package names of the applications holding the role.
     * <p>
@@ -172,7 +202,7 @@ public final class RoleManager {
     * @param roleName the name of the role to get the role holder for
     * @param user the user to get the role holder for
     *
     * @return the package name of the role holder, or {@code null} if none.
     * @return a list of package names of the role holders, or an empty list if none.
     *
     * @throws IllegalArgumentException if the role name is {@code null} or empty.
     *
@@ -185,16 +215,14 @@ public final class RoleManager {
    @NonNull
    @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
    @SystemApi
    public Set<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) {
    public List<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) {
        Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
        Preconditions.checkNotNull(user, "user cannot be null");
        List<String> roleHolders;
        try {
            roleHolders = mService.getRoleHoldersAsUser(roleName, user.getIdentifier());
            return mService.getRoleHoldersAsUser(roleName, user.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return new ArraySet<>(roleHolders);
    }

    /**
@@ -312,6 +340,74 @@ public final class RoleManager {
        }
    }

    /**
     * Add a specific application to the holders of a role, only modifying records inside
     * {@link RoleManager}. Should only be called from
     * {@link android.rolecontrollerservice.RoleControllerService}.
     * <p>
     * <strong>Note:</strong> Using this API requires holding
     * {@link #PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER}.
     *
     * @param roleName the name of the role to add the role holder for
     * @param packageName the package name of the application to add to the role holders
     *
     * @return whether the operation was successful, and will also be {@code true} if a matching
     *         role holder is already found.
     *
     * @throws IllegalArgumentException if the role name or package name is {@code null} or empty.
     *
     * @see #getRoleHolders(String)
     * @see #removeRoleHolderFromController(String, String)
     *
     * @hide
     */
    @RequiresPermission(PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER)
    @SystemApi
    public boolean addRoleHolderFromController(@NonNull String roleName,
            @NonNull String packageName) {
        Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
        Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
        try {
            return mService.addRoleHolderFromController(roleName, packageName);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Remove a specific application from the holders of a role, only modifying records inside
     * {@link RoleManager}. Should only be called from
     * {@link android.rolecontrollerservice.RoleControllerService}.
     * <p>
     * <strong>Note:</strong> Using this API requires holding
     * {@link #PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER}.
     *
     * @param roleName the name of the role to remove the role holder for
     * @param packageName the package name of the application to remove from the role holders
     *
     * @return whether the operation was successful, and will also be {@code true} if no matching
     *         role holder was found to remove.
     *
     * @throws IllegalArgumentException if the role name or package name is {@code null} or empty.
     *
     * @see #getRoleHolders(String)
     * @see #addRoleHolderFromController(String, String)
     *
     * @hide
     */
    @RequiresPermission(PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER)
    @SystemApi
    public boolean removeRoleHolderFromController(@NonNull String roleName,
            @NonNull String packageName) {
        Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
        Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
        try {
            return mService.removeRoleHolderFromController(roleName, packageName);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    private static class RoleManagerCallbackDelegate extends IRoleManagerCallback.Stub {

        @NonNull
+7 −5
Original line number Diff line number Diff line
@@ -105,6 +105,9 @@ 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;

@@ -142,7 +145,7 @@ public class RemoteRoleControllerService {
        }

        public void enqueueCall(@NonNull Call call) {
            Handler.getMain().post(PooledLambda.obtainRunnable(this::executeCall, call));
            mMainHandler.post(PooledLambda.obtainRunnable(this::executeCall, call));
        }

        @MainThread
@@ -158,7 +161,7 @@ public class RemoteRoleControllerService {

        @MainThread
        private void ensureBound() {
            Handler.getMain().removeCallbacks(mUnbindRunnable);
            mMainHandler.removeCallbacks(mUnbindRunnable);
            if (!mBound) {
                Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
                intent.setPackage(mContext.getPackageManager()
@@ -169,9 +172,8 @@ public class RemoteRoleControllerService {
        }

        private void scheduleUnbind() {
            Handler mainHandler = Handler.getMain();
            mainHandler.removeCallbacks(mUnbindRunnable);
            mainHandler.postDelayed(mUnbindRunnable, UNBIND_DELAY_MILLIS);
            mMainHandler.removeCallbacks(mUnbindRunnable);
            mMainHandler.postDelayed(mUnbindRunnable, UNBIND_DELAY_MILLIS);
        }

        @MainThread
+33 −0
Original line number Diff line number Diff line
@@ -249,9 +249,42 @@ public class RoleManagerService extends SystemService {
            userId = handleIncomingUser(userId, "clearRoleHoldersAsUser");
            getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                    "clearRoleHoldersAsUser");

            getControllerService(userId).onClearRoleHolders(roleName, callback);
        }

        @Override
        public boolean addRoleHolderFromController(@NonNull String roleName,
                @NonNull String packageName) {
            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
            getContext().enforceCallingOrSelfPermission(
                    RoleManager.PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER,
                    "addRoleHolderFromController");

            int userId = UserHandle.getCallingUserId();
            synchronized (mLock) {
                RoleUserState userState = getUserStateLocked(userId);
                return userState.addRoleHolderLocked(roleName, packageName);
            }
        }

        @Override
        public boolean removeRoleHolderFromController(@NonNull String roleName,
                @NonNull String packageName) {
            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
            getContext().enforceCallingOrSelfPermission(
                    RoleManager.PERMISSION_MANAGE_ROLE_HOLDERS_FROM_CONTROLLER,
                    "removeRoleHolderFromController");

            int userId = UserHandle.getCallingUserId();
            synchronized (mLock) {
                RoleUserState userState = getUserStateLocked(userId);
                return userState.removeRoleHolderLocked(roleName, packageName);
            }
        }

        @CheckResult
        private int handleIncomingUser(@UserIdInt int userId, @NonNull String name) {
            return ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
Loading