Loading services/core/java/com/android/server/pm/UserManagerInternal.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; } services/core/java/com/android/server/pm/UserManagerService.java +70 −38 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"; Loading Loading @@ -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. */ Loading Loading @@ -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"); Loading Loading @@ -7164,47 +7214,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); } } } 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; 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 (!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 Loading services/java/com/android/server/HsumBootUserInitializer.java +11 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 = Loading @@ -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; } Loading Loading @@ -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); Loading services/java/com/android/server/SystemServer.java +2 −3 Original line number Diff line number Diff line Loading @@ -2723,7 +2723,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"); Loading Loading @@ -3023,8 +3023,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(); Loading services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +9 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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) { Loading Loading
services/core/java/com/android/server/pm/UserManagerInternal.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; }
services/core/java/com/android/server/pm/UserManagerService.java +70 −38 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"; Loading Loading @@ -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. */ Loading Loading @@ -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"); Loading Loading @@ -7164,47 +7214,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); } } } 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; 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 (!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 Loading
services/java/com/android/server/HsumBootUserInitializer.java +11 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 = Loading @@ -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; } Loading Loading @@ -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); Loading
services/java/com/android/server/SystemServer.java +2 −3 Original line number Diff line number Diff line Loading @@ -2723,7 +2723,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"); Loading Loading @@ -3023,8 +3023,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(); Loading
services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +9 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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) { Loading