diff options
5 files changed, 94 insertions, 52 deletions
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java index b4d467f96091..eb37302817c5 100644 --- a/services/core/java/com/android/server/pm/UserManagerInternal.java +++ b/services/core/java/com/android/server/pm/UserManagerInternal.java @@ -573,5 +573,6 @@ public abstract class UserManagerInternal { * @throws UserManager.CheckedUserOperationException if no switchable user can be found */ - public abstract @UserIdInt int getBootUser() throws UserManager.CheckedUserOperationException; + public abstract @UserIdInt int getBootUser(boolean waitUntilSet) + throws UserManager.CheckedUserOperationException; } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 334317281a1c..cde8bd7447e6 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -161,7 +161,9 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -278,6 +280,8 @@ public class UserManagerService extends IUserManager.Stub { static final int WRITE_USER_MSG = 1; static final int WRITE_USER_DELAY = 2*1000; // 2 seconds + private static final long BOOT_USER_SET_TIMEOUT_MS = 300_000; + // Tron counters private static final String TRON_GUEST_CREATED = "users_guest_created"; private static final String TRON_USER_CREATED = "users_user_created"; @@ -333,6 +337,8 @@ public class UserManagerService extends IUserManager.Stub { /** Indicates that this is the 1st boot after the system user mode was changed by emulation. */ private boolean mUpdatingSystemUserMode; + /** Count down latch to wait while boot user is not set.*/ + private final CountDownLatch mBootUserLatch = new CountDownLatch(1); /** * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps. */ @@ -952,18 +958,62 @@ public class UserManagerService extends IUserManager.Stub { Slogf.i(LOG_TAG, "setBootUser %d", userId); mBootUser = userId; } + mBootUserLatch.countDown(); } @Override public @UserIdInt int getBootUser() { checkCreateUsersPermission("Get boot user"); try { - return mLocalService.getBootUser(); + return getBootUserUnchecked(); } catch (UserManager.CheckedUserOperationException e) { throw e.toServiceSpecificException(); } } + private @UserIdInt int getBootUserUnchecked() throws UserManager.CheckedUserOperationException { + synchronized (mUsersLock) { + if (mBootUser != UserHandle.USER_NULL) { + final UserData userData = mUsers.get(mBootUser); + if (userData != null && userData.info.supportsSwitchToByUser()) { + Slogf.i(LOG_TAG, "Using provided boot user: %d", mBootUser); + return mBootUser; + } else { + Slogf.w(LOG_TAG, + "Provided boot user cannot be switched to: %d", mBootUser); + } + } + } + + if (isHeadlessSystemUserMode()) { + // Return the previous foreground user, if there is one. + final int previousUser = getPreviousFullUserToEnterForeground(); + if (previousUser != UserHandle.USER_NULL) { + Slogf.i(LOG_TAG, "Boot user is previous user %d", previousUser); + return previousUser; + } + // No previous user. Return the first switchable user if there is one. + synchronized (mUsersLock) { + final int userSize = mUsers.size(); + for (int i = 0; i < userSize; i++) { + final UserData userData = mUsers.valueAt(i); + if (userData.info.supportsSwitchToByUser()) { + int firstSwitchable = userData.info.id; + Slogf.i(LOG_TAG, + "Boot user is first switchable user %d", firstSwitchable); + return firstSwitchable; + } + } + } + // No switchable users found. Uh oh! + throw new UserManager.CheckedUserOperationException( + "No switchable users found", USER_OPERATION_ERROR_UNKNOWN); + } + // Not HSUM, return system user. + return UserHandle.USER_SYSTEM; + } + + @Override public int getPreviousFullUserToEnterForeground() { checkQueryOrCreateUsersPermission("get previous user"); @@ -7182,47 +7232,29 @@ public class UserManagerService extends IUserManager.Stub { } @Override - public @UserIdInt int getBootUser() throws UserManager.CheckedUserOperationException { - synchronized (mUsersLock) { - // TODO(b/242195409): On Automotive, block if boot user not provided. - if (mBootUser != UserHandle.USER_NULL) { - final UserData userData = mUsers.get(mBootUser); - if (userData != null && userData.info.supportsSwitchToByUser()) { - Slogf.i(LOG_TAG, "Using provided boot user: %d", mBootUser); - return mBootUser; - } else { - Slogf.w(LOG_TAG, - "Provided boot user cannot be switched to: %d", mBootUser); + public @UserIdInt int getBootUser(boolean waitUntilSet) + throws UserManager.CheckedUserOperationException { + if (waitUntilSet) { + final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); + t.traceBegin("wait-boot-user"); + try { + if (mBootUserLatch.getCount() != 0) { + Slogf.d(LOG_TAG, + "Sleeping for boot user to be set. " + + "Max sleep for Time: %d", BOOT_USER_SET_TIMEOUT_MS); } - } - } - - if (isHeadlessSystemUserMode()) { - // Return the previous foreground user, if there is one. - final int previousUser = getPreviousFullUserToEnterForeground(); - if (previousUser != UserHandle.USER_NULL) { - Slogf.i(LOG_TAG, "Boot user is previous user %d", previousUser); - return previousUser; - } - // No previous user. Return the first switchable user if there is one. - synchronized (mUsersLock) { - final int userSize = mUsers.size(); - for (int i = 0; i < userSize; i++) { - final UserData userData = mUsers.valueAt(i); - if (userData.info.supportsSwitchToByUser()) { - int firstSwitchable = userData.info.id; - Slogf.i(LOG_TAG, - "Boot user is first switchable user %d", firstSwitchable); - return firstSwitchable; - } + if (!mBootUserLatch.await(BOOT_USER_SET_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + Slogf.w(LOG_TAG, "Boot user not set. Timeout: %d", + BOOT_USER_SET_TIMEOUT_MS); } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + Slogf.w(LOG_TAG, e, "InterruptedException during wait for boot user."); } - // No switchable users found. Uh oh! - throw new UserManager.CheckedUserOperationException( - "No switchable users found", USER_OPERATION_ERROR_UNKNOWN); + t.traceEnd(); } - // Not HSUM, return system user. - return UserHandle.USER_SYSTEM; + + return getBootUserUnchecked(); } } // class LocalService diff --git a/services/java/com/android/server/HsumBootUserInitializer.java b/services/java/com/android/server/HsumBootUserInitializer.java index 50113feb558b..b8958128adf5 100644 --- a/services/java/com/android/server/HsumBootUserInitializer.java +++ b/services/java/com/android/server/HsumBootUserInitializer.java @@ -18,6 +18,7 @@ package com.android.server; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ContentResolver; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.os.Handler; @@ -27,6 +28,7 @@ import android.os.UserManager; import android.provider.Settings; import com.android.server.am.ActivityManagerService; +import com.android.server.pm.PackageManagerService; import com.android.server.pm.UserManagerInternal; import com.android.server.utils.Slogf; import com.android.server.utils.TimingsTraceAndSlog; @@ -41,6 +43,7 @@ final class HsumBootUserInitializer { private final UserManagerInternal mUmi; private final ActivityManagerService mAms; + private final PackageManagerService mPms; private final ContentResolver mContentResolver; private final ContentObserver mDeviceProvisionedObserver = @@ -63,20 +66,23 @@ final class HsumBootUserInitializer { /** Static factory method for creating a {@link HsumBootUserInitializer} instance. */ public static @Nullable HsumBootUserInitializer createInstance(ActivityManagerService am, - ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser) { + PackageManagerService pms, ContentResolver contentResolver, + boolean shouldAlwaysHaveMainUser) { if (!UserManager.isHeadlessSystemUserMode()) { return null; } return new HsumBootUserInitializer( LocalServices.getService(UserManagerInternal.class), - am, contentResolver, shouldAlwaysHaveMainUser); + am, pms, contentResolver, shouldAlwaysHaveMainUser); } private HsumBootUserInitializer(UserManagerInternal umi, ActivityManagerService am, - ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser) { + PackageManagerService pms, ContentResolver contentResolver, + boolean shouldAlwaysHaveMainUser) { mUmi = umi; mAms = am; + mPms = pms; mContentResolver = contentResolver; mShouldAlwaysHaveMainUser = shouldAlwaysHaveMainUser; } @@ -131,7 +137,8 @@ final class HsumBootUserInitializer { try { t.traceBegin("getBootUser"); - final int bootUser = mUmi.getBootUser(); + final int bootUser = mUmi.getBootUser(/* waitUntilSet= */ mPms + .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, /* version= */0)); t.traceEnd(); t.traceBegin("switchToBootUser-" + bootUser); switchToBootUser(bootUser); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index edfe95efe7f9..460bed9b6cc6 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -2719,7 +2719,7 @@ public final class SystemServer implements Dumpable { // on it in their setup, but likely needs to be done after LockSettingsService is ready. final HsumBootUserInitializer hsumBootUserInitializer = HsumBootUserInitializer.createInstance( - mActivityManagerService, mContentResolver, + mActivityManagerService, mPackageManagerService, mContentResolver, context.getResources().getBoolean(R.bool.config_isMainUserPermanentAdmin)); if (hsumBootUserInitializer != null) { t.traceBegin("HsumBootUserInitializer.init"); @@ -3019,8 +3019,7 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startBootPhase(t, SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); t.traceEnd(); - if (hsumBootUserInitializer != null && !isAutomotive) { - // TODO(b/261924826): remove isAutomotive check once the workflow is finalized + if (hsumBootUserInitializer != null) { t.traceBegin("HsumBootUserInitializer.systemRunning"); hsumBootUserInitializer.systemRunning(t); t.traceEnd(); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java index 564893c3c629..e7b3e6f88dce 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java @@ -260,7 +260,7 @@ public final class UserManagerServiceTest { mUms.setBootUser(OTHER_USER_ID); assertWithMessage("getBootUser") - .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID); + .that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID); } @Test @@ -273,7 +273,8 @@ public final class UserManagerServiceTest { mUms.setBootUser(PROFILE_USER_ID); assertWithMessage("getBootUser") - .that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM); + .that(mUmi.getBootUser(/* waitUntilSet= */ false)) + .isEqualTo(UserHandle.USER_SYSTEM); } @Test @@ -289,7 +290,7 @@ public final class UserManagerServiceTest { // Boot user not switchable so return most recently in foreground. assertWithMessage("getBootUser") - .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID); + .that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID); } @Test @@ -299,7 +300,8 @@ public final class UserManagerServiceTest { addUser(OTHER_USER_ID); assertWithMessage("getBootUser") - .that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM); + .that(mUmi.getBootUser(/* waitUntilSet= */ false)) + .isEqualTo(UserHandle.USER_SYSTEM); } @Test @@ -312,14 +314,15 @@ public final class UserManagerServiceTest { setLastForegroundTime(OTHER_USER_ID, 2_000_000L); assertWithMessage("getBootUser") - .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID); + .that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID); } @Test public void testGetBootUser_Headless_ThrowsIfOnlySystemUserExists() throws Exception { setSystemUserHeadless(true); - assertThrows(UserManager.CheckedUserOperationException.class, () -> mUmi.getBootUser()); + assertThrows(UserManager.CheckedUserOperationException.class, + () -> mUmi.getBootUser(/* waitUntilSet= */ false)); } private void mockCurrentUser(@UserIdInt int userId) { |