From 80dc45dd7ef4f6902e123b5d5926bdd73b440491 Mon Sep 17 00:00:00 2001 From: Adam Bookatz Date: Tue, 20 Jul 2021 17:45:23 -0700 Subject: [PATCH] UserTypeDetails - new enabled option Adds an option for enabling/disabling a user type. enabled=0 means disabled (otherwise it is enabled). We use an int (rather than a boolean) to make it clear what String value does what (1 vs. 0). If we had used a boolean, we'd have to worry about true/True/TRUE/1/etc.; with an int, the device will fail to boot if a non-int is given. If a user type is diabled, pre-existing users of that type are unaffected. However, no new users of that type may be created. We do NOT simply use the maxAllowed option (setting it to 0 to simulate disalbing) for ease-of-use and to avoid any potential complications with pre-created users. Bug: 192577100 Bug: 142482943 Test: atest UserManagerServiceUserTypeTest Change-Id: I3db25f3a48f9ba18a5dd3e74f6ac9b7638980497 --- core/res/res/xml/config_user_types.xml | 8 +++++ .../android/server/pm/UserManagerService.java | 11 +++++- .../android/server/pm/UserTypeDetails.java | 34 ++++++++++++++----- .../android/server/pm/UserTypeFactory.java | 2 ++ .../pm/UserManagerServiceUserTypeTest.java | 4 ++- 5 files changed, 48 insertions(+), 11 deletions(-) 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 89f2bfe4c64d7..11219c75a77db 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2352,6 +2352,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. @@ -2392,7 +2395,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. @@ -3549,6 +3552,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()));