Loading core/java/android/content/pm/multiuser.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -507,6 +507,13 @@ flag { bug: "409650316" } flag { name: "demote_main_user" namespace: "multiuser" description: "Remove the FLAG_MAIN on boot when the device doesn't support Main User anymore" bug: "402486365" } flag { name: "setupwizard_username_population" namespace: "multiuser" Loading services/core/java/com/android/server/pm/HsumBootUserInitializer.java +37 −13 Original line number Diff line number Diff line Loading @@ -69,8 +69,8 @@ public final class HsumBootUserInitializer { } }; /** Whether this device should always have a non-removable MainUser, including at first boot. */ private final boolean mShouldAlwaysHaveMainUser; /** Whether it should create a main user on first boot. */ private final boolean mShouldCreateMainUser; /** Whether it should create an initial user, but without setting it as the main user. */ private final boolean mShouldCreateInitialUser; Loading @@ -90,12 +90,12 @@ public final class HsumBootUserInitializer { @VisibleForTesting HsumBootUserInitializer(UserManagerService ums, ActivityManagerService ams, PackageManagerService pms, ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser, boolean shouldCreateInitialUser) { boolean shouldCreateMainUser, boolean shouldCreateInitialUser) { mUms = ums; mAms = ams; mPms = pms; mContentResolver = contentResolver; mShouldAlwaysHaveMainUser = shouldAlwaysHaveMainUser; mShouldCreateMainUser = shouldCreateMainUser; mShouldCreateInitialUser = shouldCreateInitialUser; } Loading @@ -105,7 +105,7 @@ public final class HsumBootUserInitializer { Slogf.d(TAG, "preCreateInitialUserFlagInit())"); } if (mShouldAlwaysHaveMainUser) { if (mShouldCreateMainUser) { t.traceBegin("createMainUserIfNeeded"); preCreateInitialUserCreateMainUserIfNeeded(); t.traceEnd(); Loading @@ -129,7 +129,7 @@ public final class HsumBootUserInitializer { UserManager.USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN, /* parentId= */ UserHandle.USER_NULL, /* preCreated= */ false, /* preCreate= */ false, /* disallowedPackages= */ null, /* token= */ null); if (newInitialUser != null) { Loading @@ -153,9 +153,9 @@ public final class HsumBootUserInitializer { */ public void init(TimingsTraceAndSlog t) { if (DEBUG) { Slogf.d(TAG, "init(): shouldAlwaysHaveMainUser=%b, shouldCreateInitialUser=%b, " Slogf.d(TAG, "init(): shouldCreateMainUser=%b, shouldCreateInitialUser=%b, " + "Flags.createInitialUser=%b", mShouldAlwaysHaveMainUser, mShouldCreateInitialUser, Flags.createInitialUser()); mShouldCreateMainUser, mShouldCreateInitialUser, Flags.createInitialUser()); } else { Slogf.i(TAG, "Initializing"); } Loading @@ -165,11 +165,19 @@ public final class HsumBootUserInitializer { return; } if (mShouldAlwaysHaveMainUser) { createMainUserIfNeeded(t); t.traceBegin("getMainUserId"); int mainUserId = mUms.getMainUserId(); t.traceEnd(); if (mShouldCreateMainUser) { createMainUserIfNeeded(t, mainUserId); return; } t.traceBegin("demoteMainUserIfNeeded"); demoteMainUserIfNeeded(t, mainUserId); t.traceEnd(); if (mShouldCreateInitialUser) { createAdminUserIfNeeded(t); return; Loading @@ -179,11 +187,10 @@ public final class HsumBootUserInitializer { } } private void createMainUserIfNeeded(TimingsTraceAndSlog t) { private void createMainUserIfNeeded(TimingsTraceAndSlog t, @UserIdInt int mainUserId) { // Always tracing as it used to be done by the caller t.traceBegin("createMainUserIfNeeded"); try { int mainUserId = mUms.getMainUserId(); if (mainUserId != UserHandle.USER_NULL) { if (DEBUG) { Slogf.d(TAG, "createMainUserIfNeeded(): found MainUser (userId=%d)", Loading @@ -197,6 +204,23 @@ public final class HsumBootUserInitializer { } } private void demoteMainUserIfNeeded(TimingsTraceAndSlog t, @UserIdInt int mainUserId) { if (mainUserId == UserHandle.USER_NULL) { if (DEBUG) { Slogf.d(TAG, "demoteMainUserIfNeeded(): didn't find MainUser"); } return; } t.traceBegin("demoteMainUserIfNeeded"); try { Slogf.i(TAG, "Demoting main user (%d)", mainUserId); if (!mUms.demoteMainUser()) { Slogf.wtf(TAG, "Failed to demote main user"); } } finally { t.traceEnd(); } } private void createAdminUserIfNeeded(TimingsTraceAndSlog t) { t.traceBegin("createAdminUserIfNeeded"); try { Loading Loading @@ -230,7 +254,7 @@ public final class HsumBootUserInitializer { UserManager.USER_TYPE_FULL_SECONDARY, flags, /* parentId= */ UserHandle.USER_NULL, /* preCreated= */ false, /* preCreate= */ false, /* disallowedPackages= */ null, /* token= */ null); Slogf.i(TAG, "Successfully created %s, userId=%d", logName, newInitialUser.id); Loading services/core/java/com/android/server/pm/UserJourneyLogger.java +4 −1 Original line number Diff line number Diff line Loading @@ -104,6 +104,8 @@ public class UserJourneyLogger { FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN; public static final int USER_JOURNEY_USER_LIFECYCLE = 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; @IntDef(prefix = {"USER_JOURNEY"}, value = { USER_JOURNEY_UNKNOWN, Loading @@ -115,7 +117,8 @@ public class UserJourneyLogger { USER_JOURNEY_USER_REMOVE, USER_JOURNEY_GRANT_ADMIN, USER_JOURNEY_REVOKE_ADMIN, USER_JOURNEY_USER_LIFECYCLE USER_JOURNEY_USER_LIFECYCLE, USER_JOURNEY_DEMOTE_MAIN_USER }) public @interface UserJourney { } Loading services/core/java/com/android/server/pm/UserManagerService.java +57 −17 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_UNSPECIFIED; import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_ALREADY_AN_ADMIN; 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_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 @@ -587,7 +588,7 @@ public class UserManagerService extends IUserManager.Stub { @GuardedBy("mUserLifecycleListeners") private final ArrayList<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>(); private final UserJourneyLogger mUserJourneyLogger = new UserJourneyLogger(); private final UserJourneyLogger mUserJourneyLogger; private final LockPatternUtils mLockPatternUtils; Loading Loading @@ -1065,7 +1066,7 @@ public class UserManagerService extends IUserManager.Stub { // TODO(b/28848102) Add support for test dependencies injection @VisibleForTesting UserManagerService(Context context) { this(context, /* pm= */ null, /* userDataPreparer= */ null, this(context, /* pm= */ null, /* userDataPreparer= */ null, new UserJourneyLogger(), /* packagesLock= */ new Object(), context.getCacheDir(), /* users= */ null); } Loading @@ -1076,16 +1077,17 @@ public class UserManagerService extends IUserManager.Stub { */ UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer, Object packagesLock) { this(context, pm, userDataPreparer, packagesLock, Environment.getDataDirectory(), /* users= */ null); this(context, pm, userDataPreparer, new UserJourneyLogger(), packagesLock, Environment.getDataDirectory(), /* users= */ null); } @VisibleForTesting UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer, Object packagesLock, File dataDir, UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer, UserJourneyLogger userJourneyLogger, Object packagesLock, File dataDir, SparseArray<UserData> users) { mContext = context; mPm = pm; mUserJourneyLogger = userJourneyLogger; mPackagesLock = packagesLock; mUsers = users != null ? users : new SparseArray<>(); mHandler = new MainHandler(); Loading Loading @@ -1358,17 +1360,24 @@ public class UserManagerService extends IUserManager.Stub { private @CanBeNULL @UserIdInt int getMainUserIdUnchecked() { synchronized (mUsersLock) { final int userSize = mUsers.size(); var mainUser = getMainUserLU(); return mainUser == null ? UserHandle.USER_NULL : mainUser.id; } } @GuardedBy("mUsersLock") private @Nullable UserInfo getMainUserLU() { int userSize = mUsers.size(); for (int i = 0; i < userSize; i++) { final UserInfo user = mUsers.valueAt(i).info; UserInfo user = mUsers.valueAt(i).info; if (user.isMain() && !mRemovingUserIds.get(user.id)) { return user.id; } return user; } } return UserHandle.USER_NULL; return null; } private @CanBeNULL @UserIdInt int getPrivateProfileUserId() { synchronized (mUsersLock) { for (int userId : getUserIds()) { Loading Loading @@ -5347,6 +5356,7 @@ public class UserManagerService extends IUserManager.Stub { initDefaultGuestRestrictions(); Slogf.i(LOG_TAG, "Creating system user: %s", userData); writeUserLP(userData); writeUserListLP(); } Loading Loading @@ -6155,11 +6165,15 @@ public class UserManagerService extends IUserManager.Stub { USER_OPERATION_ERROR_UNKNOWN); } } if (isMainUser && getMainUserIdUnchecked() != UserHandle.USER_NULL) { if (isMainUser) { int mainUserId = getMainUserIdUnchecked(); if (mainUserId != UserHandle.USER_NULL) { throwCheckedUserOperationException( "Cannot add user with FLAG_MAIN as main user already exists.", "Cannot add user with FLAG_MAIN as main user already exists (id=" + mainUserId + ").", UserManager.USER_OPERATION_ERROR_MAX_USERS); } } if (!canAddMoreUsersOfType(userTypeDetails)) { if (isUserLimitReachedForLogging()) { throwCheckedUserOperationException( Loading Loading @@ -8826,6 +8840,32 @@ public class UserManagerService extends IUserManager.Stub { return defaultValue; } boolean demoteMainUser() { if (!android.multiuser.Flags.demoteMainUser()) { Slog.d(LOG_TAG, "demoteMainUser(): ignoring because flag is disabled"); return false; } synchronized (mUsersLock) { var mainUser = getMainUserLU(); if (mainUser == null) { Slog.e(LOG_TAG, "demoteMainUser(): no main user"); return false; } if (mainUser.id == UserHandle.USER_SYSTEM) { Slog.e(LOG_TAG, "demoteMainUser(): cannot demote system user"); return false; } Slogf.i(LOG_TAG, "Demoting main user (%s)", mainUser); mUserJourneyLogger.logUserJourneyBegin(mainUser.id, USER_JOURNEY_DEMOTE_MAIN_USER); var userData = getUserDataLU(mainUser.id); 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 +37 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.os.UserHandle.USER_SYSTEM; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.ADMIN_USER_CREATED; 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.InitialUsers.SYSTEM_AND_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_NON_MAIN; Loading Loading @@ -110,11 +111,11 @@ public final class HsumBootUserInitializerTest { return Arrays.asList(new Object[][] { // shouldAlwaysHaveMainUser false, shouldCreateInitialUser false { false, false, SYSTEM_ONLY, NO_USER_CREATED }, { false, false, SYSTEM_AND_MAIN, NO_USER_CREATED }, { false, false, SYSTEM_AND_MAIN, MAIN_USER_DEMOTED }, { false, false, SYSTEM_AND_NON_MAIN, NO_USER_CREATED }, // shouldAlwaysHaveMainUser false, shouldCreateInitialUser true { false, true, SYSTEM_ONLY, ADMIN_USER_CREATED}, { false, true, SYSTEM_AND_MAIN, NO_USER_CREATED }, { false, true, SYSTEM_AND_MAIN, MAIN_USER_DEMOTED }, { false, true, SYSTEM_AND_NON_MAIN, NO_USER_CREATED}, // shouldAlwaysHaveMainUser true, shouldCreateInitialUser false { true, false, SYSTEM_ONLY, MAIN_USER_CREATED}, Loading Loading @@ -163,6 +164,9 @@ public final class HsumBootUserInitializerTest { case MAIN_USER_CREATED: mockCreateNewUser(MAIN_USER_ID); break; case MAIN_USER_DEMOTED: mockGetMainUserId(MAIN_USER_ID); break; default: // don't need to mock it } Loading Loading @@ -192,13 +196,20 @@ public final class HsumBootUserInitializerTest { case ADMIN_USER_CREATED: expectAdminUserCreated(); expectSetBootUserId(NON_SYSTEM_USER_ID); expectMainUserNotDemoted(); break; case MAIN_USER_CREATED: expectMainUserCreated(); expectSetBootUserId(MAIN_USER_ID); expectMainUserNotDemoted(); break; case NO_USER_CREATED: expectNoUserCreated(); expectMainUserNotDemoted(); break; case MAIN_USER_DEMOTED: expectNoUserCreated(); expectMainUserDemoted(); break; } } Loading @@ -216,12 +227,14 @@ public final class HsumBootUserInitializerTest { // When the flag is disabled, it shouldn't trigger the "create admin user" workflow case ADMIN_USER_CREATED: case NO_USER_CREATED: case MAIN_USER_DEMOTED: expectNoUserCreated(); break; case MAIN_USER_CREATED: expectMainUserCreated(); break; } expectMainUserNotDemoted(); } private HsumBootUserInitializer createHsumBootUserInitializer( Loading Loading @@ -266,6 +279,27 @@ public final class HsumBootUserInitializerTest { expectSetBootUserIdNeverCalled(); } private void expectMainUserDemoted() { try { verify(mMockUms).demoteMainUser(); } catch (Exception e) { String msg = "should have demoted main user"; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectMainUserNotDemoted() { try { verify(mMockUms, never()).demoteMainUser(); } catch (Exception e) { String msg = "should not have demoted main user"; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectSetBootUserId(@UserIdInt int userId) { try { verify(mMockUms).setBootUserIdUnchecked(userId); Loading Loading @@ -316,6 +350,7 @@ public final class HsumBootUserInitializerTest { public enum ExpectedResult { NO_USER_CREATED, MAIN_USER_CREATED, MAIN_USER_DEMOTED, ADMIN_USER_CREATED } } Loading
core/java/android/content/pm/multiuser.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -507,6 +507,13 @@ flag { bug: "409650316" } flag { name: "demote_main_user" namespace: "multiuser" description: "Remove the FLAG_MAIN on boot when the device doesn't support Main User anymore" bug: "402486365" } flag { name: "setupwizard_username_population" namespace: "multiuser" Loading
services/core/java/com/android/server/pm/HsumBootUserInitializer.java +37 −13 Original line number Diff line number Diff line Loading @@ -69,8 +69,8 @@ public final class HsumBootUserInitializer { } }; /** Whether this device should always have a non-removable MainUser, including at first boot. */ private final boolean mShouldAlwaysHaveMainUser; /** Whether it should create a main user on first boot. */ private final boolean mShouldCreateMainUser; /** Whether it should create an initial user, but without setting it as the main user. */ private final boolean mShouldCreateInitialUser; Loading @@ -90,12 +90,12 @@ public final class HsumBootUserInitializer { @VisibleForTesting HsumBootUserInitializer(UserManagerService ums, ActivityManagerService ams, PackageManagerService pms, ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser, boolean shouldCreateInitialUser) { boolean shouldCreateMainUser, boolean shouldCreateInitialUser) { mUms = ums; mAms = ams; mPms = pms; mContentResolver = contentResolver; mShouldAlwaysHaveMainUser = shouldAlwaysHaveMainUser; mShouldCreateMainUser = shouldCreateMainUser; mShouldCreateInitialUser = shouldCreateInitialUser; } Loading @@ -105,7 +105,7 @@ public final class HsumBootUserInitializer { Slogf.d(TAG, "preCreateInitialUserFlagInit())"); } if (mShouldAlwaysHaveMainUser) { if (mShouldCreateMainUser) { t.traceBegin("createMainUserIfNeeded"); preCreateInitialUserCreateMainUserIfNeeded(); t.traceEnd(); Loading @@ -129,7 +129,7 @@ public final class HsumBootUserInitializer { UserManager.USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN, /* parentId= */ UserHandle.USER_NULL, /* preCreated= */ false, /* preCreate= */ false, /* disallowedPackages= */ null, /* token= */ null); if (newInitialUser != null) { Loading @@ -153,9 +153,9 @@ public final class HsumBootUserInitializer { */ public void init(TimingsTraceAndSlog t) { if (DEBUG) { Slogf.d(TAG, "init(): shouldAlwaysHaveMainUser=%b, shouldCreateInitialUser=%b, " Slogf.d(TAG, "init(): shouldCreateMainUser=%b, shouldCreateInitialUser=%b, " + "Flags.createInitialUser=%b", mShouldAlwaysHaveMainUser, mShouldCreateInitialUser, Flags.createInitialUser()); mShouldCreateMainUser, mShouldCreateInitialUser, Flags.createInitialUser()); } else { Slogf.i(TAG, "Initializing"); } Loading @@ -165,11 +165,19 @@ public final class HsumBootUserInitializer { return; } if (mShouldAlwaysHaveMainUser) { createMainUserIfNeeded(t); t.traceBegin("getMainUserId"); int mainUserId = mUms.getMainUserId(); t.traceEnd(); if (mShouldCreateMainUser) { createMainUserIfNeeded(t, mainUserId); return; } t.traceBegin("demoteMainUserIfNeeded"); demoteMainUserIfNeeded(t, mainUserId); t.traceEnd(); if (mShouldCreateInitialUser) { createAdminUserIfNeeded(t); return; Loading @@ -179,11 +187,10 @@ public final class HsumBootUserInitializer { } } private void createMainUserIfNeeded(TimingsTraceAndSlog t) { private void createMainUserIfNeeded(TimingsTraceAndSlog t, @UserIdInt int mainUserId) { // Always tracing as it used to be done by the caller t.traceBegin("createMainUserIfNeeded"); try { int mainUserId = mUms.getMainUserId(); if (mainUserId != UserHandle.USER_NULL) { if (DEBUG) { Slogf.d(TAG, "createMainUserIfNeeded(): found MainUser (userId=%d)", Loading @@ -197,6 +204,23 @@ public final class HsumBootUserInitializer { } } private void demoteMainUserIfNeeded(TimingsTraceAndSlog t, @UserIdInt int mainUserId) { if (mainUserId == UserHandle.USER_NULL) { if (DEBUG) { Slogf.d(TAG, "demoteMainUserIfNeeded(): didn't find MainUser"); } return; } t.traceBegin("demoteMainUserIfNeeded"); try { Slogf.i(TAG, "Demoting main user (%d)", mainUserId); if (!mUms.demoteMainUser()) { Slogf.wtf(TAG, "Failed to demote main user"); } } finally { t.traceEnd(); } } private void createAdminUserIfNeeded(TimingsTraceAndSlog t) { t.traceBegin("createAdminUserIfNeeded"); try { Loading Loading @@ -230,7 +254,7 @@ public final class HsumBootUserInitializer { UserManager.USER_TYPE_FULL_SECONDARY, flags, /* parentId= */ UserHandle.USER_NULL, /* preCreated= */ false, /* preCreate= */ false, /* disallowedPackages= */ null, /* token= */ null); Slogf.i(TAG, "Successfully created %s, userId=%d", logName, newInitialUser.id); Loading
services/core/java/com/android/server/pm/UserJourneyLogger.java +4 −1 Original line number Diff line number Diff line Loading @@ -104,6 +104,8 @@ public class UserJourneyLogger { FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__JOURNEY__REVOKE_ADMIN; public static final int USER_JOURNEY_USER_LIFECYCLE = 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; @IntDef(prefix = {"USER_JOURNEY"}, value = { USER_JOURNEY_UNKNOWN, Loading @@ -115,7 +117,8 @@ public class UserJourneyLogger { USER_JOURNEY_USER_REMOVE, USER_JOURNEY_GRANT_ADMIN, USER_JOURNEY_REVOKE_ADMIN, USER_JOURNEY_USER_LIFECYCLE USER_JOURNEY_USER_LIFECYCLE, USER_JOURNEY_DEMOTE_MAIN_USER }) public @interface UserJourney { } Loading
services/core/java/com/android/server/pm/UserManagerService.java +57 −17 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_UNSPECIFIED; import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_ALREADY_AN_ADMIN; 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_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 @@ -587,7 +588,7 @@ public class UserManagerService extends IUserManager.Stub { @GuardedBy("mUserLifecycleListeners") private final ArrayList<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>(); private final UserJourneyLogger mUserJourneyLogger = new UserJourneyLogger(); private final UserJourneyLogger mUserJourneyLogger; private final LockPatternUtils mLockPatternUtils; Loading Loading @@ -1065,7 +1066,7 @@ public class UserManagerService extends IUserManager.Stub { // TODO(b/28848102) Add support for test dependencies injection @VisibleForTesting UserManagerService(Context context) { this(context, /* pm= */ null, /* userDataPreparer= */ null, this(context, /* pm= */ null, /* userDataPreparer= */ null, new UserJourneyLogger(), /* packagesLock= */ new Object(), context.getCacheDir(), /* users= */ null); } Loading @@ -1076,16 +1077,17 @@ public class UserManagerService extends IUserManager.Stub { */ UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer, Object packagesLock) { this(context, pm, userDataPreparer, packagesLock, Environment.getDataDirectory(), /* users= */ null); this(context, pm, userDataPreparer, new UserJourneyLogger(), packagesLock, Environment.getDataDirectory(), /* users= */ null); } @VisibleForTesting UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer, Object packagesLock, File dataDir, UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer, UserJourneyLogger userJourneyLogger, Object packagesLock, File dataDir, SparseArray<UserData> users) { mContext = context; mPm = pm; mUserJourneyLogger = userJourneyLogger; mPackagesLock = packagesLock; mUsers = users != null ? users : new SparseArray<>(); mHandler = new MainHandler(); Loading Loading @@ -1358,17 +1360,24 @@ public class UserManagerService extends IUserManager.Stub { private @CanBeNULL @UserIdInt int getMainUserIdUnchecked() { synchronized (mUsersLock) { final int userSize = mUsers.size(); var mainUser = getMainUserLU(); return mainUser == null ? UserHandle.USER_NULL : mainUser.id; } } @GuardedBy("mUsersLock") private @Nullable UserInfo getMainUserLU() { int userSize = mUsers.size(); for (int i = 0; i < userSize; i++) { final UserInfo user = mUsers.valueAt(i).info; UserInfo user = mUsers.valueAt(i).info; if (user.isMain() && !mRemovingUserIds.get(user.id)) { return user.id; } return user; } } return UserHandle.USER_NULL; return null; } private @CanBeNULL @UserIdInt int getPrivateProfileUserId() { synchronized (mUsersLock) { for (int userId : getUserIds()) { Loading Loading @@ -5347,6 +5356,7 @@ public class UserManagerService extends IUserManager.Stub { initDefaultGuestRestrictions(); Slogf.i(LOG_TAG, "Creating system user: %s", userData); writeUserLP(userData); writeUserListLP(); } Loading Loading @@ -6155,11 +6165,15 @@ public class UserManagerService extends IUserManager.Stub { USER_OPERATION_ERROR_UNKNOWN); } } if (isMainUser && getMainUserIdUnchecked() != UserHandle.USER_NULL) { if (isMainUser) { int mainUserId = getMainUserIdUnchecked(); if (mainUserId != UserHandle.USER_NULL) { throwCheckedUserOperationException( "Cannot add user with FLAG_MAIN as main user already exists.", "Cannot add user with FLAG_MAIN as main user already exists (id=" + mainUserId + ").", UserManager.USER_OPERATION_ERROR_MAX_USERS); } } if (!canAddMoreUsersOfType(userTypeDetails)) { if (isUserLimitReachedForLogging()) { throwCheckedUserOperationException( Loading Loading @@ -8826,6 +8840,32 @@ public class UserManagerService extends IUserManager.Stub { return defaultValue; } boolean demoteMainUser() { if (!android.multiuser.Flags.demoteMainUser()) { Slog.d(LOG_TAG, "demoteMainUser(): ignoring because flag is disabled"); return false; } synchronized (mUsersLock) { var mainUser = getMainUserLU(); if (mainUser == null) { Slog.e(LOG_TAG, "demoteMainUser(): no main user"); return false; } if (mainUser.id == UserHandle.USER_SYSTEM) { Slog.e(LOG_TAG, "demoteMainUser(): cannot demote system user"); return false; } Slogf.i(LOG_TAG, "Demoting main user (%s)", mainUser); mUserJourneyLogger.logUserJourneyBegin(mainUser.id, USER_JOURNEY_DEMOTE_MAIN_USER); var userData = getUserDataLU(mainUser.id); 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 +37 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.os.UserHandle.USER_SYSTEM; import static com.android.server.pm.HsumBootUserInitializerTest.ExpectedResult.ADMIN_USER_CREATED; 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.InitialUsers.SYSTEM_AND_MAIN; import static com.android.server.pm.HsumBootUserInitializerTest.InitialUsers.SYSTEM_AND_NON_MAIN; Loading Loading @@ -110,11 +111,11 @@ public final class HsumBootUserInitializerTest { return Arrays.asList(new Object[][] { // shouldAlwaysHaveMainUser false, shouldCreateInitialUser false { false, false, SYSTEM_ONLY, NO_USER_CREATED }, { false, false, SYSTEM_AND_MAIN, NO_USER_CREATED }, { false, false, SYSTEM_AND_MAIN, MAIN_USER_DEMOTED }, { false, false, SYSTEM_AND_NON_MAIN, NO_USER_CREATED }, // shouldAlwaysHaveMainUser false, shouldCreateInitialUser true { false, true, SYSTEM_ONLY, ADMIN_USER_CREATED}, { false, true, SYSTEM_AND_MAIN, NO_USER_CREATED }, { false, true, SYSTEM_AND_MAIN, MAIN_USER_DEMOTED }, { false, true, SYSTEM_AND_NON_MAIN, NO_USER_CREATED}, // shouldAlwaysHaveMainUser true, shouldCreateInitialUser false { true, false, SYSTEM_ONLY, MAIN_USER_CREATED}, Loading Loading @@ -163,6 +164,9 @@ public final class HsumBootUserInitializerTest { case MAIN_USER_CREATED: mockCreateNewUser(MAIN_USER_ID); break; case MAIN_USER_DEMOTED: mockGetMainUserId(MAIN_USER_ID); break; default: // don't need to mock it } Loading Loading @@ -192,13 +196,20 @@ public final class HsumBootUserInitializerTest { case ADMIN_USER_CREATED: expectAdminUserCreated(); expectSetBootUserId(NON_SYSTEM_USER_ID); expectMainUserNotDemoted(); break; case MAIN_USER_CREATED: expectMainUserCreated(); expectSetBootUserId(MAIN_USER_ID); expectMainUserNotDemoted(); break; case NO_USER_CREATED: expectNoUserCreated(); expectMainUserNotDemoted(); break; case MAIN_USER_DEMOTED: expectNoUserCreated(); expectMainUserDemoted(); break; } } Loading @@ -216,12 +227,14 @@ public final class HsumBootUserInitializerTest { // When the flag is disabled, it shouldn't trigger the "create admin user" workflow case ADMIN_USER_CREATED: case NO_USER_CREATED: case MAIN_USER_DEMOTED: expectNoUserCreated(); break; case MAIN_USER_CREATED: expectMainUserCreated(); break; } expectMainUserNotDemoted(); } private HsumBootUserInitializer createHsumBootUserInitializer( Loading Loading @@ -266,6 +279,27 @@ public final class HsumBootUserInitializerTest { expectSetBootUserIdNeverCalled(); } private void expectMainUserDemoted() { try { verify(mMockUms).demoteMainUser(); } catch (Exception e) { String msg = "should have demoted main user"; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectMainUserNotDemoted() { try { verify(mMockUms, never()).demoteMainUser(); } catch (Exception e) { String msg = "should not have demoted main user"; Log.e(TAG, msg, e); expect.withMessage(msg).fail(); } } private void expectSetBootUserId(@UserIdInt int userId) { try { verify(mMockUms).setBootUserIdUnchecked(userId); Loading Loading @@ -316,6 +350,7 @@ public final class HsumBootUserInitializerTest { public enum ExpectedResult { NO_USER_CREATED, MAIN_USER_CREATED, MAIN_USER_DEMOTED, ADMIN_USER_CREATED } }