summaryrefslogtreecommitdiff
path: root/services/java
diff options
context:
space:
mode:
author Adam Bookatz <bookatz@google.com> 2023-02-01 19:38:08 -0800
committer Adam Bookatz <bookatz@google.com> 2023-02-02 10:38:29 -0800
commite5a06ca619fb37bc20e5b8d38ab8f2c19f9257cb (patch)
tree6a1cbef2964885a8eb6c67923b2aaff418c405f1 /services/java
parentc0bcd9afb8a79393ece6d920f0e3631ff93f7fc0 (diff)
HsumBootUserInitializer creates MainUser earlier
Previously, on first boot, an HSUM device would unlock the system user, then create the MainUser (if needed), and then switch to the boot user, all at around the same time. This cl reorders these events and spreads them out: * first, early on (just prior to PHASE_SYSTEM_SERVICES_READY), the MainUser is created (if needed) * later (after PHASE_THIRD_PARTY_APPS_CAN_START), the system user is unlocked * then we promptly switch to the boot user. This needs to be after PHASE_THIRD_PARTY_APPS_CAN_START since special apps may designate a different boot user. This will ensure that the MainUser can be retrieved much earlier on by system services whose operations may depend on it. Also, the structure of BootUserInitializer is renamed to better reflect its role, and its structure is modified slightly to allow SystemServer to use it more easily. Bug: 262438904 Bug: 266098768 Test: flashed HSUM and confirmed that MainUser was created as needed Test: atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest Change-Id: Ic84b1be538234b2bfde3ae792c9a923ace55f24c
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/HsumBootUserInitializer.java (renamed from services/java/com/android/server/BootUserInitializer.java)80
-rw-r--r--services/java/com/android/server/SystemServer.java21
2 files changed, 87 insertions, 14 deletions
diff --git a/services/java/com/android/server/BootUserInitializer.java b/services/java/com/android/server/HsumBootUserInitializer.java
index 3d71739924f7..cc6c36ef1ed5 100644
--- a/services/java/com/android/server/BootUserInitializer.java
+++ b/services/java/com/android/server/HsumBootUserInitializer.java
@@ -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;
@@ -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())");
@@ -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.");
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a15c6d288cfd..d22be9ec01d0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -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;
@@ -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();
@@ -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();
}