diff options
-rw-r--r-- | flags/flags.aconfig | 2 | ||||
-rw-r--r-- | framework-s/Android.bp | 1 | ||||
-rw-r--r-- | framework-s/api/system-current.txt | 2 | ||||
-rw-r--r-- | framework-s/jarjar-rules.txt | 1 | ||||
-rw-r--r-- | framework-s/java/android/app/role/IRoleManager.aidl | 4 | ||||
-rw-r--r-- | framework-s/java/android/app/role/RoleManager.java | 49 | ||||
-rw-r--r-- | service/Android.bp | 1 | ||||
-rw-r--r-- | service/api/system-server-current.txt | 2 | ||||
-rw-r--r-- | service/jarjar-rules.txt | 1 | ||||
-rw-r--r-- | service/java/com/android/role/RoleService.java | 36 | ||||
-rw-r--r-- | service/java/com/android/role/RoleUserState.java | 52 | ||||
-rw-r--r-- | service/java/com/android/role/persistence/RolesPersistenceImpl.java | 12 | ||||
-rw-r--r-- | service/java/com/android/role/persistence/RolesState.java | 41 | ||||
-rw-r--r-- | service/proto/role_service.proto | 3 | ||||
-rw-r--r-- | tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt | 50 | ||||
-rw-r--r-- | tests/cts/role/src/android/app/role/cts/RoleManagerTest.java | 12 |
16 files changed, 248 insertions, 21 deletions
diff --git a/flags/flags.aconfig b/flags/flags.aconfig index 050065368..64a9647ba 100644 --- a/flags/flags.aconfig +++ b/flags/flags.aconfig @@ -5,4 +5,4 @@ flag { namespace: "permissions" description: "This flag is used to support hotword activation events in privacy dashboard" bug: "287264308" -}
\ No newline at end of file +} diff --git a/framework-s/Android.bp b/framework-s/Android.bp index e017a7ea5..076b497cb 100644 --- a/framework-s/Android.bp +++ b/framework-s/Android.bp @@ -69,6 +69,7 @@ java_sdk_library { static_libs: [ "framework-permission-s-shared", "modules-utils-build", + "android.permission.flags-aconfig-java", ], apex_available: [ "com.android.permission", diff --git a/framework-s/api/system-current.txt b/framework-s/api/system-current.txt index 9545356a4..f502a3231 100644 --- a/framework-s/api/system-current.txt +++ b/framework-s/api/system-current.txt @@ -29,12 +29,14 @@ package android.app.role { method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean isBypassingRoleQualification(); + method @FlaggedApi(android.permission.flags.Flags.FLAG_ROLE_CONTROLLER_IN_SYSTEM_SERVER) @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 @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 @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(android.permission.flags.Flags.FLAG_ROLE_CONTROLLER_IN_SYSTEM_SERVER) @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>); 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"; diff --git a/framework-s/jarjar-rules.txt b/framework-s/jarjar-rules.txt index 3b888fe99..39f2ad3b7 100644 --- a/framework-s/jarjar-rules.txt +++ b/framework-s/jarjar-rules.txt @@ -1,4 +1,5 @@ rule android.os.HandlerExecutor android.permission.jarjar.@0 +rule android.permission.flags.** android.permission.jarjar.@0 rule android.util.IndentingPrintWriter android.permission.jarjar.@0 rule com.android.internal.** android.permission.jarjar.@0 rule com.android.modules.** android.permission.jarjar.@0 diff --git a/framework-s/java/android/app/role/IRoleManager.aidl b/framework-s/java/android/app/role/IRoleManager.aidl index 5f7cb1bf5..5bcda037e 100644 --- a/framework-s/java/android/app/role/IRoleManager.aidl +++ b/framework-s/java/android/app/role/IRoleManager.aidl @@ -54,6 +54,10 @@ interface IRoleManager { void setBypassingRoleQualification(boolean bypassRoleQualification); + boolean isRoleFallbackEnabledAsUser(in String roleName, int userId); + + void setRoleFallbackEnabledAsUser(in String roleName, boolean fallbackEnabled, int userId); + void setRoleNamesFromController(in List<String> roleNames); boolean addRoleHolderFromController(in String roleName, in String packageName); diff --git a/framework-s/java/android/app/role/RoleManager.java b/framework-s/java/android/app/role/RoleManager.java index d8e7149f2..cb3ebfe3c 100644 --- a/framework-s/java/android/app/role/RoleManager.java +++ b/framework-s/java/android/app/role/RoleManager.java @@ -18,6 +18,7 @@ package android.app.role; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -35,6 +36,7 @@ import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.UserHandle; +import android.permission.flags.Flags; import android.util.ArrayMap; import android.util.SparseArray; @@ -690,6 +692,53 @@ public final class RoleManager { } /** + * Check whether role currently enables fallback to default holder. + * <p> + * This is based on the "None" holder being actively selected, in which case don't fallback. + * + * @param roleName the name of the role being queried + * + * @return whether fallback is enabled for the provided role + * + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) + @FlaggedApi(Flags.FLAG_ROLE_CONTROLLER_IN_SYSTEM_SERVER) + @UserHandleAware + @SystemApi + public boolean isRoleFallbackEnabled(@NonNull String roleName) { + try { + return mService.isRoleFallbackEnabledAsUser(roleName, + mContext.getUser().getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set whether role should fallback to a default role holder. + * + * @param roleName the name of the role being queried. + * @param fallbackEnabled whether to enable fallback holders for this role. + * + * @hide + */ + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) + @FlaggedApi(Flags.FLAG_ROLE_CONTROLLER_IN_SYSTEM_SERVER) + @UserHandleAware + @SystemApi + public void setRoleFallbackEnabled(@NonNull String roleName, boolean fallbackEnabled) { + try { + mService.setRoleFallbackEnabledAsUser(roleName, fallbackEnabled, + mContext.getUser().getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Set the names of all the available roles. Should only be called from * {@link android.app.role.RoleControllerService}. * <p> diff --git a/service/Android.bp b/service/Android.bp index 96b8fbb96..a6513508a 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -108,6 +108,7 @@ java_sdk_library { "service-permission-shared", "service-permission-statsd", "service-permission-proto-stream", + "android.permission.flags-aconfig-java", ], errorprone: { javacflags: ["-Xep:GuardedBy:ERROR"], diff --git a/service/api/system-server-current.txt b/service/api/system-server-current.txt index b1869c2c7..ea9c9750c 100644 --- a/service/api/system-server-current.txt +++ b/service/api/system-server-current.txt @@ -45,6 +45,8 @@ package com.android.role.persistence { public final class RolesState { ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>); + ctor @FlaggedApi(android.permission.flags.Flags.FLAG_ROLE_CONTROLLER_IN_SYSTEM_SERVER) public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>, @NonNull java.util.Set<java.lang.String>); + method @FlaggedApi(android.permission.flags.Flags.FLAG_ROLE_CONTROLLER_IN_SYSTEM_SERVER) @NonNull public java.util.Set<java.lang.String> getFallbackEnabledRoles(); method @Nullable public String getPackagesHash(); method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles(); method public int getVersion(); diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt index 2b8765cf5..a3fd75930 100644 --- a/service/jarjar-rules.txt +++ b/service/jarjar-rules.txt @@ -1,4 +1,5 @@ rule android.os.HandlerExecutor com.android.permission.jarjar.@0 +rule android.permission.flags.** com.android.permission.jarjar.@0 rule android.util.IndentingPrintWriter com.android.permission.jarjar.@0 rule com.android.internal.** com.android.permission.jarjar.@0 rule com.android.modules.** com.android.permission.jarjar.@0 diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java index f18a9e79e..6845d506b 100644 --- a/service/java/com/android/role/RoleService.java +++ b/service/java/com/android/role/RoleService.java @@ -649,6 +649,42 @@ public class RoleService extends SystemService implements RoleUserState.Callback } @Override + public boolean isRoleFallbackEnabledAsUser(@NonNull String roleName, + @UserIdInt int userId) { + UserUtils.enforceCrossUserPermission(userId, false, "isRoleFallbackEnabledAsUser", + getContext()); + if (!UserUtils.isUserExistent(userId, getContext())) { + Log.e(LOG_TAG, "user " + userId + " does not exist"); + return false; + } + + getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, + "isRoleFallbackEnabledAsUser"); + + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + + return getOrCreateUserState(userId).isFallbackEnabled(roleName); + } + + @Override + public void setRoleFallbackEnabledAsUser(@NonNull String roleName, boolean fallbackEnabled, + @UserIdInt int userId) { + UserUtils.enforceCrossUserPermission(userId, false, "setRoleFallbackEnabledAsUser", + getContext()); + if (!UserUtils.isUserExistent(userId, getContext())) { + Log.e(LOG_TAG, "user " + userId + " does not exist"); + return; + } + + getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, + "setRoleFallbackEnabledAsUser"); + + Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); + + getOrCreateUserState(userId).setFallbackEnabled(roleName, fallbackEnabled); + } + + @Override public void setRoleNamesFromController(@NonNull List<String> roleNames) { getContext().enforceCallingOrSelfPermission( RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, diff --git a/service/java/com/android/role/RoleUserState.java b/service/java/com/android/role/RoleUserState.java index 727e0f122..201633898 100644 --- a/service/java/com/android/role/RoleUserState.java +++ b/service/java/com/android/role/RoleUserState.java @@ -53,6 +53,8 @@ class RoleUserState { public static final int VERSION_UNDEFINED = -1; + public static final int VERSION_FALLBACK_STATE_MIGRATED = 1; + private static final long WRITE_DELAY_MILLIS = 200; private final RolesPersistence mPersistence = RolesPersistence.createInstance(); @@ -86,6 +88,13 @@ class RoleUserState { @NonNull private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>(); + /** + * + */ + @GuardedBy("mLock") + @NonNull + private ArraySet<String> mFallbackEnabledRoles = new ArraySet<>(); + @GuardedBy("mLock") private boolean mWriteScheduled; @@ -193,6 +202,31 @@ class RoleUserState { } } + public boolean isFallbackEnabled(@NonNull String roleName) { + synchronized (mLock) { + return mFallbackEnabledRoles.contains(roleName); + } + } + + public void setFallbackEnabled(@NonNull String roleName, boolean fallbackEnabled) { + synchronized (mLock) { + if (!mRoles.containsKey(roleName)) { + Log.e(LOG_TAG, "Cannot set fallback enabled for unknown role, role: " + roleName + + ", fallbackEnabled: " + fallbackEnabled); + return; + } + if (mFallbackEnabledRoles.contains(roleName) == fallbackEnabled) { + return; + } + if (fallbackEnabled) { + mFallbackEnabledRoles.add(roleName); + } else { + mFallbackEnabledRoles.remove(roleName); + } + scheduleWriteFileLocked(); + } + } + /** * Get whether the role is available. * @@ -386,7 +420,8 @@ class RoleUserState { // Force a reconciliation on next boot if we are bypassing role qualification now. String packagesHash = mBypassingRoleQualification ? null : mPackagesHash; roles = new RolesState(mVersion, packagesHash, - (Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked()); + (Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked(), + snapshotFallbackEnabledRoles()); } mPersistence.writeForUser(roles, UserHandle.of(mUserId)); @@ -413,6 +448,9 @@ class RoleUserState { if (roleState == null) { scheduleWriteFileLocked(); + } else { + mFallbackEnabledRoles.clear(); + mFallbackEnabledRoles.addAll(roleState.getFallbackEnabledRoles()); } } } @@ -427,10 +465,12 @@ class RoleUserState { int version; String packagesHash; ArrayMap<String, ArraySet<String>> roles; + ArraySet<String> fallbackEnabledRoles; synchronized (mLock) { version = mVersion; packagesHash = mPackagesHash; roles = snapshotRolesLocked(); + fallbackEnabledRoles = snapshotFallbackEnabledRoles(); } long fieldToken = dumpOutputStream.start(fieldName, fieldId); @@ -442,10 +482,12 @@ class RoleUserState { for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) { String roleName = roles.keyAt(rolesIndex); ArraySet<String> roleHolders = roles.valueAt(rolesIndex); + boolean fallbackEnabled = fallbackEnabledRoles.contains(roleName); long rolesToken = dumpOutputStream.start("roles", RoleUserStateProto.ROLES); dumpOutputStream.write("name", RoleProto.NAME, roleName); - + dumpOutputStream.write("fallback_enabled", RoleProto.FALLBACK_ENABLED, + Boolean.toString(fallbackEnabled)); int roleHoldersSize = roleHolders.size(); for (int roleHoldersIndex = 0; roleHoldersIndex < roleHoldersSize; roleHoldersIndex++) { String roleHolder = roleHolders.valueAt(roleHoldersIndex); @@ -485,6 +527,12 @@ class RoleUserState { return roles; } + @GuardedBy("mLock") + @NonNull + private ArraySet<String> snapshotFallbackEnabledRoles() { + return new ArraySet<>(mFallbackEnabledRoles); + } + /** * Destroy this user state and delete the corresponding file. Any pending writes to the file * will be cancelled, and any future interaction with this state will throw an exception. diff --git a/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/service/java/com/android/role/persistence/RolesPersistenceImpl.java index 76cf8f81f..242f7315f 100644 --- a/service/java/com/android/role/persistence/RolesPersistenceImpl.java +++ b/service/java/com/android/role/persistence/RolesPersistenceImpl.java @@ -66,6 +66,7 @@ public class RolesPersistenceImpl implements RolesPersistence { private static final String ATTRIBUTE_VERSION = "version"; private static final String ATTRIBUTE_NAME = "name"; + private static final String ATTRIBUTE_FALLBACK_ENABLED = "fallbackEnabled"; private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash"; @VisibleForTesting @@ -142,6 +143,7 @@ public class RolesPersistenceImpl implements RolesPersistence { String packagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH); Map<String, Set<String>> roles = new ArrayMap<>(); + Set<String> fallbackEnabledRoles = new ArraySet<>(); int type; int depth; int innerDepth = parser.getDepth() + 1; @@ -153,12 +155,16 @@ public class RolesPersistenceImpl implements RolesPersistence { if (parser.getName().equals(TAG_ROLE)) { String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME); + String fallbackEnabled = parser.getAttributeValue(null, ATTRIBUTE_FALLBACK_ENABLED); + if (Boolean.parseBoolean(fallbackEnabled)) { + fallbackEnabledRoles.add(roleName); + } Set<String> roleHolders = parseRoleHolders(parser); roles.put(roleName, roleHolders); } } - return new RolesState(version, packagesHash, roles); + return new RolesState(version, packagesHash, roles, fallbackEnabledRoles); } @NonNull @@ -238,12 +244,16 @@ public class RolesPersistenceImpl implements RolesPersistence { serializer.attribute(null, ATTRIBUTE_PACKAGES_HASH, packagesHash); } + Set<String> fallbackEnabledRoles = roles.getFallbackEnabledRoles(); for (Map.Entry<String, Set<String>> entry : roles.getRoles().entrySet()) { String roleName = entry.getKey(); Set<String> roleHolders = entry.getValue(); + boolean isFallbackEnabled = fallbackEnabledRoles.contains(roleName); serializer.startTag(null, TAG_ROLE); serializer.attribute(null, ATTRIBUTE_NAME, roleName); + serializer.attribute(null, ATTRIBUTE_FALLBACK_ENABLED, + Boolean.toString(isFallbackEnabled)); serializeRoleHolders(serializer, roleHolders); serializer.endTag(null, TAG_ROLE); } diff --git a/service/java/com/android/role/persistence/RolesState.java b/service/java/com/android/role/persistence/RolesState.java index f61efa0e8..fc6b88f26 100644 --- a/service/java/com/android/role/persistence/RolesState.java +++ b/service/java/com/android/role/persistence/RolesState.java @@ -16,10 +16,13 @@ package com.android.role.persistence; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.SystemApi.Client; +import android.permission.flags.Flags; +import android.util.ArraySet; import java.util.Map; import java.util.Objects; @@ -33,7 +36,6 @@ import java.util.Set; */ @SystemApi(client = Client.SYSTEM_SERVER) public final class RolesState { - /** * The version of the roles. */ @@ -52,6 +54,12 @@ public final class RolesState { private final Map<String, Set<String>> mRoles; /** + * The names of roles with fallback enabled. + */ + @NonNull + private final Set<String> mFallbackEnabledRoles; + + /** * Create a new instance of this class. * * @param version the version of the roles @@ -60,9 +68,24 @@ public final class RolesState { */ public RolesState(int version, @Nullable String packagesHash, @NonNull Map<String, Set<String>> roles) { + this(version, packagesHash, roles, new ArraySet<>()); + } + + /** + * Create a new instance of this class. + * + * @param version the version of the roles + * @param packagesHash the hash of all packages in the system + * @param roles the roles + * @param fallbackEnabledRoles the roles with fallback enabled + */ + @FlaggedApi(Flags.FLAG_ROLE_CONTROLLER_IN_SYSTEM_SERVER) + public RolesState(int version, @Nullable String packagesHash, + @NonNull Map<String, Set<String>> roles, @NonNull Set<String> fallbackEnabledRoles) { mVersion = version; mPackagesHash = packagesHash; mRoles = roles; + mFallbackEnabledRoles = fallbackEnabledRoles; } /** @@ -94,6 +117,17 @@ public final class RolesState { return mRoles; } + /** + * Get the fallback enabled roles. + * + * @return fallback enabled roles + */ + @NonNull + @FlaggedApi(Flags.FLAG_ROLE_CONTROLLER_IN_SYSTEM_SERVER) + public Set<String> getFallbackEnabledRoles() { + return mFallbackEnabledRoles; + } + @Override public boolean equals(Object object) { if (this == object) { @@ -105,11 +139,12 @@ public final class RolesState { RolesState that = (RolesState) object; return mVersion == that.mVersion && Objects.equals(mPackagesHash, that.mPackagesHash) - && Objects.equals(mRoles, that.mRoles); + && Objects.equals(mRoles, that.mRoles) + && Objects.equals(mFallbackEnabledRoles, that.mFallbackEnabledRoles); } @Override public int hashCode() { - return Objects.hash(mVersion, mPackagesHash, mRoles); + return Objects.hash(mVersion, mPackagesHash, mRoles, mFallbackEnabledRoles); } } diff --git a/service/proto/role_service.proto b/service/proto/role_service.proto index 79c422992..f982ead5b 100644 --- a/service/proto/role_service.proto +++ b/service/proto/role_service.proto @@ -53,4 +53,7 @@ message RoleProto { // The package names of the holders of this role. repeated string holders = 2; + + // Whether fallback holders are enabled for this role. + optional bool fallback_enabled = 3; } diff --git a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt index d90ffade9..0cf1fa665 100644 --- a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt +++ b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt @@ -20,7 +20,6 @@ import android.content.ApexEnvironment import android.content.Context import android.os.Process import android.os.UserHandle -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.google.common.truth.Truth.assertThat @@ -29,6 +28,7 @@ import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.junit.runners.Parameterized import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq import org.mockito.Mock @@ -37,27 +37,36 @@ import org.mockito.MockitoAnnotations.initMocks import org.mockito.MockitoSession import org.mockito.quality.Strictness -@RunWith(AndroidJUnit4::class) +@RunWith(Parameterized::class) class RolesPersistenceTest { private val context = InstrumentationRegistry.getInstrumentation().context private lateinit var mockDataDirectory: File - private lateinit var mockitoSession: MockitoSession @Mock lateinit var apexEnvironment: ApexEnvironment + @Parameterized.Parameter(0) lateinit var stateVersion: StateVersion + private lateinit var state: RolesState private val persistence = RolesPersistenceImpl {} - private val state = RolesState(1, "packagesHash", mapOf("role" to setOf("holder1", "holder2"))) + private val defaultRoles = mapOf(ROLE_NAME to setOf(HOLDER_1, HOLDER_2)) + private val stateVersionUndefined = RolesState(VERSION_UNDEFINED, PACKAGE_HASH, defaultRoles) + private val stateVersionFallbackMigrated = + RolesState(VERSION_FALLBACK_MIGRATED, PACKAGE_HASH, defaultRoles, setOf(ROLE_NAME)) private val user = Process.myUserHandle() @Before - fun createMockDataDirectory() { + fun setUp() { + createMockDataDirectory() + mockApexEnvironment() + state = getState() + } + + private fun createMockDataDirectory() { mockDataDirectory = context.getDir("mock_data", Context.MODE_PRIVATE) mockDataDirectory.listFiles()!!.forEach { assertThat(it.deleteRecursively()).isTrue() } } - @Before - fun mockApexEnvironment() { + private fun mockApexEnvironment() { initMocks(this) mockitoSession = mockitoSession() @@ -80,7 +89,7 @@ class RolesPersistenceTest { persistence.writeForUser(state, user) val persistedState = persistence.readForUser(user) - checkPersistedState(persistedState) + assertThat(persistedState).isEqualTo(state) } @Test @@ -91,7 +100,7 @@ class RolesPersistenceTest { .writeText("<roles version=\"-1\"><role name=\"com.foo.bar\"><holder") val persistedState = persistence.readForUser(user) - checkPersistedState(persistedState) + assertThat(persistedState).isEqualTo(state) } @Test @@ -102,15 +111,28 @@ class RolesPersistenceTest { assertThat(persistedState).isNull() } + private fun getState(): RolesState = + when (stateVersion) { + StateVersion.VERSION_UNDEFINED -> stateVersionUndefined + StateVersion.VERSION_FALLBACK_MIGRATED -> stateVersionFallbackMigrated + } - private fun checkPersistedState(persistedState: RolesState?) { - assertThat(persistedState).isEqualTo(state) - assertThat(persistedState?.version).isEqualTo(state.version) - assertThat(persistedState?.packagesHash).isEqualTo(state.packagesHash) - assertThat(persistedState?.roles).isEqualTo(state.roles) + enum class StateVersion { + VERSION_UNDEFINED, + VERSION_FALLBACK_MIGRATED } companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun data(): Array<StateVersion> = StateVersion.values() + + private const val VERSION_UNDEFINED = -1 + private const val VERSION_FALLBACK_MIGRATED = 1 private const val APEX_MODULE_NAME = "com.android.permission" + private const val PACKAGE_HASH = "packagesHash" + private const val ROLE_NAME = "roleName" + private const val HOLDER_1 = "holder1" + private const val HOLDER_2 = "holder2" } } 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 a7429ac99..61625d587 100644 --- a/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java +++ b/tests/cts/role/src/android/app/role/cts/RoleManagerTest.java @@ -1153,6 +1153,18 @@ public class RoleManagerTest { }); } + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, + codeName = "VanillaIceCream") + @Test + public void testSetAndGetRoleFallbackEnabled() { + assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)); + + runWithShellPermissionIdentity(() -> { + sRoleManager.setRoleFallbackEnabled(RoleManager.ROLE_SMS, true); + assertThat(sRoleManager.isRoleFallbackEnabled(RoleManager.ROLE_SMS)).isTrue(); + }); + } + @NonNull private List<String> getRoleHolders(@NonNull String roleName) throws Exception { return callWithShellPermissionIdentity(() -> sRoleManager.getRoleHolders(roleName)); |