Loading services/core/java/com/android/server/pm/UserManagerInternal.java +6 −5 Original line number Diff line number Diff line Loading @@ -553,11 +553,12 @@ public abstract class UserManagerInternal { * switched to. * * <p>Otherwise, in {@link UserManager#isHeadlessSystemUserMode() headless system user mode}, * this will be the user who was last in the foreground on this device. If there is no * switchable user on the device, a new user will be created and its id will be returned. * this will be the user who was last in the foreground on this device. * * <p>In non-headless system user mode, the return value will be {@link UserHandle#USER_SYSTEM}. * <p>In non-headless system user mode, the return value will be * {@link android.os.UserHandle#USER_SYSTEM}. * @throws UserManager.CheckedUserOperationException if no switchable user can be found */ public abstract @UserIdInt int getBootUser() throws UserManager.CheckedUserOperationException; public abstract @UserIdInt int getBootUser() throws UserManager.CheckedUserOperationException; } services/core/java/com/android/server/pm/UserManagerService.java +7 −23 Original line number Diff line number Diff line Loading @@ -5049,6 +5049,8 @@ public class UserManagerService extends IUserManager.Stub { //...then external ones Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); addedIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); // In HSUM, MainUser might be created before PHASE_ACTIVITY_MANAGER_READY has been sent. addedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id); // Also, add the UserHandle for mainline modules which can't use the @hide // EXTRA_USER_HANDLE. Loading Loading @@ -6758,18 +6760,6 @@ public class UserManagerService extends IUserManager.Stub { return mLocalService.isUserInitialized(userId); } /** * Creates a new user, intended to be the initial user on a device in headless system user mode. */ private UserInfo createInitialUserForHsum() throws UserManager.CheckedUserOperationException { final int flags = UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN; // Null name will be replaced with "Owner" on-demand to allow for localisation. return createUserInternalUnchecked(/* name= */ null, UserManager.USER_TYPE_FULL_SECONDARY, flags, UserHandle.USER_NULL, /* preCreate= */ false, /* disallowedPackages= */ null, /* token= */ null); } private class LocalService extends UserManagerInternal { @Override public void setDevicePolicyUserRestrictions(@UserIdInt int originatingUserId, Loading Loading @@ -7249,15 +7239,9 @@ public class UserManagerService extends IUserManager.Stub { } } } // No switchable users. Create the initial user. final UserInfo newInitialUser = createInitialUserForHsum(); if (newInitialUser == null) { // No switchable users found. Uh oh! throw new UserManager.CheckedUserOperationException( "Initial user creation failed", USER_OPERATION_ERROR_UNKNOWN); } Slogf.i(LOG_TAG, "No switchable users. Boot user is new user %d", newInitialUser.id); return newInitialUser.id; "No switchable users found", USER_OPERATION_ERROR_UNKNOWN); } // Not HSUM, return system user. return UserHandle.USER_SYSTEM; Loading Loading @@ -7437,14 +7421,14 @@ public class UserManagerService extends IUserManager.Stub { /** * Returns true, when user has {@link UserInfo#FLAG_MAIN} and system property * {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. * {@link com.android.internal.R.bool#config_isMainUserPermanentAdmin} is true. */ private boolean isNonRemovableMainUser(UserInfo userInfo) { return userInfo.isMain() && isMainUserPermanentAdmin(); } /** * Returns true, when {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. * Returns true if {@link com.android.internal.R.bool#config_isMainUserPermanentAdmin} is true. * If the main user is a permanent admin user it can't be deleted * or downgraded to non-admin status. */ Loading services/java/com/android/server/BootUserInitializer.java→services/java/com/android/server/HsumBootUserInitializer.java +71 −9 Original line number Diff line number Diff line Loading @@ -15,8 +15,10 @@ */ package com.android.server; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ContentResolver; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; Loading @@ -30,22 +32,43 @@ import com.android.server.utils.TimingsTraceAndSlog; * Class responsible for booting the device in the proper user on headless system user mode. * */ // TODO(b/204091126): STOPSHIP - provide proper APIs final class BootUserInitializer { final class HsumBootUserInitializer { private static final String TAG = BootUserInitializer.class.getSimpleName(); // TODO(b/204091126): STOPSHIP - set to false or dynamic value private static final boolean DEBUG = true; private static final String TAG = HsumBootUserInitializer.class.getSimpleName(); private final UserManagerInternal mUmi; private final ActivityManagerService mAms; private final ContentResolver mContentResolver; BootUserInitializer(ActivityManagerService am, ContentResolver contentResolver) { /** Whether this device should always have a non-removable MainUser, including at first boot. */ private final boolean mShouldAlwaysHaveMainUser; /** Static factory method for creating a {@link HsumBootUserInitializer} instance. */ public static @Nullable HsumBootUserInitializer createInstance(ActivityManagerService am, ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser) { if (!UserManager.isHeadlessSystemUserMode()) { return null; } return new HsumBootUserInitializer( LocalServices.getService(UserManagerInternal.class), am, contentResolver, shouldAlwaysHaveMainUser); } private HsumBootUserInitializer(UserManagerInternal umi, ActivityManagerService am, ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser) { mUmi = umi; mAms = am; mContentResolver = contentResolver; this.mShouldAlwaysHaveMainUser = shouldAlwaysHaveMainUser; } /** * Initialize this object, and create MainUser if needed. * * Should be called before PHASE_SYSTEM_SERVICES_READY as services' setups may require MainUser, * but probably after PHASE_LOCK_SETTINGS_READY since that may be needed for user creation. */ public void init(TimingsTraceAndSlog t) { Slogf.i(TAG, "init())"); Loading @@ -53,17 +76,56 @@ final class BootUserInitializer { // this class or the setup wizard app provisionHeadlessSystemUser(); if (mShouldAlwaysHaveMainUser) { t.traceBegin("createMainUserIfNeeded"); createMainUserIfNeeded(); t.traceEnd(); } } private void createMainUserIfNeeded() { int mainUser = mUmi.getMainUserId(); if (mainUser != UserHandle.USER_NULL) { Slogf.d(TAG, "Found existing MainUser, userId=%d", mainUser); return; } Slogf.d(TAG, "Creating a new MainUser"); try { final UserInfo newInitialUser = mUmi.createUserEvenWhenDisallowed( /* name= */ null, // null will appear as "Owner" in on-demand localisation UserManager.USER_TYPE_FULL_SECONDARY, 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); } } catch (UserManager.CheckedUserOperationException e) { Slogf.wtf(TAG, "Initial bootable MainUser creation failed", e); } } /** * Put the device into the correct user state: unlock the system and switch to the boot user. * * Should only call once PHASE_THIRD_PARTY_APPS_CAN_START is reached to ensure that privileged * apps have had the chance to set the boot user, if applicable. */ public void systemRunning(TimingsTraceAndSlog t) { unlockSystemUser(t); try { t.traceBegin("getBootUser"); int bootUser = LocalServices.getService(UserManagerInternal.class).getBootUser(); final int bootUser = mUmi.getBootUser(); t.traceEnd(); t.traceBegin("switchToBootUser-" + bootUser); switchToBootUser(bootUser); t.traceEnd(); } catch (UserManager.CheckedUserOperationException e) { Slogf.wtf(TAG, "Failed to created boot user", e); Slogf.wtf(TAG, "Failed to switch to boot user since there isn't one."); } } Loading services/java/com/android/server/SystemServer.java +16 −5 Original line number Diff line number Diff line Loading @@ -75,7 +75,6 @@ import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.IStorageManager; import android.provider.DeviceConfig; import android.provider.Settings; Loading Loading @@ -2694,6 +2693,18 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startBootPhase(t, SystemService.PHASE_LOCK_SETTINGS_READY); t.traceEnd(); // Create initial user if needed, which should be done early since some system services rely // on it in their setup, but likely needs to be done after LockSettingsService is ready. final HsumBootUserInitializer hsumBootUserInitializer = HsumBootUserInitializer.createInstance( mActivityManagerService, mContentResolver, context.getResources().getBoolean(R.bool.config_isMainUserPermanentAdmin)); if (hsumBootUserInitializer != null) { t.traceBegin("HsumBootUserInitializer.init"); hsumBootUserInitializer.init(t); t.traceEnd(); } t.traceBegin("StartBootPhaseSystemServicesReady"); mSystemServiceManager.startBootPhase(t, SystemService.PHASE_SYSTEM_SERVICES_READY); t.traceEnd(); Loading Loading @@ -2961,10 +2972,10 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startBootPhase(t, SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); t.traceEnd(); if (UserManager.isHeadlessSystemUserMode() && !isAutomotive) { // TODO(b/204091126): remove isAutomotive check once the workflow is finalized t.traceBegin("BootUserInitializer"); new BootUserInitializer(mActivityManagerService, mContentResolver).init(t); if (hsumBootUserInitializer != null && !isAutomotive) { // TODO(b/261924826): remove isAutomotive check once the workflow is finalized t.traceBegin("HsumBootUserInitializer.systemRunning"); hsumBootUserInitializer.systemRunning(t); t.traceEnd(); } Loading services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +3 −13 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; Loading Loading @@ -316,21 +317,10 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { } @Test public void testGetBootUser_Headless_UserCreatedIfOnlySystemUserExists() throws Exception { public void testGetBootUser_Headless_ThrowsIfOnlySystemUserExists() throws Exception { setSystemUserHeadless(true); int bootUser = mUmi.getBootUser(); assertWithMessage("getStartingUser") .that(bootUser).isNotEqualTo(UserHandle.USER_SYSTEM); UserData newUser = mUsers.get(bootUser); assertWithMessage("New boot user is a full user") .that(newUser.info.isFull()).isTrue(); assertWithMessage("New boot user is an admin user") .that(newUser.info.isAdmin()).isTrue(); assertWithMessage("New boot user is the main user") .that(newUser.info.isMain()).isTrue(); assertThrows(UserManager.CheckedUserOperationException.class, () -> mUmi.getBootUser()); } private void mockCurrentUser(@UserIdInt int userId) { Loading Loading
services/core/java/com/android/server/pm/UserManagerInternal.java +6 −5 Original line number Diff line number Diff line Loading @@ -553,11 +553,12 @@ public abstract class UserManagerInternal { * switched to. * * <p>Otherwise, in {@link UserManager#isHeadlessSystemUserMode() headless system user mode}, * this will be the user who was last in the foreground on this device. If there is no * switchable user on the device, a new user will be created and its id will be returned. * this will be the user who was last in the foreground on this device. * * <p>In non-headless system user mode, the return value will be {@link UserHandle#USER_SYSTEM}. * <p>In non-headless system user mode, the return value will be * {@link android.os.UserHandle#USER_SYSTEM}. * @throws UserManager.CheckedUserOperationException if no switchable user can be found */ public abstract @UserIdInt int getBootUser() throws UserManager.CheckedUserOperationException; public abstract @UserIdInt int getBootUser() throws UserManager.CheckedUserOperationException; }
services/core/java/com/android/server/pm/UserManagerService.java +7 −23 Original line number Diff line number Diff line Loading @@ -5049,6 +5049,8 @@ public class UserManagerService extends IUserManager.Stub { //...then external ones Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); addedIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); // In HSUM, MainUser might be created before PHASE_ACTIVITY_MANAGER_READY has been sent. addedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id); // Also, add the UserHandle for mainline modules which can't use the @hide // EXTRA_USER_HANDLE. Loading Loading @@ -6758,18 +6760,6 @@ public class UserManagerService extends IUserManager.Stub { return mLocalService.isUserInitialized(userId); } /** * Creates a new user, intended to be the initial user on a device in headless system user mode. */ private UserInfo createInitialUserForHsum() throws UserManager.CheckedUserOperationException { final int flags = UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN; // Null name will be replaced with "Owner" on-demand to allow for localisation. return createUserInternalUnchecked(/* name= */ null, UserManager.USER_TYPE_FULL_SECONDARY, flags, UserHandle.USER_NULL, /* preCreate= */ false, /* disallowedPackages= */ null, /* token= */ null); } private class LocalService extends UserManagerInternal { @Override public void setDevicePolicyUserRestrictions(@UserIdInt int originatingUserId, Loading Loading @@ -7249,15 +7239,9 @@ public class UserManagerService extends IUserManager.Stub { } } } // No switchable users. Create the initial user. final UserInfo newInitialUser = createInitialUserForHsum(); if (newInitialUser == null) { // No switchable users found. Uh oh! throw new UserManager.CheckedUserOperationException( "Initial user creation failed", USER_OPERATION_ERROR_UNKNOWN); } Slogf.i(LOG_TAG, "No switchable users. Boot user is new user %d", newInitialUser.id); return newInitialUser.id; "No switchable users found", USER_OPERATION_ERROR_UNKNOWN); } // Not HSUM, return system user. return UserHandle.USER_SYSTEM; Loading Loading @@ -7437,14 +7421,14 @@ public class UserManagerService extends IUserManager.Stub { /** * Returns true, when user has {@link UserInfo#FLAG_MAIN} and system property * {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. * {@link com.android.internal.R.bool#config_isMainUserPermanentAdmin} is true. */ private boolean isNonRemovableMainUser(UserInfo userInfo) { return userInfo.isMain() && isMainUserPermanentAdmin(); } /** * Returns true, when {@link com.android.internal.R.bool.isMainUserPermanentAdmin} is true. * Returns true if {@link com.android.internal.R.bool#config_isMainUserPermanentAdmin} is true. * If the main user is a permanent admin user it can't be deleted * or downgraded to non-admin status. */ Loading
services/java/com/android/server/BootUserInitializer.java→services/java/com/android/server/HsumBootUserInitializer.java +71 −9 Original line number Diff line number Diff line Loading @@ -15,8 +15,10 @@ */ package com.android.server; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ContentResolver; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; Loading @@ -30,22 +32,43 @@ import com.android.server.utils.TimingsTraceAndSlog; * Class responsible for booting the device in the proper user on headless system user mode. * */ // TODO(b/204091126): STOPSHIP - provide proper APIs final class BootUserInitializer { final class HsumBootUserInitializer { private static final String TAG = BootUserInitializer.class.getSimpleName(); // TODO(b/204091126): STOPSHIP - set to false or dynamic value private static final boolean DEBUG = true; private static final String TAG = HsumBootUserInitializer.class.getSimpleName(); private final UserManagerInternal mUmi; private final ActivityManagerService mAms; private final ContentResolver mContentResolver; BootUserInitializer(ActivityManagerService am, ContentResolver contentResolver) { /** Whether this device should always have a non-removable MainUser, including at first boot. */ private final boolean mShouldAlwaysHaveMainUser; /** Static factory method for creating a {@link HsumBootUserInitializer} instance. */ public static @Nullable HsumBootUserInitializer createInstance(ActivityManagerService am, ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser) { if (!UserManager.isHeadlessSystemUserMode()) { return null; } return new HsumBootUserInitializer( LocalServices.getService(UserManagerInternal.class), am, contentResolver, shouldAlwaysHaveMainUser); } private HsumBootUserInitializer(UserManagerInternal umi, ActivityManagerService am, ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser) { mUmi = umi; mAms = am; mContentResolver = contentResolver; this.mShouldAlwaysHaveMainUser = shouldAlwaysHaveMainUser; } /** * Initialize this object, and create MainUser if needed. * * Should be called before PHASE_SYSTEM_SERVICES_READY as services' setups may require MainUser, * but probably after PHASE_LOCK_SETTINGS_READY since that may be needed for user creation. */ public void init(TimingsTraceAndSlog t) { Slogf.i(TAG, "init())"); Loading @@ -53,17 +76,56 @@ final class BootUserInitializer { // this class or the setup wizard app provisionHeadlessSystemUser(); if (mShouldAlwaysHaveMainUser) { t.traceBegin("createMainUserIfNeeded"); createMainUserIfNeeded(); t.traceEnd(); } } private void createMainUserIfNeeded() { int mainUser = mUmi.getMainUserId(); if (mainUser != UserHandle.USER_NULL) { Slogf.d(TAG, "Found existing MainUser, userId=%d", mainUser); return; } Slogf.d(TAG, "Creating a new MainUser"); try { final UserInfo newInitialUser = mUmi.createUserEvenWhenDisallowed( /* name= */ null, // null will appear as "Owner" in on-demand localisation UserManager.USER_TYPE_FULL_SECONDARY, 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); } } catch (UserManager.CheckedUserOperationException e) { Slogf.wtf(TAG, "Initial bootable MainUser creation failed", e); } } /** * Put the device into the correct user state: unlock the system and switch to the boot user. * * Should only call once PHASE_THIRD_PARTY_APPS_CAN_START is reached to ensure that privileged * apps have had the chance to set the boot user, if applicable. */ public void systemRunning(TimingsTraceAndSlog t) { unlockSystemUser(t); try { t.traceBegin("getBootUser"); int bootUser = LocalServices.getService(UserManagerInternal.class).getBootUser(); final int bootUser = mUmi.getBootUser(); t.traceEnd(); t.traceBegin("switchToBootUser-" + bootUser); switchToBootUser(bootUser); t.traceEnd(); } catch (UserManager.CheckedUserOperationException e) { Slogf.wtf(TAG, "Failed to created boot user", e); Slogf.wtf(TAG, "Failed to switch to boot user since there isn't one."); } } Loading
services/java/com/android/server/SystemServer.java +16 −5 Original line number Diff line number Diff line Loading @@ -75,7 +75,6 @@ import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.IStorageManager; import android.provider.DeviceConfig; import android.provider.Settings; Loading Loading @@ -2694,6 +2693,18 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startBootPhase(t, SystemService.PHASE_LOCK_SETTINGS_READY); t.traceEnd(); // Create initial user if needed, which should be done early since some system services rely // on it in their setup, but likely needs to be done after LockSettingsService is ready. final HsumBootUserInitializer hsumBootUserInitializer = HsumBootUserInitializer.createInstance( mActivityManagerService, mContentResolver, context.getResources().getBoolean(R.bool.config_isMainUserPermanentAdmin)); if (hsumBootUserInitializer != null) { t.traceBegin("HsumBootUserInitializer.init"); hsumBootUserInitializer.init(t); t.traceEnd(); } t.traceBegin("StartBootPhaseSystemServicesReady"); mSystemServiceManager.startBootPhase(t, SystemService.PHASE_SYSTEM_SERVICES_READY); t.traceEnd(); Loading Loading @@ -2961,10 +2972,10 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startBootPhase(t, SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); t.traceEnd(); if (UserManager.isHeadlessSystemUserMode() && !isAutomotive) { // TODO(b/204091126): remove isAutomotive check once the workflow is finalized t.traceBegin("BootUserInitializer"); new BootUserInitializer(mActivityManagerService, mContentResolver).init(t); if (hsumBootUserInitializer != null && !isAutomotive) { // TODO(b/261924826): remove isAutomotive check once the workflow is finalized t.traceBegin("HsumBootUserInitializer.systemRunning"); hsumBootUserInitializer.systemRunning(t); t.traceEnd(); } Loading
services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +3 −13 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; Loading Loading @@ -316,21 +317,10 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { } @Test public void testGetBootUser_Headless_UserCreatedIfOnlySystemUserExists() throws Exception { public void testGetBootUser_Headless_ThrowsIfOnlySystemUserExists() throws Exception { setSystemUserHeadless(true); int bootUser = mUmi.getBootUser(); assertWithMessage("getStartingUser") .that(bootUser).isNotEqualTo(UserHandle.USER_SYSTEM); UserData newUser = mUsers.get(bootUser); assertWithMessage("New boot user is a full user") .that(newUser.info.isFull()).isTrue(); assertWithMessage("New boot user is an admin user") .that(newUser.info.isAdmin()).isTrue(); assertWithMessage("New boot user is the main user") .that(newUser.info.isMain()).isTrue(); assertThrows(UserManager.CheckedUserOperationException.class, () -> mUmi.getBootUser()); } private void mockCurrentUser(@UserIdInt int userId) { Loading