diff --git a/core/res/res/xml/config_user_types.xml b/core/res/res/xml/config_user_types.xml index 71dfc551ccc14..766315029f3d1 100644 --- a/core/res/res/xml/config_user_types.xml +++ b/core/res/res/xml/config_user_types.xml @@ -62,6 +62,10 @@ and the PROFILE user android.os.usertype.profile.MANAGED) and creates a new PROF + + @@ -78,6 +82,7 @@ Mandatory attributes: Supported optional properties (to be used as shown in the example above) are as follows. For profile and full users: default-restrictions (with values defined in UserRestrictionUtils.USER_RESTRICTIONS) + enabled For profile users only: max-allowed-per-parent icon-badge @@ -98,6 +103,9 @@ If this file is updated, the properties of any pre-existing user types will be u Note, however, that default-restrictions refers to the restrictions applied at the time of user creation; therefore, the active restrictions of any pre-existing users will not be updated. +If a user type is disabled, by setting enabled='0', then no further users of that type may be +created; however, any pre-existing users of that type will remain. + The 'change-user-type' tag should be used in conjunction with the 'version' property of 'user-types'. It defines a type change for all pre-existing users of 'from' type to the new 'to' type, if the former 'user-type's version of device is less than or equal to 'whenVersionLeq'. diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 190e7bcee3325..0d909a949a14a 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2357,6 +2357,9 @@ public class UserManagerService extends IUserManager.Stub { * {@link #canAddMoreProfilesToUser}. */ private boolean canAddMoreUsersOfType(UserTypeDetails userTypeDetails) { + if (!userTypeDetails.isEnabled()) { + return false; + } final int max = userTypeDetails.getMaxAllowed(); if (max == UserTypeDetails.UNLIMITED_NUMBER_OF_USERS) { return true; // Indicates that there is no max. @@ -2397,7 +2400,7 @@ public class UserManagerService extends IUserManager.Stub { boolean allowedToRemoveOne) { checkManageUsersPermission("check if more profiles can be added."); final UserTypeDetails type = mUserTypes.get(userType); - if (type == null) { + if (type == null || !type.isEnabled()) { return false; } // Managed profiles have their own specific rules. @@ -3553,6 +3556,12 @@ public class UserManagerService extends IUserManager.Stub { + ") indicated SYSTEM user, which cannot be created."); return null; } + if (!userTypeDetails.isEnabled()) { + throwCheckedUserOperationException( + "Cannot add a user of disabled type " + userType + ".", + UserManager.USER_OPERATION_ERROR_MAX_USERS); + } + synchronized (mUsersLock) { if (mForceEphemeralUsers) { flags |= UserInfo.FLAG_EPHEMERAL; diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java index 92ec31b21e07a..24dab9ed73b99 100644 --- a/services/core/java/com/android/server/pm/UserTypeDetails.java +++ b/services/core/java/com/android/server/pm/UserTypeDetails.java @@ -50,7 +50,7 @@ public final class UserTypeDetails { /** Name of the user type, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}. */ private final @NonNull String mName; - // TODO(b/142482943): Currently unused. Hook this up. + /** Whether users of this type can be created. */ private final boolean mEnabled; // TODO(b/142482943): Currently unused and not set. Hook this up. @@ -195,7 +195,10 @@ public final class UserTypeDetails { return mName; } - // TODO(b/142482943) Hook this up or delete it. + /** + * Returns whether this user type is enabled. + * If it is not enabled, all future attempts to create users of this type will be rejected. + */ public boolean isEnabled() { return mEnabled; } @@ -390,7 +393,7 @@ public final class UserTypeDetails { private @Nullable Bundle mDefaultSecureSettings = null; private @Nullable List mDefaultCrossProfileIntentFilters = null; - private boolean mEnabled = true; + private int mEnabled = 1; private int mLabel = Resources.ID_NULL; private @Nullable int[] mBadgeLabels = null; private @Nullable int[] mBadgeColors = null; @@ -405,7 +408,7 @@ public final class UserTypeDetails { return this; } - public Builder setEnabled(boolean enabled) { + public Builder setEnabled(int enabled) { mEnabled = enabled; return this; } @@ -522,12 +525,25 @@ public final class UserTypeDetails { "UserTypeDetails %s has a non empty " + "defaultCrossProfileIntentFilters", mName); } - return new UserTypeDetails(mName, mEnabled, mMaxAllowed, mBaseType, - mDefaultUserInfoPropertyFlags, mLabel, mMaxAllowedPerParent, - mIconBadge, mBadgePlain, mBadgeNoBackground, mBadgeLabels, mBadgeColors, + return new UserTypeDetails( + mName, + mEnabled != 0, + mMaxAllowed, + mBaseType, + mDefaultUserInfoPropertyFlags, + mLabel, + mMaxAllowedPerParent, + mIconBadge, + mBadgePlain, + mBadgeNoBackground, + mBadgeLabels, + mBadgeColors, mDarkThemeBadgeColors == null ? mBadgeColors : mDarkThemeBadgeColors, - mDefaultRestrictions, mDefaultSystemSettings, mDefaultSecureSettings, - mDefaultCrossProfileIntentFilters, mIsMediaSharedWithParent); + mDefaultRestrictions, + mDefaultSystemSettings, + mDefaultSecureSettings, + mDefaultCrossProfileIntentFilters, + mIsMediaSharedWithParent); } private boolean hasBadge() { diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java index 30cb40c342035..5fcb843a26994 100644 --- a/services/core/java/com/android/server/pm/UserTypeFactory.java +++ b/services/core/java/com/android/server/pm/UserTypeFactory.java @@ -376,6 +376,8 @@ public final class UserTypeFactory { setResAttribute(parser, "badge-no-background", builder::setBadgeNoBackground); } + setIntAttribute(parser, "enabled", builder::setEnabled); + // Process child elements. final int depth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, depth)) { diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java index cd98d44075ca4..f1acc66798777 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java @@ -81,7 +81,7 @@ public class UserManagerServiceUserTypeTest { /* letsPersonalDataIntoProfile= */false).build()); final UserTypeDetails type = new UserTypeDetails.Builder() .setName("a.name") - .setEnabled(true) + .setEnabled(1) .setMaxAllowed(21) .setBaseType(FLAG_PROFILE) .setDefaultUserInfoPropertyFlags(FLAG_EPHEMERAL) @@ -316,6 +316,7 @@ public class UserManagerServiceUserTypeTest { builders.put(userTypeFull, new UserTypeDetails.Builder() .setName(userTypeFull) .setBaseType(FLAG_FULL) + .setEnabled(0) .setDefaultRestrictions(restrictions)); final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_full); @@ -323,6 +324,7 @@ public class UserManagerServiceUserTypeTest { UserTypeDetails details = builders.get(userTypeFull).createUserTypeDetails(); assertEquals(UNLIMITED_NUMBER_OF_USERS, details.getMaxAllowedPerParent()); + assertFalse(details.isEnabled()); assertTrue(UserRestrictionsUtils.areEqual( makeRestrictionsBundle("no_remove_user", "no_bluetooth"), details.getDefaultRestrictions()));