Loading services/core/java/com/android/server/pm/HsumBootUserInitializer.java +31 −1 Original line number Diff line number Diff line Loading @@ -200,7 +200,35 @@ public final class HsumBootUserInitializer { } return; } if (!promoteAdminUserToMainUserIfNeeded(t)) { createInitialUser(/* isMainUser= */ true); } } finally { t.traceEnd(); } } private boolean promoteAdminUserToMainUserIfNeeded(TimingsTraceAndSlog t) { t.traceBegin("promoteAdminUserToMainUserIfNeeded"); try { // TODO(b/419086491): use getUsers(Filter) var users = mUms.getUsers(/* excludeDying= */ true); int numberUsers = users.size(); for (int i = 0; i < numberUsers; i++) { var user = users.get(i); if (user.isFull() && user.isAdmin()) { Slogf.i(TAG, "Promoting admin user (%d) as main user", user.id); if (!mUms.setMainUser(user.id)) { Slogf.e(TAG, "Failed to promote admin user (%d) as main user", user.id); continue; } return true; } } if (DEBUG) { Slogf.d(TAG, "No existing admin user was promoted as main user (users=%s)", users); } return false; } finally { t.traceEnd(); } Loading @@ -223,9 +251,11 @@ public final class HsumBootUserInitializer { t.traceEnd(); } } private void createAdminUserIfNeeded(TimingsTraceAndSlog t) { t.traceBegin("createAdminUserIfNeeded"); try { // TODO(b/419086491): use getUsers(Filter) int[] userIds = mUms.getUserIds(); if (userIds != null && userIds.length > 1) { if (DEBUG) { Loading services/core/java/com/android/server/pm/UserJourneyLogger.java +4 −1 Original line number Diff line number Diff line Loading @@ -106,6 +106,8 @@ public class UserJourneyLogger { FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_LIFECYCLE; public static final int USER_JOURNEY_DEMOTE_MAIN_USER = FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__DEMOTE_MAIN_USER; public static final int USER_JOURNEY_PROMOTE_MAIN_USER = FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__PROMOTE_MAIN_USER; @IntDef(prefix = {"USER_JOURNEY"}, value = { USER_JOURNEY_UNKNOWN, Loading @@ -118,7 +120,8 @@ public class UserJourneyLogger { USER_JOURNEY_GRANT_ADMIN, USER_JOURNEY_REVOKE_ADMIN, USER_JOURNEY_USER_LIFECYCLE, USER_JOURNEY_DEMOTE_MAIN_USER USER_JOURNEY_DEMOTE_MAIN_USER, USER_JOURNEY_PROMOTE_MAIN_USER }) public @interface UserJourney { } Loading services/core/java/com/android/server/pm/UserManagerService.java +48 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_ALREADY_AN import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_IS_NOT_AN_ADMIN; import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_INVALID_USER_TYPE; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_DEMOTE_MAIN_USER; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_PROMOTE_MAIN_USER; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_GRANT_ADMIN; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_CREATE; Loading Loading @@ -8851,6 +8852,11 @@ public class UserManagerService extends IUserManager.Stub { return defaultValue; } /** * "Demotes" the main user to be just an admin. * * <p>Should be called only by {@link HsumBootUserInitializer} and unit tests */ boolean demoteMainUser() { if (!android.multiuser.Flags.demoteMainUser()) { Slog.d(LOG_TAG, "demoteMainUser(): ignoring because flag is disabled"); Loading @@ -8877,6 +8883,48 @@ public class UserManagerService extends IUserManager.Stub { } } /** * Sets the given user as the main user. * * <p>User must be an admin (and alive), and the current main user must be {@code null}. * * <p>Should be called only by {@link HsumBootUserInitializer} and unit tests * * @return whether it succeeded. */ boolean setMainUser(@UserIdInt int userId) { if (!android.multiuser.Flags.demoteMainUser()) { Slogf.d(LOG_TAG, "setMainUser(%d): ignoring because flag is disabled", userId); return false; } synchronized (mUsersLock) { var mainUser = getMainUserLU(); if (mainUser != null) { Slogf.e(LOG_TAG, "setMainUser(%d): already have a main user (%d)", userId, mainUser.id); return false; } var userData = getUserDataLU(userId); if (userData == null) { Slogf.e(LOG_TAG, "setMainUser(%d): user not found", userId); return false; } if (!userData.info.isAdmin()) { Slogf.e(LOG_TAG, "setMainUser(%d): user is not an admin", userId); return false; } Slogf.i(LOG_TAG, "Setting user %d as main user", userId); mUserJourneyLogger.logUserJourneyBegin(userId, USER_JOURNEY_PROMOTE_MAIN_USER); userData.info.flags |= UserInfo.FLAG_MAIN; writeUserLP(userData); return true; } } /** * Returns true if {@link com.android.internal.R.bool#config_canSwitchToHeadlessSystemUser} * is true. If allowed, headless system user can run in the foreground even though Loading services/tests/mockingservicestests/src/com/android/server/pm/HsumBootUserInitializerTest.java +142 −20 Original line number Diff line number Diff line Loading @@ -18,13 +18,21 @@ package com.android.server.pm; import static android.multiuser.Flags.FLAG_CREATE_INITIAL_USER; import static android.os.UserHandle.USER_NULL; import static android.os.UserHandle.USER_SYSTEM; import static android.content.pm.UserInfo.FLAG_ADMIN; import static android.content.pm.UserInfo.FLAG_FULL; import static android.content.pm.UserInfo.FLAG_MAIN; import static android.content.pm.UserInfo.FLAG_SYSTEM; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.ADMIN_USER_CREATED; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.FIRST_ADMIN_USER_PROMOTED_TO_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.MAIN_USER_CREATED; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.MAIN_USER_DEMOTED; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.NO_USER_CREATED; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.SECOND_ADMIN_USER_PROMOTED_TO_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_NON_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_ADMINS; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_REGULAR; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_ONLY; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -62,8 +70,10 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; // NOTE: rename to HsumBootUserInitializerInitMethodTest if it needs to test other methods @RunWith(Parameterized.class) Loading @@ -72,10 +82,25 @@ public final class HsumBootUserInitializerTest { private static final String TAG = HsumBootUserInitializerTest.class.getSimpleName(); @UserIdInt private static final int NON_SYSTEM_USER_ID = 42; private static final int MAIN_USER_ID = 4; @UserIdInt private static final int ADMIN_USER_ID = 8; @UserIdInt private static final int ANOTHER_ADMIN_USER_ID = 15; @UserIdInt private static final int MAIN_USER_ID = 108; private static final int REGULAR_USER_ID = 16; // Pre-defined users. NOTE: only setting basic flags and not setting UserType. private final UserInfo mHeadlessSystemUser = createUser(USER_SYSTEM, FLAG_SYSTEM | FLAG_ADMIN); private final UserInfo mMainUser = createUser(MAIN_USER_ID, FLAG_FULL | FLAG_MAIN | FLAG_ADMIN); private final UserInfo mAdminUser = createUser(ADMIN_USER_ID, FLAG_FULL | FLAG_ADMIN); private final UserInfo mAnotherAdminUser = createUser(ANOTHER_ADMIN_USER_ID, FLAG_FULL | FLAG_ADMIN); private final UserInfo mRegularUser = createUser(REGULAR_USER_ID, FLAG_FULL); @Rule public final Expect expect = Expect.create(); Loading Loading @@ -112,19 +137,28 @@ public final class HsumBootUserInitializerTest { // shouldAlwaysHaveMainUser false, shouldCreateInitialUser false { false, false, SYSTEM_ONLY, NO_USER_CREATED }, { false, false, SYSTEM_AND_MAIN, MAIN_USER_DEMOTED }, { false, false, SYSTEM_AND_NON_MAIN, NO_USER_CREATED }, { false, false, SYSTEM_AND_ADMINS, NO_USER_CREATED }, { false, false, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, NO_USER_CREATED }, { false, false, SYSTEM_AND_REGULAR, NO_USER_CREATED }, // shouldAlwaysHaveMainUser false, shouldCreateInitialUser true { false, true, SYSTEM_ONLY, ADMIN_USER_CREATED}, { false, true, SYSTEM_AND_MAIN, MAIN_USER_DEMOTED }, { false, true, SYSTEM_AND_NON_MAIN, NO_USER_CREATED}, { false, true, SYSTEM_AND_ADMINS, NO_USER_CREATED }, { false, true, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, NO_USER_CREATED }, { false, true, SYSTEM_AND_REGULAR, NO_USER_CREATED }, // shouldAlwaysHaveMainUser true, shouldCreateInitialUser false { true, false, SYSTEM_ONLY, MAIN_USER_CREATED }, { true, false, SYSTEM_AND_MAIN, NO_USER_CREATED }, { true, false, SYSTEM_AND_NON_MAIN, MAIN_USER_CREATED}, { true, false, SYSTEM_AND_ADMINS, FIRST_ADMIN_USER_PROMOTED_TO_MAIN }, { true, false, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, SECOND_ADMIN_USER_PROMOTED_TO_MAIN }, { true, false, SYSTEM_AND_REGULAR, MAIN_USER_CREATED }, // shouldAlwaysHaveMainUser true, shouldCreateInitialUser true { true, true, SYSTEM_ONLY, MAIN_USER_CREATED }, { true, true, SYSTEM_AND_MAIN, NO_USER_CREATED }, { true, true, SYSTEM_AND_NON_MAIN, MAIN_USER_CREATED} { true, true, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, SECOND_ADMIN_USER_PROMOTED_TO_MAIN }, { true, true, SYSTEM_AND_REGULAR, MAIN_USER_CREATED } }); } Loading @@ -144,22 +178,36 @@ public final class HsumBootUserInitializerTest { public void setDefaultExpectations() throws Exception { switch (mInitialUsers) { case SYSTEM_ONLY: mockGetUserIds(USER_SYSTEM); mockGetUsers(mHeadlessSystemUser); mockGetMainUserId(USER_NULL); break; case SYSTEM_AND_MAIN: mockGetUserIds(USER_SYSTEM, MAIN_USER_ID); mockGetUsers(mHeadlessSystemUser, mMainUser); mockGetMainUserId(MAIN_USER_ID); break; case SYSTEM_AND_NON_MAIN: mockGetUserIds(USER_SYSTEM, NON_SYSTEM_USER_ID); case SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE: mockPromoteToMainUserFails(ADMIN_USER_ID); // fall through case SYSTEM_AND_ADMINS: mockGetUsers(mHeadlessSystemUser, mAdminUser, mAnotherAdminUser); mockGetMainUserId(USER_NULL); break; case SYSTEM_AND_REGULAR: mockGetUsers(mHeadlessSystemUser, mRegularUser); mockGetMainUserId(USER_NULL); break; } // NOTE: need to mock createNewUser() as the user id is used on Slog. switch (mExpectedResult) { case ADMIN_USER_CREATED: mockCreateNewUser(NON_SYSTEM_USER_ID); mockCreateNewUser(ADMIN_USER_ID); break; case FIRST_ADMIN_USER_PROMOTED_TO_MAIN: mockPromoteToMainUser(ADMIN_USER_ID); break; case SECOND_ADMIN_USER_PROMOTED_TO_MAIN: mockPromoteToMainUserFails(ADMIN_USER_ID); mockPromoteToMainUser(ANOTHER_ADMIN_USER_ID); break; case MAIN_USER_CREATED: mockCreateNewUser(MAIN_USER_ID); Loading Loading @@ -195,21 +243,36 @@ public final class HsumBootUserInitializerTest { switch (mExpectedResult) { case ADMIN_USER_CREATED: expectAdminUserCreated(); expectSetBootUserId(NON_SYSTEM_USER_ID); expectSetBootUserId(ADMIN_USER_ID); expectMainUserNotDemoted(); break; case FIRST_ADMIN_USER_PROMOTED_TO_MAIN: expectNoUserCreated(); expectSetBootUserIdNeverCalled(); expectAdminPromotedToMainUser(ADMIN_USER_ID); expectAdminNotPromotedToMainUser(ANOTHER_ADMIN_USER_ID); break; case SECOND_ADMIN_USER_PROMOTED_TO_MAIN: expectNoUserCreated(); expectSetBootUserIdNeverCalled(); // don't need to verify call to ADMIN_USER_ID - it was mocked to return false expectAdminPromotedToMainUser(ANOTHER_ADMIN_USER_ID); break; case MAIN_USER_CREATED: expectMainUserCreated(); expectSetBootUserId(MAIN_USER_ID); expectMainUserNotDemoted(); expectNoAdminPromotedToMainUser(); break; case NO_USER_CREATED: expectNoUserCreated(); expectMainUserNotDemoted(); expectNoAdminPromotedToMainUser(); break; case MAIN_USER_DEMOTED: expectNoUserCreated(); expectMainUserDemoted(); expectNoAdminPromotedToMainUser(); break; } } Loading Loading @@ -279,7 +342,6 @@ public final class HsumBootUserInitializerTest { expectSetBootUserIdNeverCalled(); } private void expectMainUserDemoted() { try { verify(mMockUms).demoteMainUser(); Loading @@ -300,6 +362,36 @@ public final class HsumBootUserInitializerTest { } } private void expectAdminPromotedToMainUser(@UserIdInt int userId) { try { verify(mMockUms).setMainUser(userId); } catch (Exception e) { String msg = "should have set main user as " + userId; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectAdminNotPromotedToMainUser(@UserIdInt int userId) { try { verify(mMockUms, never()).setMainUser(userId); } catch (Exception e) { String msg = "should have not set main user as " + userId; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectNoAdminPromotedToMainUser() { try { verify(mMockUms, never()).setMainUser(anyInt()); } catch (Exception e) { String msg = "should not have set main user"; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectSetBootUserId(@UserIdInt int userId) { try { verify(mMockUms).setBootUserIdUnchecked(userId); Loading Loading @@ -334,23 +426,53 @@ public final class HsumBootUserInitializerTest { when(mMockUms.getMainUserId()).thenReturn(userId); } private void mockGetUserIds(@UserIdInt int... userIds) { Log.d(TAG, "mockGetUserIds(): " + Arrays.toString(userIds)); private void mockGetUsers(UserInfo... users) { List<UserInfo> asList = new ArrayList<>(users.length); int[] userIds = new int[users.length]; for (int i = 0; i < users.length; i++) { var user = users[i]; asList.add(user); userIds[i] = user.id; } Log.d(TAG, "mockGetUsers(): returning " + asList + " for getUsers(), and " + Arrays.toString(userIds) + " to getUserIds()"); when(mMockUms.getUsers(/* excludingDying= */ true)).thenReturn(asList); when(mMockUms.getUserIds()).thenReturn(userIds); } private void mockPromoteToMainUser(@UserIdInt int userId) { Log.d(TAG, "mockPromoteToMainUser(): " + userId); when(mMockUms.setMainUser(userId)).thenReturn(true); } private void mockPromoteToMainUserFails(@UserIdInt int userId) { Log.d(TAG, "mockPromoteToMainUserFails(): " + userId); when(mMockUms.setMainUser(userId)).thenReturn(false); } private static UserInfo createUser(@UserIdInt int userId, @UserInfoFlag int flags) { return new UserInfo(userId, /* name= */ null, /* iconPath= */ null, flags, // Not using userType (for now) /* userType= */ "AB Positive"); } // NOTE: enums below must be public to be static imported public enum InitialUsers { SYSTEM_ONLY, SYSTEM_AND_MAIN, SYSTEM_AND_NON_MAIN SYSTEM_AND_ADMINS, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, // hacky case to mock failure SYSTEM_AND_REGULAR } public enum ExpectedResult { NO_USER_CREATED, MAIN_USER_CREATED, MAIN_USER_DEMOTED, FIRST_ADMIN_USER_PROMOTED_TO_MAIN, SECOND_ADMIN_USER_PROMOTED_TO_MAIN, ADMIN_USER_CREATED } } services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceMockedTest.java +138 −3 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_DEMOTE_MAIN_USER; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_PROMOTE_MAIN_USER; import static com.android.server.pm.UserManagerService.BOOT_TO_HSU_FOR_PROVISIONED_DEVICE; import static com.android.server.pm.UserManagerService.BOOT_TO_PREVIOUS_OR_FIRST_SWITCHABLE_USER; Loading Loading @@ -1515,6 +1516,113 @@ public final class UserManagerServiceMockedTest { assertDefaultSystemUserName(resolvedNameUsers); } @Test @EnableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser() { assumeDoesntHaveMainUser(); var adminUser = createAdminUser(); int userId = adminUser.id; // Make sure the new user is not the main user expect.withMessage("getMainUser() before").that(mUms.getMainUserId()).isNotEqualTo(userId); expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isTrue(); // Make sure it changed expect.withMessage("getMainUser() after").that(mUms.getMainUserId()).isEqualTo(userId); // assert journey logged expectUserJourneyLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @EnableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_hasMainUser() { var mainUserId = assumeHasMainUser(); var adminUser = createAdminUser(); int userId = adminUser.id; expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isFalse(); // Make sure it didn't change expect.withMessage("getMainUser()").that(mUms.getMainUserId()).isEqualTo(mainUserId); // assert journey not logged expectUserJourneyNotLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @EnableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_userNotFound() { assumeDoesntHaveMainUser(); int userId = 666; expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isFalse(); // Make sure it didn't change expect.withMessage("getMainUser()").that(mUms.getMainUserId()) .isEqualTo(UserHandle.USER_NULL); // assert journey not logged expectUserJourneyNotLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @EnableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_userNotAdmin() { assumeDoesntHaveMainUser(); var regularUser = createRegularUser(); int userId = regularUser.id; expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isFalse(); // Make sure it didn't change expect.withMessage("getMainUser()").that(mUms.getMainUserId()) .isEqualTo(UserHandle.USER_NULL); // assert journey not logged expectUserJourneyNotLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @DisableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_flagDisabled() { assumeDoesntHaveMainUser(); var adminUser = createAdminUser(); int userId = adminUser.id; // Make sure the new user is not the main user expect.withMessage("getMainUser() before").that(mUms.getMainUserId()).isNotEqualTo(userId); expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isFalse(); // Make sure it didn't change expect.withMessage("getMainUser() after").that(mUms.getMainUserId()) .isEqualTo(UserHandle.USER_NULL); // assert journey logged expectUserJourneyNotLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @DisableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_hasMainUser_flagDisabled() { // Should behave the same as when it's enabled (i.e. be a no-op) testSetMainUser_hasMainUser(); } @Test @DisableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_userNotFound_flagDisabled() { // Should behave the same as when it's enabled (i.e. be a no-op) testSetMainUser_userNotFound(); } @Test @DisableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_userNotAdmin_flagDisabled() { // Should behave the same as when it's enabled (i.e. be a no-op) testSetMainUser_userNotAdmin(); } /** * Returns true if the user's XML file has Default restrictions * @param userId Id of the user. Loading Loading @@ -1693,12 +1801,39 @@ public final class UserManagerServiceMockedTest { mainUserId == USER_SYSTEM); } @UserIdInt private int assumeHasMainUser() { var mainUserId = mUms.getMainUserId(); assumeFalse("main user exists (id=" + mainUserId + ")", mainUserId == UserHandle.USER_NULL); return mainUserId; } private void assumeDoesntHaveMainUser() { var mainUserId = mUms.getMainUserId(); assumeTrue("main user doesn't exsit", mainUserId == UserHandle.USER_NULL); } private UserInfo createMainUser() { UserInfo mainUser = mUms.createUserWithThrow("The Name is User, Main User", UserInfo user = mUms.createUserWithThrow("The Name is User, Main User", USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL | UserInfo.FLAG_MAIN); Log.d(TAG, "created main user: " + mainUser); return mainUser; Log.d(TAG, "created main user: " + user); return user; } private UserInfo createAdminUser() { UserInfo user = mUms.createUserWithThrow("The Name is Admin, Admin User", USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL); Log.d(TAG, "created admin user: " + user); return user; } private UserInfo createRegularUser() { UserInfo user = mUms.createUserWithThrow("The Name is Regular, Regular User", USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_FULL); Log.d(TAG, "created regular user: " + user); return user; } private UserInfo getSystemUser() { Loading Loading
services/core/java/com/android/server/pm/HsumBootUserInitializer.java +31 −1 Original line number Diff line number Diff line Loading @@ -200,7 +200,35 @@ public final class HsumBootUserInitializer { } return; } if (!promoteAdminUserToMainUserIfNeeded(t)) { createInitialUser(/* isMainUser= */ true); } } finally { t.traceEnd(); } } private boolean promoteAdminUserToMainUserIfNeeded(TimingsTraceAndSlog t) { t.traceBegin("promoteAdminUserToMainUserIfNeeded"); try { // TODO(b/419086491): use getUsers(Filter) var users = mUms.getUsers(/* excludeDying= */ true); int numberUsers = users.size(); for (int i = 0; i < numberUsers; i++) { var user = users.get(i); if (user.isFull() && user.isAdmin()) { Slogf.i(TAG, "Promoting admin user (%d) as main user", user.id); if (!mUms.setMainUser(user.id)) { Slogf.e(TAG, "Failed to promote admin user (%d) as main user", user.id); continue; } return true; } } if (DEBUG) { Slogf.d(TAG, "No existing admin user was promoted as main user (users=%s)", users); } return false; } finally { t.traceEnd(); } Loading @@ -223,9 +251,11 @@ public final class HsumBootUserInitializer { t.traceEnd(); } } private void createAdminUserIfNeeded(TimingsTraceAndSlog t) { t.traceBegin("createAdminUserIfNeeded"); try { // TODO(b/419086491): use getUsers(Filter) int[] userIds = mUms.getUserIds(); if (userIds != null && userIds.length > 1) { if (DEBUG) { Loading
services/core/java/com/android/server/pm/UserJourneyLogger.java +4 −1 Original line number Diff line number Diff line Loading @@ -106,6 +106,8 @@ public class UserJourneyLogger { FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__USER_LIFECYCLE; public static final int USER_JOURNEY_DEMOTE_MAIN_USER = FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__DEMOTE_MAIN_USER; public static final int USER_JOURNEY_PROMOTE_MAIN_USER = FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__PROMOTE_MAIN_USER; @IntDef(prefix = {"USER_JOURNEY"}, value = { USER_JOURNEY_UNKNOWN, Loading @@ -118,7 +120,8 @@ public class UserJourneyLogger { USER_JOURNEY_GRANT_ADMIN, USER_JOURNEY_REVOKE_ADMIN, USER_JOURNEY_USER_LIFECYCLE, USER_JOURNEY_DEMOTE_MAIN_USER USER_JOURNEY_DEMOTE_MAIN_USER, USER_JOURNEY_PROMOTE_MAIN_USER }) public @interface UserJourney { } Loading
services/core/java/com/android/server/pm/UserManagerService.java +48 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_ALREADY_AN import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_IS_NOT_AN_ADMIN; import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_INVALID_USER_TYPE; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_DEMOTE_MAIN_USER; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_PROMOTE_MAIN_USER; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_GRANT_ADMIN; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_REVOKE_ADMIN; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_USER_CREATE; Loading Loading @@ -8851,6 +8852,11 @@ public class UserManagerService extends IUserManager.Stub { return defaultValue; } /** * "Demotes" the main user to be just an admin. * * <p>Should be called only by {@link HsumBootUserInitializer} and unit tests */ boolean demoteMainUser() { if (!android.multiuser.Flags.demoteMainUser()) { Slog.d(LOG_TAG, "demoteMainUser(): ignoring because flag is disabled"); Loading @@ -8877,6 +8883,48 @@ public class UserManagerService extends IUserManager.Stub { } } /** * Sets the given user as the main user. * * <p>User must be an admin (and alive), and the current main user must be {@code null}. * * <p>Should be called only by {@link HsumBootUserInitializer} and unit tests * * @return whether it succeeded. */ boolean setMainUser(@UserIdInt int userId) { if (!android.multiuser.Flags.demoteMainUser()) { Slogf.d(LOG_TAG, "setMainUser(%d): ignoring because flag is disabled", userId); return false; } synchronized (mUsersLock) { var mainUser = getMainUserLU(); if (mainUser != null) { Slogf.e(LOG_TAG, "setMainUser(%d): already have a main user (%d)", userId, mainUser.id); return false; } var userData = getUserDataLU(userId); if (userData == null) { Slogf.e(LOG_TAG, "setMainUser(%d): user not found", userId); return false; } if (!userData.info.isAdmin()) { Slogf.e(LOG_TAG, "setMainUser(%d): user is not an admin", userId); return false; } Slogf.i(LOG_TAG, "Setting user %d as main user", userId); mUserJourneyLogger.logUserJourneyBegin(userId, USER_JOURNEY_PROMOTE_MAIN_USER); userData.info.flags |= UserInfo.FLAG_MAIN; writeUserLP(userData); return true; } } /** * Returns true if {@link com.android.internal.R.bool#config_canSwitchToHeadlessSystemUser} * is true. If allowed, headless system user can run in the foreground even though Loading
services/tests/mockingservicestests/src/com/android/server/pm/HsumBootUserInitializerTest.java +142 −20 Original line number Diff line number Diff line Loading @@ -18,13 +18,21 @@ package com.android.server.pm; import static android.multiuser.Flags.FLAG_CREATE_INITIAL_USER; import static android.os.UserHandle.USER_NULL; import static android.os.UserHandle.USER_SYSTEM; import static android.content.pm.UserInfo.FLAG_ADMIN; import static android.content.pm.UserInfo.FLAG_FULL; import static android.content.pm.UserInfo.FLAG_MAIN; import static android.content.pm.UserInfo.FLAG_SYSTEM; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.ADMIN_USER_CREATED; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.FIRST_ADMIN_USER_PROMOTED_TO_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.MAIN_USER_CREATED; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.MAIN_USER_DEMOTED; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.NO_USER_CREATED; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.SECOND_ADMIN_USER_PROMOTED_TO_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_NON_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_ADMINS; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_REGULAR; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_ONLY; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -62,8 +70,10 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; // NOTE: rename to HsumBootUserInitializerInitMethodTest if it needs to test other methods @RunWith(Parameterized.class) Loading @@ -72,10 +82,25 @@ public final class HsumBootUserInitializerTest { private static final String TAG = HsumBootUserInitializerTest.class.getSimpleName(); @UserIdInt private static final int NON_SYSTEM_USER_ID = 42; private static final int MAIN_USER_ID = 4; @UserIdInt private static final int ADMIN_USER_ID = 8; @UserIdInt private static final int ANOTHER_ADMIN_USER_ID = 15; @UserIdInt private static final int MAIN_USER_ID = 108; private static final int REGULAR_USER_ID = 16; // Pre-defined users. NOTE: only setting basic flags and not setting UserType. private final UserInfo mHeadlessSystemUser = createUser(USER_SYSTEM, FLAG_SYSTEM | FLAG_ADMIN); private final UserInfo mMainUser = createUser(MAIN_USER_ID, FLAG_FULL | FLAG_MAIN | FLAG_ADMIN); private final UserInfo mAdminUser = createUser(ADMIN_USER_ID, FLAG_FULL | FLAG_ADMIN); private final UserInfo mAnotherAdminUser = createUser(ANOTHER_ADMIN_USER_ID, FLAG_FULL | FLAG_ADMIN); private final UserInfo mRegularUser = createUser(REGULAR_USER_ID, FLAG_FULL); @Rule public final Expect expect = Expect.create(); Loading Loading @@ -112,19 +137,28 @@ public final class HsumBootUserInitializerTest { // shouldAlwaysHaveMainUser false, shouldCreateInitialUser false { false, false, SYSTEM_ONLY, NO_USER_CREATED }, { false, false, SYSTEM_AND_MAIN, MAIN_USER_DEMOTED }, { false, false, SYSTEM_AND_NON_MAIN, NO_USER_CREATED }, { false, false, SYSTEM_AND_ADMINS, NO_USER_CREATED }, { false, false, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, NO_USER_CREATED }, { false, false, SYSTEM_AND_REGULAR, NO_USER_CREATED }, // shouldAlwaysHaveMainUser false, shouldCreateInitialUser true { false, true, SYSTEM_ONLY, ADMIN_USER_CREATED}, { false, true, SYSTEM_AND_MAIN, MAIN_USER_DEMOTED }, { false, true, SYSTEM_AND_NON_MAIN, NO_USER_CREATED}, { false, true, SYSTEM_AND_ADMINS, NO_USER_CREATED }, { false, true, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, NO_USER_CREATED }, { false, true, SYSTEM_AND_REGULAR, NO_USER_CREATED }, // shouldAlwaysHaveMainUser true, shouldCreateInitialUser false { true, false, SYSTEM_ONLY, MAIN_USER_CREATED }, { true, false, SYSTEM_AND_MAIN, NO_USER_CREATED }, { true, false, SYSTEM_AND_NON_MAIN, MAIN_USER_CREATED}, { true, false, SYSTEM_AND_ADMINS, FIRST_ADMIN_USER_PROMOTED_TO_MAIN }, { true, false, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, SECOND_ADMIN_USER_PROMOTED_TO_MAIN }, { true, false, SYSTEM_AND_REGULAR, MAIN_USER_CREATED }, // shouldAlwaysHaveMainUser true, shouldCreateInitialUser true { true, true, SYSTEM_ONLY, MAIN_USER_CREATED }, { true, true, SYSTEM_AND_MAIN, NO_USER_CREATED }, { true, true, SYSTEM_AND_NON_MAIN, MAIN_USER_CREATED} { true, true, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, SECOND_ADMIN_USER_PROMOTED_TO_MAIN }, { true, true, SYSTEM_AND_REGULAR, MAIN_USER_CREATED } }); } Loading @@ -144,22 +178,36 @@ public final class HsumBootUserInitializerTest { public void setDefaultExpectations() throws Exception { switch (mInitialUsers) { case SYSTEM_ONLY: mockGetUserIds(USER_SYSTEM); mockGetUsers(mHeadlessSystemUser); mockGetMainUserId(USER_NULL); break; case SYSTEM_AND_MAIN: mockGetUserIds(USER_SYSTEM, MAIN_USER_ID); mockGetUsers(mHeadlessSystemUser, mMainUser); mockGetMainUserId(MAIN_USER_ID); break; case SYSTEM_AND_NON_MAIN: mockGetUserIds(USER_SYSTEM, NON_SYSTEM_USER_ID); case SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE: mockPromoteToMainUserFails(ADMIN_USER_ID); // fall through case SYSTEM_AND_ADMINS: mockGetUsers(mHeadlessSystemUser, mAdminUser, mAnotherAdminUser); mockGetMainUserId(USER_NULL); break; case SYSTEM_AND_REGULAR: mockGetUsers(mHeadlessSystemUser, mRegularUser); mockGetMainUserId(USER_NULL); break; } // NOTE: need to mock createNewUser() as the user id is used on Slog. switch (mExpectedResult) { case ADMIN_USER_CREATED: mockCreateNewUser(NON_SYSTEM_USER_ID); mockCreateNewUser(ADMIN_USER_ID); break; case FIRST_ADMIN_USER_PROMOTED_TO_MAIN: mockPromoteToMainUser(ADMIN_USER_ID); break; case SECOND_ADMIN_USER_PROMOTED_TO_MAIN: mockPromoteToMainUserFails(ADMIN_USER_ID); mockPromoteToMainUser(ANOTHER_ADMIN_USER_ID); break; case MAIN_USER_CREATED: mockCreateNewUser(MAIN_USER_ID); Loading Loading @@ -195,21 +243,36 @@ public final class HsumBootUserInitializerTest { switch (mExpectedResult) { case ADMIN_USER_CREATED: expectAdminUserCreated(); expectSetBootUserId(NON_SYSTEM_USER_ID); expectSetBootUserId(ADMIN_USER_ID); expectMainUserNotDemoted(); break; case FIRST_ADMIN_USER_PROMOTED_TO_MAIN: expectNoUserCreated(); expectSetBootUserIdNeverCalled(); expectAdminPromotedToMainUser(ADMIN_USER_ID); expectAdminNotPromotedToMainUser(ANOTHER_ADMIN_USER_ID); break; case SECOND_ADMIN_USER_PROMOTED_TO_MAIN: expectNoUserCreated(); expectSetBootUserIdNeverCalled(); // don't need to verify call to ADMIN_USER_ID - it was mocked to return false expectAdminPromotedToMainUser(ANOTHER_ADMIN_USER_ID); break; case MAIN_USER_CREATED: expectMainUserCreated(); expectSetBootUserId(MAIN_USER_ID); expectMainUserNotDemoted(); expectNoAdminPromotedToMainUser(); break; case NO_USER_CREATED: expectNoUserCreated(); expectMainUserNotDemoted(); expectNoAdminPromotedToMainUser(); break; case MAIN_USER_DEMOTED: expectNoUserCreated(); expectMainUserDemoted(); expectNoAdminPromotedToMainUser(); break; } } Loading Loading @@ -279,7 +342,6 @@ public final class HsumBootUserInitializerTest { expectSetBootUserIdNeverCalled(); } private void expectMainUserDemoted() { try { verify(mMockUms).demoteMainUser(); Loading @@ -300,6 +362,36 @@ public final class HsumBootUserInitializerTest { } } private void expectAdminPromotedToMainUser(@UserIdInt int userId) { try { verify(mMockUms).setMainUser(userId); } catch (Exception e) { String msg = "should have set main user as " + userId; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectAdminNotPromotedToMainUser(@UserIdInt int userId) { try { verify(mMockUms, never()).setMainUser(userId); } catch (Exception e) { String msg = "should have not set main user as " + userId; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectNoAdminPromotedToMainUser() { try { verify(mMockUms, never()).setMainUser(anyInt()); } catch (Exception e) { String msg = "should not have set main user"; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectSetBootUserId(@UserIdInt int userId) { try { verify(mMockUms).setBootUserIdUnchecked(userId); Loading Loading @@ -334,23 +426,53 @@ public final class HsumBootUserInitializerTest { when(mMockUms.getMainUserId()).thenReturn(userId); } private void mockGetUserIds(@UserIdInt int... userIds) { Log.d(TAG, "mockGetUserIds(): " + Arrays.toString(userIds)); private void mockGetUsers(UserInfo... users) { List<UserInfo> asList = new ArrayList<>(users.length); int[] userIds = new int[users.length]; for (int i = 0; i < users.length; i++) { var user = users[i]; asList.add(user); userIds[i] = user.id; } Log.d(TAG, "mockGetUsers(): returning " + asList + " for getUsers(), and " + Arrays.toString(userIds) + " to getUserIds()"); when(mMockUms.getUsers(/* excludingDying= */ true)).thenReturn(asList); when(mMockUms.getUserIds()).thenReturn(userIds); } private void mockPromoteToMainUser(@UserIdInt int userId) { Log.d(TAG, "mockPromoteToMainUser(): " + userId); when(mMockUms.setMainUser(userId)).thenReturn(true); } private void mockPromoteToMainUserFails(@UserIdInt int userId) { Log.d(TAG, "mockPromoteToMainUserFails(): " + userId); when(mMockUms.setMainUser(userId)).thenReturn(false); } private static UserInfo createUser(@UserIdInt int userId, @UserInfoFlag int flags) { return new UserInfo(userId, /* name= */ null, /* iconPath= */ null, flags, // Not using userType (for now) /* userType= */ "AB Positive"); } // NOTE: enums below must be public to be static imported public enum InitialUsers { SYSTEM_ONLY, SYSTEM_AND_MAIN, SYSTEM_AND_NON_MAIN SYSTEM_AND_ADMINS, SYSTEM_AND_ADMINS_FIRST_ADMIN_UNPROMOTABLE, // hacky case to mock failure SYSTEM_AND_REGULAR } public enum ExpectedResult { NO_USER_CREATED, MAIN_USER_CREATED, MAIN_USER_DEMOTED, FIRST_ADMIN_USER_PROMOTED_TO_MAIN, SECOND_ADMIN_USER_PROMOTED_TO_MAIN, ADMIN_USER_CREATED } }
services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceMockedTest.java +138 −3 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_DEMOTE_MAIN_USER; import static com.android.server.pm.UserJourneyLogger.USER_JOURNEY_PROMOTE_MAIN_USER; import static com.android.server.pm.UserManagerService.BOOT_TO_HSU_FOR_PROVISIONED_DEVICE; import static com.android.server.pm.UserManagerService.BOOT_TO_PREVIOUS_OR_FIRST_SWITCHABLE_USER; Loading Loading @@ -1515,6 +1516,113 @@ public final class UserManagerServiceMockedTest { assertDefaultSystemUserName(resolvedNameUsers); } @Test @EnableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser() { assumeDoesntHaveMainUser(); var adminUser = createAdminUser(); int userId = adminUser.id; // Make sure the new user is not the main user expect.withMessage("getMainUser() before").that(mUms.getMainUserId()).isNotEqualTo(userId); expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isTrue(); // Make sure it changed expect.withMessage("getMainUser() after").that(mUms.getMainUserId()).isEqualTo(userId); // assert journey logged expectUserJourneyLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @EnableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_hasMainUser() { var mainUserId = assumeHasMainUser(); var adminUser = createAdminUser(); int userId = adminUser.id; expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isFalse(); // Make sure it didn't change expect.withMessage("getMainUser()").that(mUms.getMainUserId()).isEqualTo(mainUserId); // assert journey not logged expectUserJourneyNotLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @EnableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_userNotFound() { assumeDoesntHaveMainUser(); int userId = 666; expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isFalse(); // Make sure it didn't change expect.withMessage("getMainUser()").that(mUms.getMainUserId()) .isEqualTo(UserHandle.USER_NULL); // assert journey not logged expectUserJourneyNotLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @EnableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_userNotAdmin() { assumeDoesntHaveMainUser(); var regularUser = createRegularUser(); int userId = regularUser.id; expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isFalse(); // Make sure it didn't change expect.withMessage("getMainUser()").that(mUms.getMainUserId()) .isEqualTo(UserHandle.USER_NULL); // assert journey not logged expectUserJourneyNotLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @DisableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_flagDisabled() { assumeDoesntHaveMainUser(); var adminUser = createAdminUser(); int userId = adminUser.id; // Make sure the new user is not the main user expect.withMessage("getMainUser() before").that(mUms.getMainUserId()).isNotEqualTo(userId); expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isFalse(); // Make sure it didn't change expect.withMessage("getMainUser() after").that(mUms.getMainUserId()) .isEqualTo(UserHandle.USER_NULL); // assert journey logged expectUserJourneyNotLogged(userId, USER_JOURNEY_PROMOTE_MAIN_USER); } @Test @DisableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_hasMainUser_flagDisabled() { // Should behave the same as when it's enabled (i.e. be a no-op) testSetMainUser_hasMainUser(); } @Test @DisableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_userNotFound_flagDisabled() { // Should behave the same as when it's enabled (i.e. be a no-op) testSetMainUser_userNotFound(); } @Test @DisableFlags(FLAG_DEMOTE_MAIN_USER) public void testSetMainUser_userNotAdmin_flagDisabled() { // Should behave the same as when it's enabled (i.e. be a no-op) testSetMainUser_userNotAdmin(); } /** * Returns true if the user's XML file has Default restrictions * @param userId Id of the user. Loading Loading @@ -1693,12 +1801,39 @@ public final class UserManagerServiceMockedTest { mainUserId == USER_SYSTEM); } @UserIdInt private int assumeHasMainUser() { var mainUserId = mUms.getMainUserId(); assumeFalse("main user exists (id=" + mainUserId + ")", mainUserId == UserHandle.USER_NULL); return mainUserId; } private void assumeDoesntHaveMainUser() { var mainUserId = mUms.getMainUserId(); assumeTrue("main user doesn't exsit", mainUserId == UserHandle.USER_NULL); } private UserInfo createMainUser() { UserInfo mainUser = mUms.createUserWithThrow("The Name is User, Main User", UserInfo user = mUms.createUserWithThrow("The Name is User, Main User", USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL | UserInfo.FLAG_MAIN); Log.d(TAG, "created main user: " + mainUser); return mainUser; Log.d(TAG, "created main user: " + user); return user; } private UserInfo createAdminUser() { UserInfo user = mUms.createUserWithThrow("The Name is Admin, Admin User", USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_ADMIN | UserInfo.FLAG_FULL); Log.d(TAG, "created admin user: " + user); return user; } private UserInfo createRegularUser() { UserInfo user = mUms.createUserWithThrow("The Name is Regular, Regular User", USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_FULL); Log.d(TAG, "created regular user: " + user); return user; } private UserInfo getSystemUser() { Loading