summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/ecm/EnhancedConfirmationService.java3
-rw-r--r--service/java/com/android/permission/util/UserUtils.java79
-rw-r--r--service/java/com/android/role/RoleService.java202
-rw-r--r--service/java/com/android/role/RoleShellCommand.java27
-rw-r--r--service/java/com/android/role/RoleUserState.java37
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterService.java3
-rw-r--r--service/java/com/android/safetycenter/UserProfileGroup.java10
7 files changed, 311 insertions, 50 deletions
diff --git a/service/java/com/android/ecm/EnhancedConfirmationService.java b/service/java/com/android/ecm/EnhancedConfirmationService.java
index 708884e85..73f66609e 100644
--- a/service/java/com/android/ecm/EnhancedConfirmationService.java
+++ b/service/java/com/android/ecm/EnhancedConfirmationService.java
@@ -228,7 +228,8 @@ public class EnhancedConfirmationService extends SystemService {
}
private void enforcePermissions(@NonNull String methodName, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false, methodName, mContext);
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, methodName, mContext);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_ENHANCED_CONFIRMATION_STATES, methodName);
}
diff --git a/service/java/com/android/permission/util/UserUtils.java b/service/java/com/android/permission/util/UserUtils.java
index 986b5af5b..c69afb199 100644
--- a/service/java/com/android/permission/util/UserUtils.java
+++ b/service/java/com/android/permission/util/UserUtils.java
@@ -17,9 +17,10 @@
package com.android.permission.util;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Process;
import android.os.UserHandle;
@@ -30,8 +31,8 @@ import com.android.internal.util.Preconditions;
import com.android.modules.utils.build.SdkLevel;
import com.android.permission.flags.Flags;
+import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
/** Utility class to deal with Android users. */
public final class UserUtils {
@@ -42,11 +43,12 @@ public final class UserUtils {
public static void enforceCrossUserPermission(
@UserIdInt int userId,
boolean allowAll,
+ boolean enforceForProfileGroup,
@NonNull String message,
@NonNull Context context) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandleCompat.getUserId(callingUid);
- if (userId == callingUserId) {
+ if (userId == callingUserId && !enforceForProfileGroup) {
return;
}
Preconditions.checkArgument(
@@ -55,13 +57,40 @@ public final class UserUtils {
"Invalid user " + userId);
context.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
- if (callingUid != Process.SHELL_UID || userId < UserHandleCompat.USER_SYSTEM) {
+ if (callingUid != Process.SHELL_UID || userId == UserHandleCompat.USER_ALL) {
return;
}
+
+ if (enforceForProfileGroup) {
+ DevicePolicyManager devicePolicyManager =
+ context.getSystemService(DevicePolicyManager.class);
+ if (!devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()) {
+ // For profileGroup exclusive roles users on BYOD are free to choose personal o
+ // work profile app regardless of DISALLOW_DEBUGGING_FEATURES
+ return;
+ }
+
+ Context userContext = UserUtils.getUserContext(userId, context);
+ List<UserHandle> profiles = getUserProfiles(userContext, true);
+ final int profilesSize = profiles.size();
+ for (int i = 0; i < profilesSize; i++) {
+ int profileId = profiles.get(i).getIdentifier();
+ if (profileId == callingUserId) {
+ continue;
+ }
+ enforceShellRestriction(profileId, context);
+ }
+ } else {
+ enforceShellRestriction(userId, context);
+ }
+ }
+
+ private static void enforceShellRestriction(int userId, @NonNull Context context) {
UserManager userManager = context.getSystemService(UserManager.class);
if (userManager.hasUserRestrictionForUser(
UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
- throw new SecurityException("Shell does not have permission to access user " + userId);
+ throw new SecurityException(
+ "Shell does not have permission to access user " + userId);
}
}
@@ -86,18 +115,54 @@ public final class UserUtils {
/** Returns all the enabled user profiles on the device. */
@NonNull
public static List<UserHandle> getUserProfiles(@NonNull Context context) {
+ return getUserProfiles(context, false);
+ }
+
+ /**
+ * Returns all the enabled user profiles on the device
+ *
+ * @param context the {@link Context}
+ * @param excludePrivate {@code true} to exclude private profiles from returned list of users
+ */
+ @NonNull
+ public static List<UserHandle> getUserProfiles(@NonNull Context context,
+ boolean excludePrivate) {
UserManager userManager = context.getSystemService(UserManager.class);
// This call requires the QUERY_USERS permission.
final long identity = Binder.clearCallingIdentity();
try {
- return userManager.getUserProfiles();
+ List<UserHandle> profiles = userManager.getUserProfiles();
+ if (!excludePrivate) {
+ return profiles;
+ }
+ List<UserHandle> filteredProfiles = new ArrayList<>();
+ final int profilesSize = profiles.size();
+ for (int i = 0; i < profilesSize; i++) {
+ UserHandle user = profiles.get(i);
+ if (!isPrivateProfile(user.getIdentifier(), context)) {
+ filteredProfiles.add(user);
+ }
+ }
+ return filteredProfiles;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ /**
+ * Returns the parent of a given user, or userId if it has no parent (e.g. it is the primary
+ * profile)
+ */
+ @UserIdInt
+ public static int getProfileParentIdOrSelf(@UserIdInt int userId, @NonNull Context context) {
+ UserHandle profileParent = getProfileParent(userId, context);
+ // If profile parent userhandle is null, then original user id is the parent
+ return profileParent != null ? profileParent.getIdentifier() : userId;
+ }
+
/** Returns the parent of a given user. */
- public static UserHandle getProfileParent(@UserIdInt int userId, @NonNull Context context) {
+ @Nullable
+ private static UserHandle getProfileParent(@UserIdInt int userId, @NonNull Context context) {
Context userContext = getUserContext(userId, context);
UserManager userManager = userContext.getSystemService(UserManager.class);
// This call requires the INTERACT_ACROSS_USERS permission.
diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java
index c4316ff71..1145f273d 100644
--- a/service/java/com/android/role/RoleService.java
+++ b/service/java/com/android/role/RoleService.java
@@ -18,6 +18,7 @@ package com.android.role;
import android.Manifest;
import android.annotation.AnyThread;
+import android.annotation.ChecksSdkIntAtLeast;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -45,8 +46,8 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.permission.internal.compat.UserHandleCompat;
import android.permission.flags.Flags;
+import android.permission.internal.compat.UserHandleCompat;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -69,6 +70,8 @@ import com.android.permission.util.ForegroundThread;
import com.android.permission.util.PackageUtils;
import com.android.permission.util.ThrottledRunnable;
import com.android.permission.util.UserUtils;
+import com.android.role.controller.model.Role;
+import com.android.role.controller.model.Roles;
import com.android.server.LocalManagerRegistry;
import com.android.server.SystemService;
import com.android.server.role.RoleServicePlatformHelper;
@@ -77,6 +80,7 @@ import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -466,8 +470,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public boolean isRoleAvailableAsUser(@NonNull String roleName, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false, "isRoleAvailableAsUser",
- getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "isRoleAvailableAsUser", getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return false;
@@ -483,7 +487,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@UserIdInt int userId) {
mAppOpsManager.checkPackage(getCallingUid(), packageName);
- UserUtils.enforceCrossUserPermission(userId, false, "isRoleHeldAsUser", getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "isRoleHeldAsUser", getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return false;
@@ -502,8 +507,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@NonNull
@Override
public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser",
- getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "getRoleHoldersAsUser", getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return Collections.emptyList();
@@ -525,8 +530,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
- UserUtils.enforceCrossUserPermission(userId, false, "addRoleHolderAsUser",
- getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "addRoleHolderAsUser", getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
@@ -546,8 +551,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
- UserUtils.enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser",
- getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "removeRoleHolderAsUser", getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
@@ -568,8 +573,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
public void clearRoleHoldersAsUser(@NonNull String roleName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
@NonNull RemoteCallback callback) {
- UserUtils.enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser",
- getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "clearRoleHoldersAsUser", getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return;
@@ -587,7 +592,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
@Nullable
public String getDefaultApplicationAsUser(@NonNull String roleName, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false, "getDefaultApplicationAsUser",
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "getDefaultApplicationAsUser",
getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
@@ -612,7 +618,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
public void setDefaultApplicationAsUser(@NonNull String roleName,
@Nullable String packageName, @RoleManager.ManageHoldersFlags int flags,
@UserIdInt int userId, @NonNull RemoteCallback callback) {
- UserUtils.enforceCrossUserPermission(userId, false, "setDefaultApplicationAsUser",
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "setDefaultApplicationAsUser",
getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
@@ -635,10 +642,101 @@ public class RoleService extends SystemService implements RoleUserState.Callback
}
@Override
+ public int getActiveUserForRoleAsUser(@NonNull String roleName, @UserIdInt int userId) {
+ Preconditions.checkState(isProfileGroupExclusivityAvailable(),
+ "getActiveUserForRoleAsUser not available");
+ enforceProfileGroupExclusiveRole(roleName);
+
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ true, "getActiveUserForRole", getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return UserHandleCompat.USER_NULL;
+ }
+
+ enforceCallingOrSelfAnyPermissions(new String[] {
+ Manifest.permission.MANAGE_DEFAULT_APPLICATIONS,
+ Manifest.permission.MANAGE_ROLE_HOLDERS
+ }, "getActiveUserForRole");
+
+ int profileParentId = UserUtils.getProfileParentIdOrSelf(userId, getContext());
+ RoleUserState userState = getOrCreateUserState(profileParentId);
+ return userState.getActiveUserForRole(roleName);
+ }
+
+ @Override
+ public void setActiveUserForRoleAsUser(@NonNull String roleName,
+ @UserIdInt int activeUserId, @RoleManager.ManageHoldersFlags int flags,
+ @UserIdInt int userId) {
+ Preconditions.checkState(isProfileGroupExclusivityAvailable(),
+ "setActiveUserForRoleAsUser not available");
+ enforceProfileGroupExclusiveRole(roleName);
+
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ true, "setActiveUserForRole", getContext());
+ if (!UserUtils.isUserExistent(userId, getContext())) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return;
+ }
+ if (!UserUtils.isUserExistent(activeUserId, getContext())) {
+ Log.e(LOG_TAG, "user " + activeUserId + " does not exist");
+ return;
+ }
+ if (UserUtils.isPrivateProfile(activeUserId, getContext())) {
+ Log.e(LOG_TAG, "Cannot set private profile " + activeUserId + " as active user"
+ + " for role");
+ return;
+ }
+ Context userContext = UserUtils.getUserContext(userId, getContext());
+ List<UserHandle> profiles = UserUtils.getUserProfiles(userContext, true);
+ if (!profiles.contains(UserHandle.of(activeUserId))) {
+ Log.e(LOG_TAG, "User " + activeUserId + " is not in the same profile-group as "
+ + userId);
+ return;
+ }
+
+ enforceCallingOrSelfAnyPermissions(new String[] {
+ Manifest.permission.MANAGE_DEFAULT_APPLICATIONS,
+ Manifest.permission.MANAGE_ROLE_HOLDERS
+ }, "setDefaultApplicationAsUser");
+
+ int profileParentId = UserUtils.getProfileParentIdOrSelf(userId, getContext());
+ RoleUserState userState = getOrCreateUserState(profileParentId);
+
+ if (!userState.setActiveUserForRole(roleName, activeUserId)) {
+ Log.i(LOG_TAG, "User " + activeUserId + " is already the active user for role");
+ return;
+ }
+
+ final int profilesSize = profiles.size();
+ for (int i = 0; i < profilesSize; i++) {
+ final AndroidFuture<Void> future = new AndroidFuture<>();
+ final RemoteCallback callback = new RemoteCallback(result -> {
+ boolean successful = result != null;
+ if (successful) {
+ future.complete(null);
+ } else {
+ future.completeExceptionally(new RuntimeException());
+ }
+ });
+ int profilesUserId = profiles.get(i).getIdentifier();
+ getOrCreateController(profilesUserId)
+ .onClearRoleHolders(roleName, flags, callback);
+ try {
+ future.get(5, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Log.e(LOG_TAG, "Exception while clearing role holders for non-active"
+ + "user: " + profilesUserId, e);
+ }
+ }
+ }
+
+ @Override
public void addOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, true,
- "addOnRoleHoldersChangedListenerAsUser", getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ true,
+ /* enforceForProfileGroup= */ false, "addOnRoleHoldersChangedListenerAsUser",
+ getContext());
if (userId != UserHandleCompat.USER_ALL && !UserUtils.isUserExistent(userId,
getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
@@ -658,7 +756,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public void removeOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, true,
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ true,
+ /* enforceForProfileGroup= */ false,
"removeOnRoleHoldersChangedListenerAsUser", getContext());
if (userId != UserHandleCompat.USER_ALL && !UserUtils.isUserExistent(userId,
getContext())) {
@@ -711,7 +810,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public boolean isRoleFallbackEnabledAsUser(@NonNull String roleName,
@UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false, "isRoleFallbackEnabledAsUser",
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "isRoleFallbackEnabledAsUser",
getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
@@ -729,7 +829,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public void setRoleFallbackEnabledAsUser(@NonNull String roleName, boolean fallbackEnabled,
@UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false, "setRoleFallbackEnabledAsUser",
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "setRoleFallbackEnabledAsUser",
getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
@@ -747,7 +848,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public void setRoleNamesFromControllerAsUser(@NonNull List<String> roleNames,
@UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false, "setRoleNamesFromControllerAsUser",
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "setRoleNamesFromControllerAsUser",
getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
@@ -766,8 +868,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public boolean addRoleHolderFromControllerAsUser(@NonNull String roleName,
@NonNull String packageName, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false,
- "addRoleHolderFromControllerAsUser", getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "addRoleHolderFromControllerAsUser",
+ getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return false;
@@ -786,8 +889,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public boolean removeRoleHolderFromControllerAsUser(@NonNull String roleName,
@NonNull String packageName, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false,
- "removeRoleHolderFromControllerAsUser", getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "removeRoleHolderFromControllerAsUser",
+ getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return false;
@@ -806,8 +910,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public List<String> getHeldRolesFromControllerAsUser(@NonNull String packageName,
@UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false,
- "getHeldRolesFromControllerAsUser", getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "getHeldRolesFromControllerAsUser",
+ getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return Collections.emptyList();
@@ -916,7 +1021,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public String getSmsRoleHolder(int userId) {
final Context context = getContext();
- UserUtils.enforceCrossUserPermission(userId, false, "getSmsRoleHolder", context);
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "getSmsRoleHolder", context);
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return null;
@@ -940,7 +1046,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public String getEmergencyRoleHolder(int userId) {
final Context context = getContext();
- UserUtils.enforceCrossUserPermission(userId, false, "getEmergencyRoleHolder", context);
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "getEmergencyRoleHolder", context);
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return null;
@@ -966,8 +1073,8 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public boolean isRoleVisibleAsUser(@NonNull String roleName, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false, "isRoleVisibleAsUser",
- getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "isRoleVisibleAsUser", getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return false;
@@ -984,8 +1091,9 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public boolean isApplicationVisibleForRoleAsUser(@NonNull String roleName,
@NonNull String packageName, @UserIdInt int userId) {
- UserUtils.enforceCrossUserPermission(userId, false,
- "isApplicationVisibleForRoleAsUser", getContext());
+ UserUtils.enforceCrossUserPermission(userId, /* allowAll= */ false,
+ /* enforceForProfileGroup= */ false, "isApplicationVisibleForRoleAsUser",
+ getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.e(LOG_TAG, "user " + userId + " does not exist");
return false;
@@ -1042,6 +1150,36 @@ public class RoleService extends SystemService implements RoleUserState.Callback
return true;
}
}
+
+ private void enforceCallingOrSelfAnyPermissions(@NonNull String[] permissions,
+ @NonNull String message) {
+ for (String permission : permissions) {
+ if (getContext().checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ }
+
+ throw new SecurityException(message + ": Neither user " + Binder.getCallingUid()
+ + " nor current process has at least one of" + Arrays.toString(permissions)
+ + ".");
+ }
+
+ private void enforceProfileGroupExclusiveRole(@NonNull String roleName) {
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Role role = Roles.get(getContext()).get(roleName);
+ Objects.requireNonNull(role, "Unknown role: " + roleName);
+ Preconditions.checkArgument(
+ role.getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP,
+ roleName + " is not a profile-group exclusive role");
+ }
+
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private boolean isProfileGroupExclusivityAvailable() {
+ // TODO(b/372743073): change to isAtLeastB once available
+ return SdkLevel.isAtLeastV()
+ && com.android.permission.flags.Flags.crossUserRoleEnabled();
+ }
}
private class Local implements RoleManagerLocal {
diff --git a/service/java/com/android/role/RoleShellCommand.java b/service/java/com/android/role/RoleShellCommand.java
index 41f0702a2..538e62f47 100644
--- a/service/java/com/android/role/RoleShellCommand.java
+++ b/service/java/com/android/role/RoleShellCommand.java
@@ -87,6 +87,10 @@ class RoleShellCommand extends BasicShellCommandHandler {
return runClearRoleHolders();
case "set-bypassing-role-qualification":
return runSetBypassingRoleQualification();
+ case "get-active-user-for-role":
+ return runGetActiveUserForRole();
+ case "set-active-user-for-role":
+ return runSetActiveUserForRole();
default:
return handleDefaultCommands(cmd);
}
@@ -162,6 +166,27 @@ class RoleShellCommand extends BasicShellCommandHandler {
return 0;
}
+ private int runGetActiveUserForRole() throws RemoteException {
+ int userId = getUserIdMaybe();
+ String roleName = getNextArgRequired();
+
+ int activeUserId = mRoleManager.getActiveUserForRoleAsUser(roleName, userId);
+ if (activeUserId != UserHandleCompat.USER_NULL) {
+ getOutPrintWriter().println(activeUserId);
+ }
+ return 0;
+ }
+
+ private int runSetActiveUserForRole() throws RemoteException {
+ int userId = getUserIdMaybe();
+ String roleName = getNextArgRequired();
+ int activeUserId = Integer.parseInt(getNextArgRequired());
+ int flags = getFlagsMaybe();
+
+ mRoleManager.setActiveUserForRoleAsUser(roleName, activeUserId, flags, userId);
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -174,6 +199,8 @@ class RoleShellCommand extends BasicShellCommandHandler {
pw.println(" remove-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]");
pw.println(" clear-role-holders [--user USER_ID] ROLE [FLAGS]");
pw.println(" set-bypassing-role-qualification true|false");
+ pw.println(" get-active-user-for-role [--user USER_ID] ROLE");
+ pw.println(" set-active-user-for-role [--user USER_ID] ROLE ACTIVE_USER_ID [FLAGS]");
pw.println();
}
}
diff --git a/service/java/com/android/role/RoleUserState.java b/service/java/com/android/role/RoleUserState.java
index cda7fcfa8..c94b58826 100644
--- a/service/java/com/android/role/RoleUserState.java
+++ b/service/java/com/android/role/RoleUserState.java
@@ -24,6 +24,7 @@ import android.annotation.WorkerThread;
import android.os.Build;
import android.os.Handler;
import android.os.UserHandle;
+import android.permission.internal.compat.UserHandleCompat;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -428,6 +429,42 @@ class RoleUserState {
}
/**
+ * Return the active user for the role
+ *
+ * @param roleName the name of the role to get the active user for
+ */
+ public int getActiveUserForRole(@NonNull String roleName) {
+ synchronized (mLock) {
+ return mActiveUserIds.getOrDefault(roleName, UserHandleCompat.USER_NULL);
+ }
+ }
+
+ /**
+ * Set the active user for the role
+ *
+ * @param roleName the name of the role to set the active user for
+ * @param userId User id to set as active for this role
+ * @return whether any changes were made
+ */
+ public boolean setActiveUserForRole(@NonNull String roleName, @UserIdInt int userId) {
+ if (!com.android.permission.flags.Flags.crossUserRoleEnabled()) {
+ return false;
+ }
+ synchronized (mLock) {
+ Integer currentActiveUserId = mActiveUserIds.get(roleName);
+ // If we have pre-existing roles that weren't profile group exclusive and don't have an
+ // active user, ensure we set and write value, and return modified, otherwise other
+ // users might not have role holder revoked.
+ if (currentActiveUserId != null && currentActiveUserId == userId) {
+ return false;
+ }
+ mActiveUserIds.put(roleName, userId);
+ scheduleWriteFileLocked();
+ return true;
+ }
+ }
+
+ /**
* Schedule writing the state to file.
*/
@GuardedBy("mLock")
diff --git a/service/java/com/android/safetycenter/SafetyCenterService.java b/service/java/com/android/safetycenter/SafetyCenterService.java
index 250be5f25..6df4184e1 100644
--- a/service/java/com/android/safetycenter/SafetyCenterService.java
+++ b/service/java/com/android/safetycenter/SafetyCenterService.java
@@ -694,7 +694,8 @@ public final class SafetyCenterService extends SystemService {
/** Enforces cross user permission and returns whether the user is valid. */
private boolean enforceCrossUserPermission(String message, @UserIdInt int userId) {
UserUtils.enforceCrossUserPermission(
- userId, /* allowAll= */ false, message, getContext());
+ userId, /* allowAll= */ false, /* enforceForProfileGroup= */ false, message,
+ getContext());
if (!UserUtils.isUserExistent(userId, getContext())) {
Log.w(
TAG,
diff --git a/service/java/com/android/safetycenter/UserProfileGroup.java b/service/java/com/android/safetycenter/UserProfileGroup.java
index d4b051d0f..1f5258437 100644
--- a/service/java/com/android/safetycenter/UserProfileGroup.java
+++ b/service/java/com/android/safetycenter/UserProfileGroup.java
@@ -21,16 +21,12 @@ import static java.util.Objects.requireNonNull;
import android.annotation.IntDef;
import android.annotation.UserIdInt;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.Binder;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.permission.internal.compat.UserHandleCompat;
import android.util.Log;
-import androidx.annotation.Nullable;
-
import com.android.permission.util.UserUtils;
import java.lang.annotation.Retention;
@@ -135,11 +131,7 @@ public final class UserProfileGroup {
public static UserProfileGroup fromUser(Context context, @UserIdInt int userId) {
Context userContext = UserUtils.getUserContext(userId, context);
List<UserHandle> userProfiles = UserUtils.getUserProfiles(userContext);
- UserHandle profileParent = UserUtils.getProfileParent(userId, userContext);
- int profileParentUserId = userId;
- if (profileParent != null) {
- profileParentUserId = profileParent.getIdentifier();
- }
+ int profileParentUserId = UserUtils.getProfileParentIdOrSelf(userId, userContext);
int[] managedProfilesUserIds = new int[userProfiles.size()];
int[] managedRunningProfilesUserIds = new int[userProfiles.size()];