diff options
| -rw-r--r-- | core/api/system-current.txt | 1 | ||||
| -rw-r--r-- | core/api/test-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/os/IUserManager.aidl | 4 | ||||
| -rw-r--r-- | core/java/android/os/UserManager.java | 34 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/UserManagerInternal.java | 16 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/UserManagerService.java | 99 | ||||
| -rw-r--r-- | services/java/com/android/server/BootUserInitializer.java | 63 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java | 121 |
8 files changed, 284 insertions, 55 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index ceed59f79464..a70dcc775dbc 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10411,6 +10411,7 @@ package android.os { method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public boolean isUserVisible(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull android.os.UserHandle); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public int removeUserWhenPossible(@NonNull android.os.UserHandle, boolean); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public void setBootUser(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap) throws android.os.UserManager.UserOperationException; method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean someUserHasAccount(@NonNull String, @NonNull String); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 3bc11facad4a..1a8ea6f1087a 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2025,6 +2025,7 @@ package android.os { method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createProfileForUser(@Nullable String, @NonNull String, int, int, @Nullable String[]); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createRestrictedProfile(@Nullable String); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle getBootUser(); method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.Set<java.lang.String> getPreInstallableSystemPackages(@NonNull String); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public String getUserType(); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers(boolean, boolean, boolean); diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 3b4e8cd39697..d1d331550ab9 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -142,4 +142,8 @@ interface IUserManager { long getUserStartRealtime(); long getUserUnlockRealtime(); boolean setUserEphemeral(int userId, boolean enableEphemeral); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS})") + void setBootUser(int userId); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS})") + int getBootUser(); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 0e4c2b2928d6..f6859ba57ff4 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -5656,6 +5656,40 @@ public class UserManager { } } + /** + * Sets the user who should be in the foreground when boot completes. This should be called + * during boot, and the provided user must be a full user (i.e. not a profile). + * + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) + public void setBootUser(@NonNull UserHandle bootUser) { + try { + mService.setBootUser(bootUser.getIdentifier()); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Returns the user who should be in the foreground when boot completes. + * + * @hide + */ + @TestApi + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) + @SuppressWarnings("[AndroidFrameworkContextUserId]") + public @NonNull UserHandle getBootUser() { + try { + return UserHandle.of(mService.getBootUser()); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /* Cache key for anything that assumes that userIds cannot be re-used without rebooting. */ private static final String CACHE_KEY_STATIC_USER_PROPERTIES = "cache_key.static_user_props"; diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java index 2ae8b52da172..4acd81560d4a 100644 --- a/services/core/java/com/android/server/pm/UserManagerInternal.java +++ b/services/core/java/com/android/server/pm/UserManagerInternal.java @@ -485,4 +485,20 @@ public abstract class UserManagerInternal { * @see UserManager#isMainUser() */ public abstract @UserIdInt int getMainUserId(); + + /** + * Returns the id of the user which should be in the foreground after boot completes. + * + * <p>If a boot user has been provided by calling {@link UserManager#setBootUser}, the + * returned value will be whatever was specified, as long as that user exists and can be + * 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. + * + * <p>In non-headless system user mode, the return value will be {@link UserHandle#USER_SYSTEM}. + */ + public abstract @UserIdInt int getBootUser() + 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 81f83b0591c4..dc8786280633 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -21,6 +21,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.UserManager.DEV_CREATE_OVERRIDE_PROPERTY; import static android.os.UserManager.DISALLOW_USER_SWITCH; import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY; +import static android.os.UserManager.USER_OPERATION_ERROR_UNKNOWN; import android.Manifest; import android.accounts.Account; @@ -637,6 +638,9 @@ public class UserManagerService extends IUserManager.Stub { private final UserVisibilityMediator mUserVisibilityMediator; + @GuardedBy("mUsersLock") + private @UserIdInt int mBootUser = UserHandle.USER_NULL; + private static UserManagerService sInstance; public static UserManagerService getInstance() { @@ -936,6 +940,26 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public void setBootUser(@UserIdInt int userId) { + checkCreateUsersPermission("Set boot user"); + synchronized (mUsersLock) { + // TODO(b/263381643): Change to EventLog. + Slogf.i(LOG_TAG, "setBootUser %d", userId); + mBootUser = userId; + } + } + + @Override + public @UserIdInt int getBootUser() { + checkCreateUsersPermission("Get boot user"); + try { + return mLocalService.getBootUser(); + } catch (UserManager.CheckedUserOperationException e) { + throw e.toServiceSpecificException(); + } + } + + @Override public int getPreviousFullUserToEnterForeground() { checkQueryOrCreateUsersPermission("get previous user"); int previousUser = UserHandle.USER_NULL; @@ -1574,6 +1598,8 @@ public class UserManagerService extends IUserManager.Stub { Slog.w(LOG_TAG, "System user instantiated at least " + number + " times"); } name = getOwnerName(); + } else if (orig.isMain()) { + name = getOwnerName(); } else if (orig.isGuest()) { name = getGuestName(); } @@ -4557,7 +4583,7 @@ public class UserManagerService extends IUserManager.Stub { UserHandle.USER_NULL, null); if (userInfo == null) { - throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN); + throw new ServiceSpecificException(USER_OPERATION_ERROR_UNKNOWN); } } catch (UserManager.CheckedUserOperationException e) { throw e.toServiceSpecificException(); @@ -4686,7 +4712,7 @@ public class UserManagerService extends IUserManager.Stub { if (parent == null) { throwCheckedUserOperationException( "Cannot find user data for parent user " + parentId, - UserManager.USER_OPERATION_ERROR_UNKNOWN); + USER_OPERATION_ERROR_UNKNOWN); } } if (!preCreate && !canAddMoreUsersOfType(userTypeDetails)) { @@ -4714,7 +4740,7 @@ public class UserManagerService extends IUserManager.Stub { && !isCreationOverrideEnabled()) { throwCheckedUserOperationException( "Cannot add restricted profile - parent user must be system", - UserManager.USER_OPERATION_ERROR_UNKNOWN); + USER_OPERATION_ERROR_UNKNOWN); } userId = getNextAvailableId(); @@ -6480,6 +6506,9 @@ public class UserManagerService extends IUserManager.Stub { if (DBG_ALLOCATION) { pw.println(" System user allocations: " + mUser0Allocations.get()); } + synchronized (mUsersLock) { + pw.println(" Boot user: " + mBootUser); + } pw.println(); pw.println("Number of listeners for"); @@ -6672,6 +6701,18 @@ 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, @@ -7105,6 +7146,56 @@ public class UserManagerService extends IUserManager.Stub { return getMainUserIdUnchecked(); } + @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; + } + } + } + // No switchable users. Create the initial user. + final UserInfo newInitialUser = createInitialUserForHsum(); + if (newInitialUser == null) { + 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; + } + // Not HSUM, return system user. + return UserHandle.USER_SYSTEM; + } + } // class LocalService @@ -7124,7 +7215,7 @@ public class UserManagerService extends IUserManager.Stub { + restriction + " is enabled."; Slog.w(LOG_TAG, errorMessage); throw new UserManager.CheckedUserOperationException(errorMessage, - UserManager.USER_OPERATION_ERROR_UNKNOWN); + USER_OPERATION_ERROR_UNKNOWN); } } diff --git a/services/java/com/android/server/BootUserInitializer.java b/services/java/com/android/server/BootUserInitializer.java index deebfc7f7d07..3d71739924f7 100644 --- a/services/java/com/android/server/BootUserInitializer.java +++ b/services/java/com/android/server/BootUserInitializer.java @@ -17,7 +17,6 @@ package com.android.server; 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; @@ -27,8 +26,6 @@ import com.android.server.pm.UserManagerInternal; import com.android.server.utils.Slogf; import com.android.server.utils.TimingsTraceAndSlog; -import java.util.List; - /** * Class responsible for booting the device in the proper user on headless system user mode. * @@ -56,50 +53,18 @@ final class BootUserInitializer { // this class or the setup wizard app provisionHeadlessSystemUser(); - UserManagerInternal um = LocalServices.getService(UserManagerInternal.class); - t.traceBegin("get-existing-users"); - List<UserInfo> existingUsers = um.getUsers(/* excludeDying= */ true); - t.traceEnd(); - - Slogf.d(TAG, "%d existing users", existingUsers.size()); - - int initialUserId = UserHandle.USER_NULL; - - for (int i = 0; i < existingUsers.size(); i++) { - UserInfo user = existingUsers.get(i); - if (DEBUG) { - Slogf.d(TAG, "User at position %d: %s", i, user.toFullString()); - } - if (user.id != UserHandle.USER_SYSTEM && user.isFull()) { - if (DEBUG) { - Slogf.d(TAG, "Found initial user: %d", user.id); - } - initialUserId = user.id; - break; - } - } + unlockSystemUser(t); - if (initialUserId == UserHandle.USER_NULL) { - Slogf.d(TAG, "Creating initial user"); - t.traceBegin("create-initial-user"); - try { - int flags = UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN; - // TODO(b/204091126): proper name for user - UserInfo newUser = um.createUserEvenWhenDisallowed("Real User", - UserManager.USER_TYPE_FULL_SECONDARY, flags, - /* disallowedPackages= */ null, /* token= */ null); - Slogf.i(TAG, "Created initial user: %s", newUser.toFullString()); - initialUserId = newUser.id; - } catch (Exception e) { - Slogf.wtf(TAG, "failed to created initial user", e); - return; - } finally { - t.traceEnd(); // create-initial-user - } + try { + t.traceBegin("getBootUser"); + int bootUser = LocalServices.getService(UserManagerInternal.class).getBootUser(); + t.traceEnd(); + t.traceBegin("switchToBootUser-" + bootUser); + switchToBootUser(bootUser); + t.traceEnd(); + } catch (UserManager.CheckedUserOperationException e) { + Slogf.wtf(TAG, "Failed to created boot user", e); } - - unlockSystemUser(t); - switchToInitialUser(initialUserId); } /* TODO(b/261791491): STOPSHIP - SUW should be responsible for this. */ @@ -152,12 +117,12 @@ final class BootUserInitializer { } } - private void switchToInitialUser(@UserIdInt int initialUserId) { - Slogf.i(TAG, "Switching to initial user %d", initialUserId); - boolean started = mAms.startUserInForegroundWithListener(initialUserId, + private void switchToBootUser(@UserIdInt int bootUserId) { + Slogf.i(TAG, "Switching to boot user %d", bootUserId); + boolean started = mAms.startUserInForegroundWithListener(bootUserId, /* unlockListener= */ null); if (!started) { - Slogf.wtf(TAG, "Failed to start user %d in foreground", initialUserId); + Slogf.wtf(TAG, "Failed to start user %d in foreground", bootUserId); } } } 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 1367af8eede3..f13de1243955 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java @@ -20,25 +20,31 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertWithMessage; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.content.Context; +import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.StorageManager; +import android.provider.Settings; import android.util.Log; import android.util.SparseArray; import androidx.test.annotation.UiThreadTest; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; +import com.android.internal.widget.LockSettingsInternal; import com.android.server.ExtendedMockitoTestCase; import com.android.server.LocalServices; import com.android.server.am.UserState; import com.android.server.pm.UserManagerService.UserData; +import com.android.server.storage.DeviceStorageMonitorInternal; import org.junit.After; import org.junit.Before; @@ -86,6 +92,10 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { private @Mock PackageManagerService mMockPms; private @Mock UserDataPreparer mMockUserDataPreparer; private @Mock ActivityManagerInternal mActivityManagerInternal; + private @Mock DeviceStorageMonitorInternal mDeviceStorageMonitorInternal; + private @Mock StorageManager mStorageManager; + private @Mock LockSettingsInternal mLockSettingsInternal; + private @Mock PackageManagerInternal mPackageManagerInternal; /** * Reference to the {@link UserManagerService} being tested. @@ -101,7 +111,8 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { protected void initializeSession(StaticMockitoSessionBuilder builder) { builder .spyStatic(UserManager.class) - .spyStatic(LocalServices.class); + .spyStatic(LocalServices.class) + .mockStatic(Settings.Global.class); } @Before @@ -112,6 +123,14 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { // Called when WatchedUserStates is constructed doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache()); + // Called when creating new users + when(mDeviceStorageMonitorInternal.isMemoryLow()).thenReturn(false); + mockGetLocalService(DeviceStorageMonitorInternal.class, mDeviceStorageMonitorInternal); + when(mSpiedContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager); + mockGetLocalService(LockSettingsInternal.class, mLockSettingsInternal); + mockGetLocalService(PackageManagerInternal.class, mPackageManagerInternal); + doNothing().when(mSpiedContext).sendBroadcastAsUser(any(), any(), any()); + // Must construct UserManagerService in the UiThread mUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer, mPackagesLock, mRealContext.getDataDir(), mUsers); @@ -223,6 +242,87 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { .that(mUms.isUserRunning(PROFILE_USER_ID)).isFalse(); } + @Test + public void testSetBootUser_SuppliedUserIsSwitchable() throws Exception { + addUser(USER_ID); + addUser(OTHER_USER_ID); + + mUms.setBootUser(OTHER_USER_ID); + + assertWithMessage("getBootUser") + .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID); + } + + @Test + public void testSetBootUser_NotHeadless_SuppliedUserIsNotSwitchable() throws Exception { + setSystemUserHeadless(false); + addUser(USER_ID); + addUser(OTHER_USER_ID); + addDefaultProfileAndParent(); + + mUms.setBootUser(PROFILE_USER_ID); + + assertWithMessage("getBootUser") + .that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM); + } + + @Test + public void testSetBootUser_Headless_SuppliedUserIsNotSwitchable() throws Exception { + setSystemUserHeadless(true); + addUser(USER_ID); + setLastForegroundTime(USER_ID, 1_000_000L); + addUser(OTHER_USER_ID); + setLastForegroundTime(OTHER_USER_ID, 2_000_000L); + addDefaultProfileAndParent(); + + mUms.setBootUser(PROFILE_USER_ID); + + // Boot user not switchable so return most recently in foreground. + assertWithMessage("getBootUser") + .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID); + } + + @Test + public void testGetBootUser_NotHeadless_ReturnsSystemUser() throws Exception { + setSystemUserHeadless(false); + addUser(USER_ID); + addUser(OTHER_USER_ID); + + assertWithMessage("getBootUser") + .that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM); + } + + @Test + public void testGetBootUser_Headless_ReturnsMostRecentlyInForeground() throws Exception { + setSystemUserHeadless(true); + addUser(USER_ID); + setLastForegroundTime(USER_ID, 1_000_000L); + + addUser(OTHER_USER_ID); + setLastForegroundTime(OTHER_USER_ID, 2_000_000L); + + assertWithMessage("getBootUser") + .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID); + } + + @Test + public void testGetBootUser_Headless_UserCreatedIfOnlySystemUserExists() 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(); + } + private void mockCurrentUser(@UserIdInt int userId) { mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal); @@ -248,7 +348,7 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { private void addUser(@UserIdInt int userId) { TestUserData userData = new TestUserData(userId); - + userData.info.flags = UserInfo.FLAG_FULL; addUserData(userData); } @@ -277,6 +377,23 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { mUsers.put(userData.info.id, userData); } + private void setSystemUserHeadless(boolean headless) { + UserData systemUser = mUsers.get(UserHandle.USER_SYSTEM); + if (headless) { + systemUser.info.flags &= ~UserInfo.FLAG_FULL; + systemUser.info.userType = UserManager.USER_TYPE_SYSTEM_HEADLESS; + } else { + systemUser.info.flags |= UserInfo.FLAG_FULL; + systemUser.info.userType = UserManager.USER_TYPE_FULL_SYSTEM; + } + doReturn(headless).when(() -> UserManager.isHeadlessSystemUserMode()); + } + + private void setLastForegroundTime(@UserIdInt int userId, long timeMillis) { + UserData userData = mUsers.get(userId); + userData.mLastEnteredForegroundTimeMillis = timeMillis; + } + private static final class TestUserData extends UserData { @SuppressWarnings("deprecation") |