From ce799bcddc999ad2d4b4470ea2c1d58244791c30 Mon Sep 17 00:00:00 2001 From: Richard MacGregor Date: Fri, 22 Nov 2024 23:28:53 +0000 Subject: Disable default and fallback role holders for non-active users of profileGroup exclusive roles If a role is profile group exclusive and users is not active, do not apply default role holder and fallback role holder for user LOW_COVERAGE_REASON=FLAG_NOT_ENABLED Relnote: N/A Flag: com.android.permission.flags.cross_user_role_enabled Bug: 379143798 Test: atest RoleManagerMultiUserTest Change-Id: I068f3eebd4ad368e68d3b3ce1069d8663a94fb5a --- ...TestingProfileGroupExclusivityRoleBehavior.java | 43 ++++++++++++++++++++++ .../com/android/role/controller/model/Role.java | 21 +++++++++++ .../service/RoleControllerServiceImpl.java | 14 +++++++ .../android/role/controller/util/RoleFlags.java | 13 +++++-- .../android/role/controller/util/UserUtils.java | 21 +++++++++++ 5 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java (limited to 'PermissionController/role-controller/java') 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 new file mode 100644 index 000000000..71f988279 --- /dev/null +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/ReservedForTestingProfileGroupExclusivityRoleBehavior.java @@ -0,0 +1,43 @@ +/* + * 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 com.android.role.controller.behavior; + +import android.content.Context; +import android.os.UserHandle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.role.controller.model.Role; +import com.android.role.controller.model.RoleBehavior; + +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 DEFAULT_HOLDERS = + Arrays.asList("android.app.rolemultiuser.cts.app"); + + @Nullable + @Override + public List getDefaultHoldersAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + return DEFAULT_HOLDERS; + } +} diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java index 0a04e2764..9895f8533 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java @@ -511,6 +511,12 @@ public class Role { @NonNull public List getDefaultHoldersAsUser(@NonNull UserHandle user, @NonNull Context context) { + // Do not allow default role holder for non-active user if the role is exclusive to profile + // group + if (isNonActiveUserForProfileGroupExclusiveRole(user, context)) { + return Collections.emptyList(); + } + if (mBehavior != null) { List defaultHolders = mBehavior.getDefaultHoldersAsUser(this, user, context); if (defaultHolders != null) { @@ -622,6 +628,10 @@ public class Role { if (!RoleManagerCompat.isRoleFallbackEnabledAsUser(this, user, context)) { return null; } + // Do not fall back for non-active user if the role is exclusive to profile group + if (isNonActiveUserForProfileGroupExclusiveRole(user, context)) { + return null; + } if (mFallBackToDefaultHolder) { return CollectionUtils.firstOrNull(getDefaultHoldersAsUser(user, context)); } @@ -631,6 +641,17 @@ public class Role { return null; } + private boolean isNonActiveUserForProfileGroupExclusiveRole(@NonNull UserHandle user, + @NonNull Context context) { + if (RoleFlags.isProfileGroupExclusivityAvailable() + && getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP) { + Context userContext = UserUtils.getUserContext(context, user); + RoleManager userRoleManager = userContext.getSystemService(RoleManager.class); + return !Objects.equals(userRoleManager.getActiveUserForRole(mName), user); + } + return false; + } + /** * Check whether this role is allowed to bypass qualification, if enabled globally. * diff --git a/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java index a5ac5700e..d00fd47af 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java +++ b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java @@ -35,6 +35,7 @@ import com.android.role.controller.model.Roles; import com.android.role.controller.util.CollectionUtils; import com.android.role.controller.util.LegacyRoleFallbackEnabledUtils; import com.android.role.controller.util.PackageUtils; +import com.android.role.controller.util.RoleFlags; import com.android.role.controller.util.UserUtils; import java.util.ArrayList; @@ -132,6 +133,19 @@ public class RoleControllerServiceImpl extends RoleControllerService { String roleName = role.getName(); + if (RoleFlags.isProfileGroupExclusivityAvailable() + && role.getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP) { + if (mUserRoleManager.getActiveUserForRole(roleName) == null) { + UserHandle profileParent = UserUtils.getProfileParentOrSelf(mUser, mContext); + if (Objects.equals(mUser, profileParent)) { + Log.i(LOG_TAG, "No active user for role: " + roleName + ", setting " + + "active user to user: " + mUser.getIdentifier()); + sSetActiveUserForRoleMethod.setActiveUserForRole(roleName, + mUser.getIdentifier(), 0); + } + } + } + // For each of the current holders, check if it is still qualified, redo grant if so, or // remove it otherwise. List currentPackageNames = mUserRoleManager.getRoleHolders(roleName); diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/RoleFlags.java b/PermissionController/role-controller/java/com/android/role/controller/util/RoleFlags.java index f8a8502cd..2c5a247b6 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/util/RoleFlags.java +++ b/PermissionController/role-controller/java/com/android/role/controller/util/RoleFlags.java @@ -20,7 +20,7 @@ import android.os.Build; import androidx.annotation.ChecksSdkIntAtLeast; -import com.android.modules.utils.build.SdkLevel; +import java.util.Objects; /** Util class for getting shared feature flag check logic. */ public final class RoleFlags { @@ -30,9 +30,16 @@ public final class RoleFlags { * Returns whether profile group exclusive roles are available. Profile exclusive roles are * available on B+ */ - @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.VANILLA_ICE_CREAM) + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.BAKLAVA) public static boolean isProfileGroupExclusivityAvailable() { // TODO(b/372743073): change to isAtLeastB once available - return SdkLevel.isAtLeastV() && com.android.permission.flags.Flags.crossUserRoleEnabled(); + return isAtLeastB() && com.android.permission.flags.Flags.crossUserRoleEnabled(); + } + + // TODO(b/372743073): remove once SdkLevel.isAtLeastB available + @ChecksSdkIntAtLeast(api = 36 /* BUILD_VERSION_CODES.Baklava */) + public static boolean isAtLeastB() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA + || Objects.equals(Build.VERSION.CODENAME, "Baklava"); } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java index 1b6926ef8..f3cb7926a 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java +++ b/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java @@ -24,6 +24,7 @@ import android.os.UserHandle; import android.os.UserManager; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.modules.utils.build.SdkLevel; @@ -111,4 +112,24 @@ public final class UserUtils { return context.createContextAsUser(user, 0); } } + + /** + * Returns the parent of a given user, or user if it has no parent (e.g. it is the primary + * user) + */ + @NonNull + public static UserHandle getProfileParentOrSelf(@NonNull UserHandle user, + @NonNull Context context) { + UserHandle profileParent = getProfileParent(user, context); + // If profile parent user is null, then original user is the parent + return profileParent != null ? profileParent : user; + } + + /** Returns the parent of a given user. */ + @Nullable + private static UserHandle getProfileParent(UserHandle user, @NonNull Context context) { + Context userContext = getUserContext(context, user); + UserManager userManager = userContext.getSystemService(UserManager.class); + return userManager.getProfileParent(user); + } } -- cgit v1.2.3-59-g8ed1b