diff options
author | 2023-10-22 22:08:05 -0700 | |
---|---|---|
committer | 2023-11-06 17:52:48 -0800 | |
commit | 3e93b16fd13dc116e16c9ba077947e72082bff32 (patch) | |
tree | b6afe2abdb7c2b97410a3ca60baf831efa6c9477 | |
parent | 161934a56f1d500e27d5d281491e4290cefe61b1 (diff) |
[Role Logic Move] Make RoleManager methods user-aware
Some RoleManager API methods are not multi-user-aware; for example, the
methods named "...FromController", among others. These methods lead to
Binder.getCallingUid().
And, many of those methods are called from the role-controller business
logic. But, that business logic will will be moving from a per-user app
into SystemServer. So, we need to make these methods multi-user-aware
to support the Role Business Logic Move project.
To do so, modify these methods to receive the user from the context,
and mark the APIs as @UserHandleAware.
For compatibility reasons, use CompatChanges, which will only enable
this change for callers with targetSdk V+. Since this is the first time
we've used CompatChanges in the Permission APEX, this involves updating
Android.bp files.
Test: atest CtsRoleTestCases
Bug: 303742236
Change-Id: I8efae9ffe083f8e33ea1bd221bc1ed05c1100a13
-rw-r--r-- | Android.bp | 3 | ||||
-rw-r--r-- | framework-s/Android.bp | 6 | ||||
-rw-r--r-- | framework-s/java/android/app/role/IRoleManager.aidl | 14 | ||||
-rw-r--r-- | framework-s/java/android/app/role/RoleManager.java | 49 | ||||
-rw-r--r-- | service/java/com/android/role/RoleService.java | 77 |
5 files changed, 116 insertions, 33 deletions
diff --git a/Android.bp b/Android.bp index bf7437814..59742acc1 100644 --- a/Android.bp +++ b/Android.bp @@ -21,6 +21,9 @@ apex { name: "com.android.permission", defaults: ["com.android.permission-defaults"], manifest: "apex_manifest.json", + compat_configs: [ + "framework-permission-s-compat-config" + ], } apex_defaults { diff --git a/framework-s/Android.bp b/framework-s/Android.bp index 076b497cb..096992362 100644 --- a/framework-s/Android.bp +++ b/framework-s/Android.bp @@ -56,6 +56,11 @@ java_library { sdk_version: "module_current", } +platform_compat_config { + name: "framework-permission-s-compat-config", + src: ":framework-permission-s", +} + java_sdk_library { name: "framework-permission-s", defaults: ["framework-module-defaults"], @@ -64,6 +69,7 @@ java_sdk_library { ], libs: [ "androidx.annotation_annotation", + "app-compat-annotations", "framework-annotations-lib", ], static_libs: [ diff --git a/framework-s/java/android/app/role/IRoleManager.aidl b/framework-s/java/android/app/role/IRoleManager.aidl index 5bcda037e..581bb20fa 100644 --- a/framework-s/java/android/app/role/IRoleManager.aidl +++ b/framework-s/java/android/app/role/IRoleManager.aidl @@ -25,9 +25,9 @@ import android.os.RemoteCallback; */ interface IRoleManager { - boolean isRoleAvailable(in String roleName); + boolean isRoleAvailableAsUser(in String roleName, int userId); - boolean isRoleHeld(in String roleName, in String packageName); + boolean isRoleHeldAsUser(in String roleName, in String packageName, int userId); List<String> getRoleHoldersAsUser(in String roleName, int userId); @@ -58,13 +58,15 @@ interface IRoleManager { void setRoleFallbackEnabledAsUser(in String roleName, boolean fallbackEnabled, int userId); - void setRoleNamesFromController(in List<String> roleNames); + void setRoleNamesFromControllerAsUser(in List<String> roleNames, int userId); - boolean addRoleHolderFromController(in String roleName, in String packageName); + boolean addRoleHolderFromControllerAsUser(in String roleName, in String packageName, + int userId); - boolean removeRoleHolderFromController(in String roleName, in String packageName); + boolean removeRoleHolderFromControllerAsUser(in String roleName, in String packageName, + int userId); - List<String> getHeldRolesFromController(in String packageName); + List<String> getHeldRolesFromControllerAsUser(in String packageName, int userId); String getBrowserRoleHolder(int userId); diff --git a/framework-s/java/android/app/role/RoleManager.java b/framework-s/java/android/app/role/RoleManager.java index cb3ebfe3c..4d8e4a1d8 100644 --- a/framework-s/java/android/app/role/RoleManager.java +++ b/framework-s/java/android/app/role/RoleManager.java @@ -28,6 +28,9 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.UserHandleAware; import android.annotation.UserIdInt; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.content.Context; import android.content.Intent; import android.os.Binder; @@ -212,6 +215,17 @@ public final class RoleManager { public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; /** + * For apps targeting Android V and above, several methods are now user-handle-aware, which + * means they use the user contained within the context. For apps targeting an SDK version + * <em>below</em> this, the user of the calling process will be used. + * + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + public static final long ROLE_MANAGER_USER_HANDLE_AWARE = 303742236L; + + /** * The action used to request user approval of a role for an application. * * @hide @@ -286,10 +300,12 @@ public final class RoleManager { * * @return whether the role is available in the system */ + @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) public boolean isRoleAvailable(@NonNull String roleName) { Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + UserHandle user = getContextUserIfAppropriate(); try { - return mService.isRoleAvailable(roleName); + return mService.isRoleAvailableAsUser(roleName, user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -302,10 +318,13 @@ public final class RoleManager { * * @return whether the calling application is holding the role */ + @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) public boolean isRoleHeld(@NonNull String roleName) { Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + UserHandle user = getContextUserIfAppropriate(); try { - return mService.isRoleHeld(roleName, mContext.getPackageName()); + return mService.isRoleHeldAsUser(roleName, mContext.getPackageName(), + user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -328,8 +347,9 @@ public final class RoleManager { @NonNull @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) @SystemApi + @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) public List<String> getRoleHolders(@NonNull String roleName) { - return getRoleHoldersAsUser(roleName, Process.myUserHandle()); + return getRoleHoldersAsUser(roleName, getContextUserIfAppropriate()); } /** @@ -755,10 +775,12 @@ public final class RoleManager { @Deprecated @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) @SystemApi + @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) public void setRoleNamesFromController(@NonNull List<String> roleNames) { Objects.requireNonNull(roleNames, "roleNames cannot be null"); + UserHandle user = getContextUserIfAppropriate(); try { - mService.setRoleNamesFromController(roleNames); + mService.setRoleNamesFromControllerAsUser(roleNames, user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -789,12 +811,15 @@ public final class RoleManager { @Deprecated @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) @SystemApi + @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) 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"); + UserHandle user = getContextUserIfAppropriate(); try { - return mService.addRoleHolderFromController(roleName, packageName); + return mService.addRoleHolderFromControllerAsUser(roleName, packageName, + user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -825,12 +850,15 @@ public final class RoleManager { @Deprecated @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) @SystemApi + @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) 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"); + UserHandle user = getContextUserIfAppropriate(); try { - return mService.removeRoleHolderFromController(roleName, packageName); + return mService.removeRoleHolderFromControllerAsUser(roleName, packageName, + user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -851,15 +879,22 @@ public final class RoleManager { @NonNull @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) @SystemApi + @UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) public List<String> getHeldRolesFromController(@NonNull String packageName) { Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); + UserHandle user = getContextUserIfAppropriate(); try { - return mService.getHeldRolesFromController(packageName); + return mService.getHeldRolesFromControllerAsUser(packageName, user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + private UserHandle getContextUserIfAppropriate() { + return CompatChanges.isChangeEnabled(ROLE_MANAGER_USER_HANDLE_AWARE) ? mContext.getUser() + : Process.myUserHandle(); + } + /** * Get the role holder of {@link #ROLE_BROWSER} without requiring * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java index 6845d506b..189b61f3e 100644 --- a/service/java/com/android/role/RoleService.java +++ b/service/java/com/android/role/RoleService.java @@ -415,22 +415,33 @@ public class RoleService extends SystemService implements RoleUserState.Callback private class Stub extends IRoleManager.Stub { @Override - public boolean isRoleAvailable(@NonNull String roleName) { + public boolean isRoleAvailableAsUser(@NonNull String roleName, @UserIdInt int userId) { + UserUtils.enforceCrossUserPermission(userId, false, "isRoleAvailableAsUser", + getContext()); + if (!UserUtils.isUserExistent(userId, getContext())) { + Log.e(LOG_TAG, "user " + userId + " does not exist"); + return false; + } + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); - int userId = UserHandleCompat.getUserId(getCallingUid()); return getOrCreateUserState(userId).isRoleAvailable(roleName); } @Override - public boolean isRoleHeld(@NonNull String roleName, @NonNull String packageName) { - int callingUid = getCallingUid(); - mAppOpsManager.checkPackage(callingUid, packageName); + public boolean isRoleHeldAsUser(@NonNull String roleName, @NonNull String packageName, + @UserIdInt int userId) { + mAppOpsManager.checkPackage(getCallingUid(), packageName); + + UserUtils.enforceCrossUserPermission(userId, false, "isRoleHeldAsUser", getContext()); + if (!UserUtils.isUserExistent(userId, getContext())) { + Log.e(LOG_TAG, "user " + userId + " does not exist"); + return false; + } Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); - int userId = UserHandleCompat.getUserId(callingUid); ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName); if (roleHolders == null) { return false; @@ -685,54 +696,80 @@ public class RoleService extends SystemService implements RoleUserState.Callback } @Override - public void setRoleNamesFromController(@NonNull List<String> roleNames) { + public void setRoleNamesFromControllerAsUser(@NonNull List<String> roleNames, + @UserIdInt int userId) { + UserUtils.enforceCrossUserPermission(userId, false, "setRoleNamesFromControllerAsUser", + getContext()); + if (!UserUtils.isUserExistent(userId, getContext())) { + Log.e(LOG_TAG, "user " + userId + " does not exist"); + return; + } + getContext().enforceCallingOrSelfPermission( RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, - "setRoleNamesFromController"); + "setRoleNamesFromControllerAsUser"); Objects.requireNonNull(roleNames, "roleNames cannot be null"); - int userId = UserHandleCompat.getUserId(Binder.getCallingUid()); getOrCreateUserState(userId).setRoleNames(roleNames); } @Override - public boolean addRoleHolderFromController(@NonNull String roleName, - @NonNull String packageName) { + public boolean addRoleHolderFromControllerAsUser(@NonNull String roleName, + @NonNull String packageName, @UserIdInt int userId) { + UserUtils.enforceCrossUserPermission(userId, false, + "addRoleHolderFromControllerAsUser", getContext()); + if (!UserUtils.isUserExistent(userId, getContext())) { + Log.e(LOG_TAG, "user " + userId + " does not exist"); + return false; + } + getContext().enforceCallingOrSelfPermission( RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, - "addRoleHolderFromController"); + "addRoleHolderFromControllerAsUser"); Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); - int userId = UserHandleCompat.getUserId(Binder.getCallingUid()); return getOrCreateUserState(userId).addRoleHolder(roleName, packageName); } @Override - public boolean removeRoleHolderFromController(@NonNull String roleName, - @NonNull String packageName) { + public boolean removeRoleHolderFromControllerAsUser(@NonNull String roleName, + @NonNull String packageName, @UserIdInt int userId) { + UserUtils.enforceCrossUserPermission(userId, false, + "removeRoleHolderFromControllerAsUser", getContext()); + if (!UserUtils.isUserExistent(userId, getContext())) { + Log.e(LOG_TAG, "user " + userId + " does not exist"); + return false; + } + getContext().enforceCallingOrSelfPermission( RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, - "removeRoleHolderFromController"); + "removeRoleHolderFromControllerAsUser"); Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); - int userId = UserHandleCompat.getUserId(Binder.getCallingUid()); return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName); } @Override - public List<String> getHeldRolesFromController(@NonNull String packageName) { + public List<String> getHeldRolesFromControllerAsUser(@NonNull String packageName, + @UserIdInt int userId) { + UserUtils.enforceCrossUserPermission(userId, false, + "getHeldRolesFromControllerAsUser", getContext()); + if (!UserUtils.isUserExistent(userId, getContext())) { + Log.e(LOG_TAG, "user " + userId + " does not exist"); + return Collections.emptyList(); + } + getContext().enforceCallingOrSelfPermission( RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, - "getRolesHeldFromController"); + "getHeldRolesFromControllerAsUser"); Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); - int userId = UserHandleCompat.getUserId(Binder.getCallingUid()); return getOrCreateUserState(userId).getHeldRoles(packageName); } |