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
This commit is contained in:
Adam Bookatz
2021-07-20 17:45:23 -07:00
parent 567fe7b464
commit 80dc45dd7e
5 changed files with 48 additions and 11 deletions

View File

@@ -62,6 +62,10 @@ and the PROFILE user android.os.usertype.profile.MANAGED) and creates a new PROF
<default-restrictions no_sms="true" no_outgoing_calls="true" />
</profile-type>
<full-type
name="android.os.usertype.full.RESTRICTED"
enabled='0' />
<profile-type
name="com.example.profilename"
max-allowed-per-parent="2" />
@@ -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'.

View File

@@ -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;

View File

@@ -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<DefaultCrossProfileIntentFilter> 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() {

View File

@@ -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)) {

View File

@@ -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()));