diff options
| author | 2018-11-01 22:22:45 +0000 | |
|---|---|---|
| committer | 2018-11-01 22:22:45 +0000 | |
| commit | eb651edabfaf9ac214183cfbf672c0b37b06831b (patch) | |
| tree | 3987324fad904f521c749bc982c3081a07248638 | |
| parent | 8c2aef9ff8004f526ba148c5c9c9115feb4afd6d (diff) | |
| parent | 87ed09ae425051c80ef7376d39b0bfcbf24df6b2 (diff) | |
Merge "Add controller APIs for RoleManager."
6 files changed, 162 insertions, 43 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 7e2953512431..1649fc775634 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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"; } diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl index 64f69c182f78..2cf13ec24141 100644 --- a/core/java/android/app/role/IRoleManager.aidl +++ b/core/java/android/app/role/IRoleManager.aidl @@ -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); } diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java index f7c6dea21e85..ed27d9fe9fd4 100644 --- a/core/java/android/app/role/RoleManager.java +++ b/core/java/android/app/role/RoleManager.java @@ -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 * @@ -165,14 +172,37 @@ public final class RoleManager { /** * Get package names of the applications holding the role. * <p> - * <strong>Note: </strong>Using this API requires holding + * <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> + * <strong>Note:</strong> Using this API requires holding * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. * * @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,23 +215,21 @@ 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); } /** * Add a specific application to the holders of a role. If the role is exclusive, the previous * holder will be replaced. * <p> - * <strong>Note: </strong>Using this API requires holding + * <strong>Note:</strong> Using this API requires holding * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. * @@ -240,7 +268,7 @@ public final class RoleManager { /** * Remove a specific application from the holders of a role. * <p> - * <strong>Note: </strong>Using this API requires holding + * <strong>Note:</strong> Using this API requires holding * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. * @@ -279,7 +307,7 @@ public final class RoleManager { /** * Remove all holders of a role. * <p> - * <strong>Note: </strong>Using this API requires holding + * <strong>Note:</strong> Using this API requires holding * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. * @@ -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 diff --git a/services/core/java/com/android/server/role/RemoteRoleControllerService.java b/services/core/java/com/android/server/role/RemoteRoleControllerService.java index c737e8bb8710..b670291ba94b 100644 --- a/services/core/java/com/android/server/role/RemoteRoleControllerService.java +++ b/services/core/java/com/android/server/role/RemoteRoleControllerService.java @@ -106,6 +106,9 @@ public class RemoteRoleControllerService { private final Queue<Call> mPendingCalls = new ArrayDeque<>(); @NonNull + private final Handler mMainHandler = Handler.getMain(); + + @NonNull private final Runnable mUnbindRunnable = this::unbind; Connection(@UserIdInt int userId, @NonNull Context context) { @@ -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 diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index 5c9cef507b67..b7d2ce29563e 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -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, diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java index bd5449151beb..caa7c2845ccb 100644 --- a/services/core/java/com/android/server/role/RoleUserState.java +++ b/services/core/java/com/android/server/role/RoleUserState.java @@ -174,25 +174,6 @@ public class RoleUserState { } /** - * Remove all holders of a role. - * - * @param roleName the name of the role to remove all its holders - * - * @return {@code false} only if the set of role holders is null, which should not happen and - * indicates an issue. - */ - @GuardedBy("RoleManagerService.mLock") - public boolean clearRoleHolderLocked(@NonNull String roleName) { - throwIfDestroyedLocked(); - ArraySet<String> roleHolders = mRoles.get(roleName); - if (roleHolders == null) { - return false; - } - roleHolders.clear(); - return true; - } - - /** * Schedule writing the state to file. */ @GuardedBy("RoleManagerService.mLock") |