diff options
author | 2024-12-06 17:13:15 +0000 | |
---|---|---|
committer | 2024-12-06 17:13:15 +0000 | |
commit | be4c76d7141ea4627e3ee3fbf645f4ac33b26e04 (patch) | |
tree | dc4f3afc4aae28bc7634a8ae599e09bcda722dd1 | |
parent | 2b30e488f3ca6fbe32c403fee708101683e0041f (diff) | |
parent | 769838e9a9d864bc64fd88a2c8bdd47e1b90007b (diff) |
Merge "Add get/setDefaultHoldersForTest and is/setRoleVisibleForTest" into main
9 files changed, 542 insertions, 29 deletions
diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml index d67a3582d..9fa361b57 100644 --- a/PermissionController/res/values/strings.xml +++ b/PermissionController/res/values/strings.xml @@ -1243,6 +1243,17 @@ <string name="role_wallet_request_title">Set <xliff:g id="app_name" example="Super Wallet">%1$s</xliff:g> as your default wallet app?</string> <string name="role_wallet_request_description">No permissions needed</string> + <!-- Label for the RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY role. [DO NOT TRANSLATE] --> + <string name="role_for_testing_profile_group_exclusivity_label" translatable="false">Default test profile group exclusive role app</string> + <!-- Short label for the RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY role. [DO NOT TRANSLATE] --> + <string name="role_for_testing_profile_group_exclusivity_short_label" translatable="false">Test profile group exclusive role app</string> + <!-- Description for the RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY role. [DO NOT TRANSLATE] --> + <string name="role_for_testing_profile_group_exclusivity_description" translatable="false">Test profile group exclusive role apps are for tests only and should not be held by production apps.</string> + <!-- Request title for the RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY role. [DO NOT TRANSLATE] --> + <string name="role_for_testing_profile_group_exclusivity_request_title" translatable="false">Set <xliff:g id="app_name" example="Super test app">%1$s</xliff:g> as your default test profile group exclusive role app?</string> + <!-- Request description for the RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY role. [DO NOT TRANSLATE] --> + <string name="role_for_testing_profile_group_exclusivity_request_description" translatable="false">No permissions needed</string> + <!-- Subtitle for the application that is the current default application [CHAR LIMIT=30] --> <string name="request_role_current_default">Current default</string> diff --git a/PermissionController/res/xml/roles.xml b/PermissionController/res/xml/roles.xml index 7c6aa2216..3d858a9c5 100644 --- a/PermissionController/res/xml/roles.xml +++ b/PermissionController/res/xml/roles.xml @@ -1875,12 +1875,18 @@ <role name="android.app.role.RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY" behavior="ReservedForTestingProfileGroupExclusivityRoleBehavior" + description="@string/role_for_testing_profile_group_exclusivity_description" exclusive="true" exclusivity="profileGroup" fallBackToDefaultHolder="true" featureFlag="com.android.permission.flags.Flags.crossUserRoleEnabled" + label="@string/role_for_testing_profile_group_exclusivity_label" + requestable="true" + requestDescription="@string/role_for_testing_profile_group_exclusivity_request_description" + requestTitle="@string/role_for_testing_profile_group_exclusivity_request_title" + shortLabel="@string/role_for_testing_profile_group_exclusivity_short_label" showNone="true" - visible="false"/> + visible="true"/> <!--- ~ A role for the vendor package that provides privacy-preserving intelligent processor for diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java index 71f988279..a9be00806 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java @@ -16,6 +16,7 @@ package com.android.role.controller.behavior; +import android.app.role.RoleManager; import android.content.Context; import android.os.UserHandle; @@ -24,20 +25,34 @@ import androidx.annotation.Nullable; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; +import com.android.role.controller.util.RoleFlags; +import com.android.role.controller.util.UserUtils; -import java.util.Arrays; import java.util.List; public class ReservedForTestingProfileGroupExclusivityRoleBehavior implements RoleBehavior { - // TODO(b/381315745): Update to use API for setting and getting test role default holders. - // This role doesn't grant any privileges, so this should be ok. - private static final List<String> DEFAULT_HOLDERS = - Arrays.asList("android.app.rolemultiuser.cts.app"); - @Nullable @Override public List<String> getDefaultHoldersAsUser(@NonNull Role role, @NonNull UserHandle user, @NonNull Context context) { - return DEFAULT_HOLDERS; + if (RoleFlags.isProfileGroupExclusivityAvailable()) { + Context userContext = UserUtils.getUserContext(context, user); + RoleManager roleManager = userContext.getSystemService(RoleManager.class); + return roleManager.getDefaultHoldersForTest(role.getName()); + } else { + return null; + } + } + + @Override + public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + if (RoleFlags.isProfileGroupExclusivityAvailable()) { + Context userContext = UserUtils.getUserContext(context, user); + RoleManager roleManager = userContext.getSystemService(RoleManager.class); + return roleManager.isRoleVisibleForTest(role.getName()); + } else { + return false; + } } } diff --git a/framework-s/api/system-current.txt b/framework-s/api/system-current.txt index a8cac03aa..efab125bd 100644 --- a/framework-s/api/system-current.txt +++ b/framework-s/api/system-current.txt @@ -41,6 +41,7 @@ package android.app.role { method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @FlaggedApi("com.android.permission.flags.cross_user_role_enabled") @Nullable @RequiresPermission(allOf={android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, android.Manifest.permission.MANAGE_ROLE_HOLDERS, android.Manifest.permission.MANAGE_DEFAULT_APPLICATIONS}, conditional=true) public android.os.UserHandle getActiveUserForRole(@NonNull String); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_DEFAULT_APPLICATIONS) public String getDefaultApplication(@NonNull String); + method @FlaggedApi("com.android.permission.flags.cross_user_role_enabled") @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getDefaultHoldersForTest(@NonNull String); method @Deprecated @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle); @@ -48,14 +49,17 @@ package android.app.role { method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean isBypassingRoleQualification(); method @FlaggedApi("android.permission.flags.system_server_role_controller_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean isRoleFallbackEnabled(@NonNull String); method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @FlaggedApi("com.android.permission.flags.cross_user_role_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean isRoleVisibleForTest(@NonNull String); method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @Deprecated @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String); method @FlaggedApi("com.android.permission.flags.cross_user_role_enabled") @RequiresPermission(allOf={android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, android.Manifest.permission.MANAGE_ROLE_HOLDERS, android.Manifest.permission.MANAGE_DEFAULT_APPLICATIONS}, conditional=true) public void setActiveUserForRole(@NonNull String, @NonNull android.os.UserHandle, int); method @RequiresPermission(android.Manifest.permission.BYPASS_ROLE_QUALIFICATION) public void setBypassingRoleQualification(boolean); method @RequiresPermission(android.Manifest.permission.MANAGE_DEFAULT_APPLICATIONS) public void setDefaultApplication(@NonNull String, @Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @FlaggedApi("com.android.permission.flags.cross_user_role_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void setDefaultHoldersForTest(@NonNull String, @Nullable java.util.List<java.lang.String>); method @FlaggedApi("android.permission.flags.system_server_role_controller_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void setRoleFallbackEnabled(@NonNull String, boolean); method @Deprecated @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>); + method @FlaggedApi("com.android.permission.flags.cross_user_role_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void setRoleVisibleForTest(@NonNull String, boolean); field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1 field public static final String ROLE_DEVICE_POLICY_MANAGEMENT = "android.app.role.DEVICE_POLICY_MANAGEMENT"; field public static final String ROLE_FINANCED_DEVICE_KIOSK = "android.app.role.FINANCED_DEVICE_KIOSK"; diff --git a/framework-s/java/android/app/role/IRoleManager.aidl b/framework-s/java/android/app/role/IRoleManager.aidl index cd0079e08..dc5bc8cb4 100644 --- a/framework-s/java/android/app/role/IRoleManager.aidl +++ b/framework-s/java/android/app/role/IRoleManager.aidl @@ -84,4 +84,12 @@ interface IRoleManager { boolean isApplicationVisibleForRoleAsUser(in String roleName, in String packageName, int userId); + + List<String> getDefaultHoldersForTest(in String roleName); + + void setDefaultHoldersForTest(in String roleName, in List<String> packageNames); + + boolean isRoleVisibleForTest(in String roleName); + + void setRoleVisibleForTest(in String roleName, boolean visible); } diff --git a/framework-s/java/android/app/role/RoleManager.java b/framework-s/java/android/app/role/RoleManager.java index 6f62fdd76..42445b4d6 100644 --- a/framework-s/java/android/app/role/RoleManager.java +++ b/framework-s/java/android/app/role/RoleManager.java @@ -1166,6 +1166,118 @@ public final class RoleManager { } } + /** + * Get the default holders of this role, which will be added when the role is added for the + * first time. + * <p> + * <strong>Note:</strong> Use of this API should be limited to tests. The values returned are + * not persisted. + * <p> + * Throws {@link IllegalArgumentException} if role is not a test role + * + * @param roleName the name of the role to get test default holders for + * @return the list of package names of the default holders + * + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) + @RequiresApi(Build.VERSION_CODES.BAKLAVA) + @SystemApi + @UserHandleAware + @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @NonNull + public List<String> getDefaultHoldersForTest(@NonNull String roleName) { + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + try { + return mService.getDefaultHoldersForTest(roleName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set the default holders of this role, which will be added when the role is added for the + * first time. + * <p> + * <strong>Note:</strong> Use of this API should be limited to tests. The values used are + * not persisted. + * <p> + * Throws {@link IllegalArgumentException} if role is not a test role + * + * @param roleName the name of the role to set test default holders for + * @param packageNames a list of package names of the default holders or {@code null} to unset + * + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) + @RequiresApi(Build.VERSION_CODES.BAKLAVA) + @SystemApi + @UserHandleAware + @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + public void setDefaultHoldersForTest( + @NonNull String roleName, @Nullable List<String> packageNames) { + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + try { + mService.setDefaultHoldersForTest(roleName, packageNames); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get whether a role should be visible for testing. + * <p> + * <strong>Note:</strong> Use of this API should be limited to tests. The values returned are + * not persisted. + * <p> + * Throws {@link IllegalArgumentException} if role is not a test role + * + * @param roleName the name of the role to get test visibility for + * @return {@code true} if role is visible, {@code false} otherwise + * + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) + @RequiresApi(Build.VERSION_CODES.BAKLAVA) + @SystemApi + @UserHandleAware + @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + public boolean isRoleVisibleForTest(@NonNull String roleName) { + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + try { + return mService.isRoleVisibleForTest(roleName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set whether a role should be visible for testing. + * <p> + * <strong>Note:</strong> Use of this API should be limited to tests. The values used are + * not persisted. + * <p> + * Throws {@link IllegalArgumentException} if role is not a test role + * + * @param roleName the name of the role to set test visibility for + * @param visible {@code true} to set role as visible, {@code false} otherwise + * + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) + @RequiresApi(Build.VERSION_CODES.BAKLAVA) + @SystemApi + @UserHandleAware + @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + public void setRoleVisibleForTest(@NonNull String roleName, boolean visible) { + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + try { + mService.setRoleVisibleForTest(roleName, visible); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @NonNull private RoleControllerManager getRoleControllerManager() { synchronized (mRoleControllerManagerLock) { diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java index 7c2ab01b1..f6c9fc6b6 100644 --- a/service/java/com/android/role/RoleService.java +++ b/service/java/com/android/role/RoleService.java @@ -16,6 +16,8 @@ package com.android.role; +import static android.app.role.RoleManager.ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY; + import android.Manifest; import android.annotation.AnyThread; import android.annotation.MainThread; @@ -49,6 +51,7 @@ import android.permission.flags.Flags; import android.permission.internal.compat.UserHandleCompat; import android.provider.Settings; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.Log; @@ -120,12 +123,21 @@ public class RoleService extends SystemService implements RoleUserState.Callback defaultApplicationRoles.add(RoleManager.ROLE_WALLET); } if (RoleFlags.isProfileGroupExclusivityAvailable()) { - defaultApplicationRoles.add( - RoleManager.ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY); + defaultApplicationRoles.add(ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY); } DEFAULT_APPLICATION_ROLES = defaultApplicationRoles.toArray(new String[0]); } + private static final String[] TEST_ROLES; + + static { + if (RoleFlags.isProfileGroupExclusivityAvailable()) { + TEST_ROLES = new String[] {ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY}; + } else { + TEST_ROLES = new String[0]; + } + } + @NonNull private final AppOpsManager mAppOpsManager; @@ -171,6 +183,14 @@ public class RoleService extends SystemService implements RoleUserState.Callback private final SparseArray<ThrottledRunnable> mGrantDefaultRolesThrottledRunnables = new SparseArray<>(); + @GuardedBy("mLock") + @NonNull + private final Map<String, List<String>> mDefaultHoldersForTest = new ArrayMap<>(); + + @GuardedBy("mLock") + @NonNull + private final Set<String> mRolesVisibleForTest = new ArraySet<>(); + public RoleService(@NonNull Context context) { super(context); @@ -1156,6 +1176,70 @@ public class RoleService extends SystemService implements RoleUserState.Callback } @Override + public List<String> getDefaultHoldersForTest(String roleName) { + Preconditions.checkState(RoleFlags.isProfileGroupExclusivityAvailable(), + "getDefaultHoldersForTest not available"); + getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, + "getDefaultHoldersForTest"); + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + Preconditions.checkArgumentIsSupported(TEST_ROLES, roleName); + + synchronized (mLock) { + return mDefaultHoldersForTest.getOrDefault(roleName, Collections.emptyList()); + } + } + + @Override + public void setDefaultHoldersForTest(String roleName, List<String> packageNames) { + Preconditions.checkState(RoleFlags.isProfileGroupExclusivityAvailable(), + "setDefaultHoldersForTest not available"); + getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, + "setDefaultHoldersForTest"); + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + Preconditions.checkArgumentIsSupported(TEST_ROLES, roleName); + + synchronized (mLock) { + if (packageNames == null || packageNames.isEmpty()) { + mDefaultHoldersForTest.remove(roleName); + } else { + mDefaultHoldersForTest.put(roleName, packageNames); + } + } + } + + @Override + public boolean isRoleVisibleForTest(String roleName) { + Preconditions.checkState(RoleFlags.isProfileGroupExclusivityAvailable(), + "isRoleVisibleForTest not available"); + getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, + "isRoleVisibleForTest"); + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + Preconditions.checkArgumentIsSupported(TEST_ROLES, roleName); + + synchronized (mLock) { + return mRolesVisibleForTest.contains(roleName); + } + } + + @Override + public void setRoleVisibleForTest(String roleName, boolean visible) { + Preconditions.checkState(RoleFlags.isProfileGroupExclusivityAvailable(), + "setRoleVisibleForTest not available"); + getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, + "setRoleVisibleForTest"); + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + Preconditions.checkArgumentIsSupported(TEST_ROLES, roleName); + + synchronized (mLock) { + if (visible) { + mRolesVisibleForTest.add(roleName); + } else { + mRolesVisibleForTest.remove(roleName); + } + } + } + + @Override protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args) { if (!checkDumpPermission("role", fout)) { diff --git a/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java b/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java index 92ea5d98c..00245a086 100644 --- a/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java +++ b/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java @@ -45,6 +45,7 @@ import android.os.Build; import android.os.Process; import android.os.UserHandle; import android.permission.flags.Flags; +import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -1355,7 +1356,7 @@ public class RoleManagerTest { @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") @Test public void cannotGetActiveUserForRoleWithoutPermission() throws Exception { - assertThrows(SecurityException.class, ()-> + assertThrows(SecurityException.class, () -> sRoleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME)); } @@ -1373,7 +1374,7 @@ public class RoleManagerTest { @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") @Test public void cannotSetActiveUserForRoleWithoutPermission() throws Exception { - assertThrows(SecurityException.class, ()-> + assertThrows(SecurityException.class, () -> sRoleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, Process.myUserHandle(), 0)); } @@ -1401,6 +1402,237 @@ public class RoleManagerTest { }); } + @RequiresFlagsDisabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetDefaultHoldersForTestFlagDisabled() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalStateException.class, () -> + sRoleManager.getDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetDefaultHoldersForTestNoPermissions() throws Exception { + assertThrows(SecurityException.class, () -> + sRoleManager.getDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetDefaultHoldersForTestEmptyRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.getDefaultHoldersForTest("")); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetDefaultHoldersForTestNonTestRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.getDefaultHoldersForTest( + RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER)); + }); + } + + @RequiresFlagsDisabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetDefaultHoldersForTestFlagDisabled() throws Exception { + List<String> testRoleHolders = List.of("a", "b", "c"); + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalStateException.class, () -> + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + testRoleHolders)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetDefaultHoldersForTestNoPermissions() throws Exception { + List<String> testRoleHolders = List.of("a", "b", "c"); + assertThrows(SecurityException.class, () -> + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + testRoleHolders)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetDefaultHoldersForTestEmptyRoleName() throws Exception { + List<String> testRoleHolders = List.of("a", "b", "c"); + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.setDefaultHoldersForTest("", testRoleHolders)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetDefaultHoldersForTestNonTestRoleName() throws Exception { + List<String> testRoleHolders = List.of("a", "b", "c"); + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.setDefaultHoldersForTest( + RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER, testRoleHolders)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetDefaultHolders() throws Exception { + List<String> testRoleHolders = List.of("a", "b", "c"); + runWithShellPermissionIdentity(() -> { + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + testRoleHolders); + List<String> roleHolders = + sRoleManager.getDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME); + assertThat(roleHolders).isEqualTo(testRoleHolders); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetDefaultHoldersNoRoleHolders() throws Exception { + List<String> initialRoleHolders = List.of("a", "b", "c"); + List<String> testRoleHolders = Collections.emptyList(); + runWithShellPermissionIdentity(() -> { + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + initialRoleHolders); + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + testRoleHolders); + List<String> roleHolders = + sRoleManager.getDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME); + assertThat(roleHolders).isEqualTo(testRoleHolders); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetDefaultHoldersNullRoleHolders() throws Exception { + List<String> initialRoleHolders = List.of("a", "b", "c"); + runWithShellPermissionIdentity(() -> { + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, + initialRoleHolders); + sRoleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, null); + List<String> roleHolders = + sRoleManager.getDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME); + assertThat(roleHolders).isEqualTo(Collections.emptyList()); + }); + } + + @RequiresFlagsDisabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetIsRoleVisibleForTestFlagDisabled() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalStateException.class, () -> + sRoleManager.isRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetIsRoleVisibleForTestNoPermissions() throws Exception { + assertThrows(SecurityException.class, () -> + sRoleManager.isRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetIsRoleVisibleForTestEmptyRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.isRoleVisibleForTest("")); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotGetIsRoleVisibleForTestNonTestRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.isRoleVisibleForTest(RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER)); + }); + } + + @RequiresFlagsDisabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetRoleVisibleForTestFlagDisabled() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalStateException.class, () -> + sRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, false)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetRoleVisibleForTestNoPermissions() throws Exception { + assertThrows(SecurityException.class, () -> + sRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, false)); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetRoleVisibleForTestEmptyRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.setRoleVisibleForTest("", false)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void cannotSetRoleVisibleForTestNonTestRoleName() throws Exception { + runWithShellPermissionIdentity(() -> { + assertThrows(IllegalArgumentException.class, () -> + sRoleManager.setRoleVisibleForTest(RoleManager.ROLE_SYSTEM_ACTIVITY_RECOGNIZER, + false)); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetIsRoleVisibleForTestSetTrue() throws Exception { + runWithShellPermissionIdentity(() -> { + sRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, true); + boolean isRoleVisibleForTest = + sRoleManager.isRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME); + assertThat(isRoleVisibleForTest).isEqualTo(true); + }); + } + + @RequiresFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") + @Test + public void setAndGetIsRoleVisibleForTestSetFalse() throws Exception { + runWithShellPermissionIdentity(() -> { + sRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME, false); + boolean isRoleVisibleForTest = + sRoleManager.isRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVE_ROLE_NAME); + assertThat(isRoleVisibleForTest).isEqualTo(false); + }); + } + @NonNull private List<String> getRoleHolders(@NonNull String roleName) throws Exception { return callWithShellPermissionIdentity(() -> sRoleManager.getRoleHolders(roleName)); diff --git a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt index e4f9ce55c..80507d0c8 100644 --- a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt +++ b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt @@ -225,9 +225,20 @@ class RoleManagerMultiUserTest { @Test @Throws(java.lang.Exception::class) fun ensureOnlyActiveUserIsRoleHolder() { - val activeUser = roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)!! - // Test app install might take a moment - eventually { assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(activeUser) } + try { + // Set test default role holder. Ensures fallbacks to a default holder + roleManager.setDefaultHoldersForTest( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + listOf(APP_PACKAGE_NAME), + ) + + val activeUser = roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)!! + // Test app install might take a moment + eventually { assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(activeUser) } + } finally { + // Clear test default role holder + roleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, null) + } } @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) @@ -286,11 +297,26 @@ class RoleManagerMultiUserTest { } roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) - roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, targetActiveUser, 0) - assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) - .isEqualTo(targetActiveUser) - // We can assume targetActiveUser is role holder since fallback is enabled - assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + try { + // Set test default role holder. Ensures fallbacks to a default holder + roleManager.setDefaultHoldersForTest( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + listOf(APP_PACKAGE_NAME), + ) + + roleManager.setActiveUserForRole( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + targetActiveUser, + 0, + ) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + // We can assume targetActiveUser is role holder since fallback is enabled + eventually { assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) } + } finally { + // Clear test default role holder + roleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, null) + } } @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) @@ -299,13 +325,28 @@ class RoleManagerMultiUserTest { @Test @Throws(Exception::class) fun setAndGetActiveUserForRoleSetWorkProfile() { - val targetActiveUser = deviceState.workProfile().userHandle() - roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, targetActiveUser, 0) + try { + // Set test default role holder. Ensures fallbacks to a default holder + roleManager.setDefaultHoldersForTest( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + listOf(APP_PACKAGE_NAME), + ) - assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) - .isEqualTo(targetActiveUser) - // We can assume targetActiveUser is role holder since fallback is enabled - assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) + val targetActiveUser = deviceState.workProfile().userHandle() + roleManager.setActiveUserForRole( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + targetActiveUser, + 0, + ) + + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + // We can assume targetActiveUser is role holder since fallback is enabled + eventually { assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) } + } finally { + // Clear test default role holder + roleManager.setDefaultHoldersForTest(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, null) + } } @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) @@ -519,13 +560,13 @@ class RoleManagerMultiUserTest { private fun assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser( expectedActiveUser: UserHandle ) { - users().profileGroup().forEach { userReference -> + for (userReference in users().profileGroup()) { val user = userReference.userHandle() if (Objects.equals(user, expectedActiveUser)) { val roleHolders = roleManager.getRoleHoldersAsUser(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, user) assertWithMessage( - "Expected user ${user.identifier} to have a role holder for" + + "Expected user ${user.identifier} to have a role holder for " + " $PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME" ) .that(roleHolders) @@ -553,7 +594,7 @@ class RoleManagerMultiUserTest { private fun assertExpectedProfileHasRoleUsingGetDefaultApplication( expectedActiveUser: UserHandle ) { - users().profileGroup().forEach { userReference -> + for (userReference in users().profileGroup()) { val user = userReference.userHandle() val userRoleManager = getRoleManagerForUser(user) if (Objects.equals(user, expectedActiveUser)) { |