summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Adam Bookatz <bookatz@google.com> 2023-02-10 16:46:45 -0800
committer Adam Bookatz <bookatz@google.com> 2023-02-10 16:46:45 -0800
commitbf5ccd26b937a06eac73f7c70bbedbb1a7decbca (patch)
tree63aaca82501fd8c99b87746f485d092515963646
parent51a18cab4ffb714993a65574abf1ef0431a4815e (diff)
Various createUsers don't sometimes return null
Previously, UserManagerService.createUserInternalUncheckedNoTracing would usually throw on failure, but could instead return null in certain circumstances (namely, bad input). This lead to ambiguity over whether the various createUser methods were able to return null. Here, we throw instead in these previously-null situations. This way, all of the createUser methods are @NonNull, unless they specifically catch errors and return null instead. The methods are now all self-consistent. In particular, this fixes the previously not-always-correct annotation of @NonNull that is on UserManager.preCreateUser. Bug: 219942927 Test: atest com.android.server.pm.UserManagerTest Test: atest com.android.server.pm.UserManagerServiceTest Test: atest android.multiuser.cts.UserManagerTest Change-Id: I7a63b4e684d03b4d2ef76046d0cf277ba2d5744d
-rw-r--r--core/java/android/os/UserManager.java48
-rw-r--r--services/core/java/com/android/server/pm/UserManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java104
-rw-r--r--services/java/com/android/server/HsumBootUserInitializer.java6
4 files changed, 86 insertions, 77 deletions
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1df45d132f34..c60f55868c00 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3612,7 +3612,7 @@ public class UserManager {
*
* <p>Requires {@link android.Manifest.permission#MANAGE_USERS}.
* {@link android.Manifest.permission#CREATE_USERS} suffices if flags are in
- * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION}.
+ * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION.
*
* @param name the user's name
* @param userType the type of user, such as {@link UserManager#USER_TYPE_FULL_GUEST}.
@@ -3686,7 +3686,7 @@ public class UserManager {
*
* <p>Requires {@link android.Manifest.permission#MANAGE_USERS}.
* {@link android.Manifest.permission#CREATE_USERS} suffices if flags are in
- * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION}.
+ * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION.
*
* @param userType the type of user, such as {@link UserManager#USER_TYPE_FULL_GUEST}.
* @return the {@link UserInfo} object for the created user.
@@ -3718,25 +3718,23 @@ public class UserManager {
*/
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public UserInfo createGuest(Context context) {
+ public @Nullable UserInfo createGuest(Context context) {
try {
final UserInfo guest = mService.createUserWithThrow(null, USER_TYPE_FULL_GUEST, 0);
- if (guest != null) {
- Settings.Secure.putStringForUser(context.getContentResolver(),
- Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
-
- if (UserManager.isGuestUserAllowEphemeralStateChange()) {
- // Mark guest as (changeably) ephemeral if REMOVE_GUEST_ON_EXIT is 1
- // This is done so that a user via a UI controller can choose to
- // make a guest as ephemeral or not.
- // Settings.Global.REMOVE_GUEST_ON_EXIT holds the choice on what the guest state
- // should be, with default being ephemeral.
- boolean resetGuestOnExit = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.REMOVE_GUEST_ON_EXIT, 1) == 1;
-
- if (resetGuestOnExit && !guest.isEphemeral()) {
- setUserEphemeral(guest.id, true);
- }
+ Settings.Secure.putStringForUser(context.getContentResolver(),
+ Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
+
+ if (UserManager.isGuestUserAllowEphemeralStateChange()) {
+ // Mark guest as (changeably) ephemeral if REMOVE_GUEST_ON_EXIT is 1
+ // This is done so that a user via a UI controller can choose to
+ // make a guest as ephemeral or not.
+ // Settings.Global.REMOVE_GUEST_ON_EXIT holds the choice on what the guest state
+ // should be, with default being ephemeral.
+ boolean resetGuestOnExit = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.REMOVE_GUEST_ON_EXIT, 1) == 1;
+
+ if (resetGuestOnExit && !guest.isEphemeral()) {
+ setUserEphemeral(guest.id, true);
}
}
return guest;
@@ -3855,7 +3853,7 @@ public class UserManager {
*/
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public UserInfo createProfileForUser(String name, @NonNull String userType,
+ public @Nullable UserInfo createProfileForUser(String name, @NonNull String userType,
@UserInfoFlag int flags, @UserIdInt int userId) {
return createProfileForUser(name, userType, flags, userId, null);
}
@@ -3900,7 +3898,7 @@ public class UserManager {
*/
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public UserInfo createProfileForUserEvenWhenDisallowed(String name,
+ public @Nullable UserInfo createProfileForUserEvenWhenDisallowed(String name,
@NonNull String userType, @UserInfoFlag int flags, @UserIdInt int userId,
String[] disallowedPackages) {
try {
@@ -3931,11 +3929,9 @@ public class UserManager {
try {
final int parentUserId = mUserId;
final UserInfo profile = mService.createRestrictedProfileWithThrow(name, parentUserId);
- if (profile != null) {
- final UserHandle parentUserHandle = UserHandle.of(parentUserId);
- AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle,
- UserHandle.of(profile.id));
- }
+ final UserHandle parentUserHandle = UserHandle.of(parentUserId);
+ AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle,
+ UserHandle.of(profile.id));
return profile;
} catch (ServiceSpecificException e) {
return null;
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 3cbaebe4101e..36efc0ddfc44 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -238,8 +238,9 @@ public abstract class UserManagerInternal {
* the user is created (as it will be passed back to it through
* {@link UserLifecycleListener#onUserCreated(UserInfo, Object)});
*/
- public abstract UserInfo createUserEvenWhenDisallowed(String name, String userType,
- int flags, String[] disallowedPackages, @Nullable Object token)
+ public abstract @NonNull UserInfo createUserEvenWhenDisallowed(
+ @Nullable String name, @NonNull String userType, @UserInfo.UserInfoFlag int flags,
+ @Nullable String[] disallowedPackages, @Nullable Object token)
throws UserManager.CheckedUserOperationException;
/**
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index ce7dc5b953ee..3cc92cf3b965 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4494,9 +4494,11 @@ public class UserManagerService extends IUserManager.Stub {
* as well as for {@link UserManager#USER_TYPE_FULL_RESTRICTED}.
*/
@Override
- public UserInfo createProfileForUserWithThrow(@Nullable String name, @NonNull String userType,
- @UserInfoFlag int flags, @UserIdInt int userId, @Nullable String[] disallowedPackages)
+ public @NonNull UserInfo createProfileForUserWithThrow(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @UserIdInt int userId, @Nullable String[] disallowedPackages)
throws ServiceSpecificException {
+
checkCreateUsersPermission(flags);
try {
return createUserInternal(name, userType, flags, userId, disallowedPackages);
@@ -4509,10 +4511,11 @@ public class UserManagerService extends IUserManager.Stub {
* @see #createProfileForUser
*/
@Override
- public UserInfo createProfileForUserEvenWhenDisallowedWithThrow(String name,
- @NonNull String userType,
- @UserInfoFlag int flags, @UserIdInt int userId, @Nullable String[] disallowedPackages)
+ public @NonNull UserInfo createProfileForUserEvenWhenDisallowedWithThrow(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @UserIdInt int userId, @Nullable String[] disallowedPackages)
throws ServiceSpecificException {
+
checkCreateUsersPermission(flags);
try {
return createUserInternalUnchecked(name, userType, flags, userId,
@@ -4523,9 +4526,10 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public UserInfo createUserWithThrow(String name, @NonNull String userType,
- @UserInfoFlag int flags)
+ public @NonNull UserInfo createUserWithThrow(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags)
throws ServiceSpecificException {
+
checkCreateUsersPermission(flags);
try {
return createUserInternal(name, userType, flags, UserHandle.USER_NULL,
@@ -4536,7 +4540,10 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public UserInfo preCreateUserWithThrow(String userType) throws ServiceSpecificException {
+ public @NonNull UserInfo preCreateUserWithThrow(
+ @NonNull String userType)
+ throws ServiceSpecificException {
+
final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
final int flags = userTypeDetails != null ? userTypeDetails.getDefaultUserInfoFlags() : 0;
@@ -4556,10 +4563,12 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public UserHandle createUserWithAttributes(
- String userName, String userType, @UserInfoFlag int flags,
- Bitmap userIcon,
- String accountName, String accountType, PersistableBundle accountOptions) {
+ public @NonNull UserHandle createUserWithAttributes(
+ @Nullable String userName, @NonNull String userType, @UserInfoFlag int flags,
+ @Nullable Bitmap userIcon, @Nullable String accountName, @Nullable String accountType,
+ @Nullable PersistableBundle accountOptions)
+ throws ServiceSpecificException {
+
checkCreateUsersPermission(flags);
if (someUserHasAccountNoChecks(accountName, accountType)) {
@@ -4569,12 +4578,7 @@ public class UserManagerService extends IUserManager.Stub {
UserInfo userInfo;
try {
- userInfo = createUserInternal(userName, userType, flags,
- UserHandle.USER_NULL, null);
-
- if (userInfo == null) {
- throw new ServiceSpecificException(USER_OPERATION_ERROR_UNKNOWN);
- }
+ userInfo = createUserInternal(userName, userType, flags, UserHandle.USER_NULL, null);
} catch (UserManager.CheckedUserOperationException e) {
throw e.toServiceSpecificException();
}
@@ -4588,7 +4592,8 @@ public class UserManagerService extends IUserManager.Stub {
return userInfo.getUserHandle();
}
- private UserInfo createUserInternal(@Nullable String name, @NonNull String userType,
+ private @NonNull UserInfo createUserInternal(
+ @Nullable String name, @NonNull String userType,
@UserInfoFlag int flags, @UserIdInt int parentId,
@Nullable String[] disallowedPackages)
throws UserManager.CheckedUserOperationException {
@@ -4610,11 +4615,12 @@ public class UserManagerService extends IUserManager.Stub {
/* preCreate= */ false, disallowedPackages, /* token= */ null);
}
- private UserInfo createUserInternalUnchecked(@Nullable String name,
- @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
- boolean preCreate, @Nullable String[] disallowedPackages,
+ private @NonNull UserInfo createUserInternalUnchecked(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages,
@Nullable Object token)
throws UserManager.CheckedUserOperationException {
+
final int noneUserId = -1;
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("createUser-" + flags);
@@ -4632,27 +4638,31 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name,
- @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
- boolean preCreate, @Nullable String[] disallowedPackages,
+ private @NonNull UserInfo createUserInternalUncheckedNoTracing(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages,
@NonNull TimingsTraceAndSlog t, @Nullable Object token)
- throws UserManager.CheckedUserOperationException {
+ throws UserManager.CheckedUserOperationException {
+
final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
if (userTypeDetails == null) {
- Slog.e(LOG_TAG, "Cannot create user of invalid user type: " + userType);
- return null;
+ throwCheckedUserOperationException(
+ "Cannot create user of invalid user type: " + userType,
+ USER_OPERATION_ERROR_UNKNOWN);
}
userType = userType.intern(); // Now that we know it's valid, we can intern it.
flags |= userTypeDetails.getDefaultUserInfoFlags();
if (!checkUserTypeConsistency(flags)) {
- Slog.e(LOG_TAG, "Cannot add user. Flags (" + Integer.toHexString(flags)
- + ") and userTypeDetails (" + userType + ") are inconsistent.");
- return null;
+ throwCheckedUserOperationException(
+ "Cannot add user. Flags (" + Integer.toHexString(flags)
+ + ") and userTypeDetails (" + userType + ") are inconsistent.",
+ USER_OPERATION_ERROR_UNKNOWN);
}
if ((flags & UserInfo.FLAG_SYSTEM) != 0) {
- Slog.e(LOG_TAG, "Cannot add user. Flags (" + Integer.toHexString(flags)
- + ") indicated SYSTEM user, which cannot be created.");
- return null;
+ throwCheckedUserOperationException(
+ "Cannot add user. Flags (" + Integer.toHexString(flags)
+ + ") indicated SYSTEM user, which cannot be created.",
+ USER_OPERATION_ERROR_UNKNOWN);
}
if (!isUserTypeEnabled(userTypeDetails)) {
throwCheckedUserOperationException(
@@ -4678,7 +4688,8 @@ public class UserManagerService extends IUserManager.Stub {
DeviceStorageMonitorInternal dsm = LocalServices
.getService(DeviceStorageMonitorInternal.class);
if (dsm.isMemoryLow()) {
- throwCheckedUserOperationException("Cannot add user. Not enough space on disk.",
+ throwCheckedUserOperationException(
+ "Cannot add user. Not enough space on disk.",
UserManager.USER_OPERATION_ERROR_LOW_STORAGE);
}
@@ -4706,7 +4717,8 @@ public class UserManagerService extends IUserManager.Stub {
}
}
if (!preCreate && !canAddMoreUsersOfType(userTypeDetails)) {
- throwCheckedUserOperationException("Cannot add more users of type " + userType
+ throwCheckedUserOperationException(
+ "Cannot add more users of type " + userType
+ ". Maximum number of that type already exists.",
UserManager.USER_OPERATION_ERROR_MAX_USERS);
}
@@ -5331,13 +5343,13 @@ public class UserManagerService extends IUserManager.Stub {
* @hide
*/
@Override
- public UserInfo createRestrictedProfileWithThrow(@Nullable String name, int parentUserId) {
+ public @NonNull UserInfo createRestrictedProfileWithThrow(
+ @Nullable String name, @UserIdInt int parentUserId)
+ throws ServiceSpecificException {
+
checkCreateUsersPermission("setupRestrictedProfile");
final UserInfo user = createProfileForUserWithThrow(
name, UserManager.USER_TYPE_FULL_RESTRICTED, 0, parentUserId, null);
- if (user == null) {
- return null;
- }
final long identity = Binder.clearCallingIdentity();
try {
setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
@@ -6338,8 +6350,10 @@ public class UserManagerService extends IUserManager.Stub {
setSeedAccountDataNoChecks(userId, accountName, accountType, accountOptions, persist);
}
- private void setSeedAccountDataNoChecks(@UserIdInt int userId, String accountName,
- String accountType, PersistableBundle accountOptions, boolean persist) {
+ private void setSeedAccountDataNoChecks(@UserIdInt int userId, @Nullable String accountName,
+ @Nullable String accountType, @Nullable PersistableBundle accountOptions,
+ boolean persist) {
+
synchronized (mPackagesLock) {
final UserData userData;
synchronized (mUsersLock) {
@@ -6908,9 +6922,11 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public UserInfo createUserEvenWhenDisallowed(String name, @NonNull String userType,
- @UserInfoFlag int flags, String[] disallowedPackages, @Nullable Object token)
+ public @NonNull UserInfo createUserEvenWhenDisallowed(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @Nullable String[] disallowedPackages, @Nullable Object token)
throws UserManager.CheckedUserOperationException {
+
return createUserInternalUnchecked(name, userType, flags,
UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages, token);
}
diff --git a/services/java/com/android/server/HsumBootUserInitializer.java b/services/java/com/android/server/HsumBootUserInitializer.java
index c4ad80e4c2c6..4e649150e6f1 100644
--- a/services/java/com/android/server/HsumBootUserInitializer.java
+++ b/services/java/com/android/server/HsumBootUserInitializer.java
@@ -112,11 +112,7 @@ final class HsumBootUserInitializer {
UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN,
/* disallowedPackages= */ null,
/* token= */ null);
- if (newInitialUser == null) {
- Slogf.wtf(TAG, "Initial bootable MainUser creation failed: returned null");
- } else {
- Slogf.i(TAG, "Successfully created MainUser, userId=%d", newInitialUser.id);
- }
+ Slogf.i(TAG, "Successfully created MainUser, userId=%d", newInitialUser.id);
} catch (UserManager.CheckedUserOperationException e) {
Slogf.wtf(TAG, "Initial bootable MainUser creation failed", e);
}