diff options
7 files changed, 82 insertions, 54 deletions
diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java index deb0cf3b0..5bc79efbb 100644 --- a/service/java/com/android/role/RoleService.java +++ b/service/java/com/android/role/RoleService.java @@ -219,7 +219,6 @@ public class RoleService extends SystemService implements RoleUserState.Callback }, intentFilter, null, null); } - // TODO(b/375029649): enforce single active user for all cross-user roles @Override public void onStart() { publishBinderService(Context.ROLE_SERVICE, new Stub()); @@ -440,6 +439,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback private void onRemoveUser(@UserIdInt int userId) { RemoteCallbackList<IOnRoleHoldersChangedListener> listeners; RoleUserState userState; + // UserManager still knows the user until ACTION_USER_REMOVED broadcasts are processed + int profileParentId = UserUtils.getProfileParentIdOrSelf(userId, getContext()); + List<String> activeRoleNames = null; synchronized (mLock) { mGrantDefaultRolesThrottledRunnables.remove(userId); listeners = mListeners.get(userId); @@ -447,7 +449,29 @@ public class RoleService extends SystemService implements RoleUserState.Callback mControllers.remove(userId); userState = mUserStates.get(userId); mUserStates.remove(userId); + + if (RoleFlags.isProfileGroupExclusivityAvailable() && userId != profileParentId) { + RoleUserState profileParentState = mUserStates.get(profileParentId); + activeRoleNames = profileParentState.getActiveRolesForUser(userId); + } } + if (RoleFlags.isProfileGroupExclusivityAvailable() && userId != profileParentId + && !CollectionUtils.isEmpty(activeRoleNames)) { + int activeRoleNamesSize = activeRoleNames.size(); + for (int i = 0; i < activeRoleNamesSize; i++) { + String roleName = activeRoleNames.get(i); + + // If the previous active user had a set role holder, attempt to fallback for + // the profile parent. + Log.i(LOG_TAG, "User " + userId + " removed, falling back to profile parent " + + profileParentId + " for role " + roleName); + // Use profileParentId instead of userId here, since userId is in a state of removal + // and might be excluded from UserManager#getUserHandles with excludeDying=true + setActiveUserForRoleAsUserInternal(roleName, profileParentId, 0, true, + profileParentId); + } + } + if (listeners != null) { listeners.kill(); } diff --git a/service/java/com/android/role/RoleUserState.java b/service/java/com/android/role/RoleUserState.java index 7f59f1385..18574a6fc 100644 --- a/service/java/com/android/role/RoleUserState.java +++ b/service/java/com/android/role/RoleUserState.java @@ -447,6 +447,22 @@ class RoleUserState { } } + @NonNull + public List<String> getActiveRolesForUser(@UserIdInt int userId) { + synchronized (mLock) { + List<String> activeRoleNames = new ArrayList<>(); + int activeUserIdsSize = mActiveUserIds.size(); + for (int i = 0; i < activeUserIdsSize; i++) { + int activeUserId = mActiveUserIds.valueAt(i); + if (activeUserId == userId) { + String roleName = mActiveUserIds.keyAt(i); + activeRoleNames.add(roleName); + } + } + return activeRoleNames; + } + } + /** * Set the active user for the role * diff --git a/tests/cts/rolemultiuser/Android.bp b/tests/cts/rolemultiuser/Android.bp index 7de55fc1b..7a49bc4e5 100644 --- a/tests/cts/rolemultiuser/Android.bp +++ b/tests/cts/rolemultiuser/Android.bp @@ -45,6 +45,6 @@ android_test { ], data: [ - ":CtsRoleMultiUserTestApp", + ":CtsRoleTestApp", ], } diff --git a/tests/cts/rolemultiuser/AndroidTest.xml b/tests/cts/rolemultiuser/AndroidTest.xml index 15c34f54a..510b70fdb 100644 --- a/tests/cts/rolemultiuser/AndroidTest.xml +++ b/tests/cts/rolemultiuser/AndroidTest.xml @@ -41,7 +41,7 @@ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> <option name="cleanup" value="true" /> - <option name="push" value="CtsRoleMultiUserTestApp.apk->/data/local/tmp/cts-role/CtsRoleMultiUserTestApp.apk" /> + <option name="push" value="CtsRoleTestApp.apk->/data/local/tmp/cts-role/CtsRoleTestApp.apk" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > diff --git a/tests/cts/rolemultiuser/CtsRoleMultiUserTestApp/Android.bp b/tests/cts/rolemultiuser/CtsRoleMultiUserTestApp/Android.bp deleted file mode 100644 index 71ccd0e59..000000000 --- a/tests/cts/rolemultiuser/CtsRoleMultiUserTestApp/Android.bp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2024 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -android_test_helper_app { - name: "CtsRoleMultiUserTestApp", - defaults: ["mts-target-sdk-version-current"], - min_sdk_version: "30", -} diff --git a/tests/cts/rolemultiuser/CtsRoleMultiUserTestApp/AndroidManifest.xml b/tests/cts/rolemultiuser/CtsRoleMultiUserTestApp/AndroidManifest.xml deleted file mode 100644 index eea3be741..000000000 --- a/tests/cts/rolemultiuser/CtsRoleMultiUserTestApp/AndroidManifest.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- - ~ Copyright (C) 2024 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<manifest - xmlns:android="http://schemas.android.com/apk/res/android" - package="android.app.rolemultiuser.cts.app"> - - <application android:label="CtsRoleMultiUserTestApp" /> -</manifest> 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 9af594070..72abf0678 100644 --- a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt +++ b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt @@ -25,12 +25,14 @@ import android.os.UserHandle import android.provider.Settings import androidx.test.filters.SdkSuppress import androidx.test.uiautomator.By +import com.android.bedstead.enterprise.annotations.EnsureHasNoWorkProfile import com.android.bedstead.enterprise.annotations.EnsureHasWorkProfile import com.android.bedstead.enterprise.annotations.RequireRunOnWorkProfile import com.android.bedstead.enterprise.workProfile import com.android.bedstead.flags.annotations.RequireFlagsEnabled import com.android.bedstead.harrier.BedsteadJUnit4 import com.android.bedstead.harrier.DeviceState +import com.android.bedstead.multiuser.annotations.EnsureCanAddUser import com.android.bedstead.multiuser.annotations.EnsureHasAdditionalUser import com.android.bedstead.multiuser.annotations.EnsureHasPrivateProfile import com.android.bedstead.multiuser.annotations.EnsureHasSecondaryUser @@ -42,6 +44,7 @@ import com.android.bedstead.nene.TestApis.context import com.android.bedstead.nene.TestApis.permissions import com.android.bedstead.nene.TestApis.users import com.android.bedstead.nene.types.OptionalBoolean +import com.android.bedstead.nene.users.UserType import com.android.bedstead.permissions.CommonPermissions.INTERACT_ACROSS_USERS_FULL import com.android.bedstead.permissions.CommonPermissions.MANAGE_DEFAULT_APPLICATIONS import com.android.bedstead.permissions.CommonPermissions.MANAGE_ROLE_HOLDERS @@ -565,6 +568,39 @@ class RoleManagerMultiUserTest { @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureCanAddUser + @EnsureHasNoWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(Exception::class) + fun ensureActiveUserSetToParentOnUserRemoved() { + users() + .createUser() + .parent(users().initial()) + .type(users().supportedType(UserType.MANAGED_PROFILE_TYPE_NAME)) + .createAndStart() + .use { userReference -> + val targetActiveUser = userReference.userHandle() + roleManager.setActiveUserForRole( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + targetActiveUser, + 0, + ) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(targetActiveUser) + + userReference.remove() + } + + // Removal of users in roles service might take a moment + eventually { + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(users().current().userHandle()) + } + } + + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) @EnsureHasWorkProfile @RequireRunOnPrimaryUser @Test @@ -915,10 +951,9 @@ class RoleManagerMultiUserTest { private const val PROFILE_GROUP_EXCLUSIVITY_ROLE_SHORT_LABEL = "Test profile group exclusive role app" private const val PRIVATE_PROFILE_TYPE_NAME = "android.os.usertype.profile.PRIVATE" - private const val APP_APK_PATH: String = - "/data/local/tmp/cts-role/CtsRoleMultiUserTestApp.apk" - private const val APP_PACKAGE_NAME: String = "android.app.rolemultiuser.cts.app" - private const val APP_LABEL: String = "CtsRoleMultiUserTestApp" + private const val APP_APK_PATH = "/data/local/tmp/cts-role/CtsRoleTestApp.apk" + private const val APP_PACKAGE_NAME = "android.app.role.cts.app" + private const val APP_LABEL = "CtsRoleTestApp" private val context: Context = context().instrumentedContext() private val roleManager: RoleManager = context.getSystemService(RoleManager::class.java) |