Integrate new boot user flow with auto
Bug: 261913541 Bug: 261924826 Test: atest UserManagerServiceTest Change-Id: I4740fe58bef942e534b6eef24bc5a1ddce270d02
This commit is contained in:
@@ -536,5 +536,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;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,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;
|
||||
|
||||
@@ -277,6 +279,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";
|
||||
@@ -332,6 +336,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.
|
||||
*/
|
||||
@@ -969,18 +975,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");
|
||||
@@ -7275,47 +7325,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 (!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.");
|
||||
}
|
||||
t.traceEnd();
|
||||
}
|
||||
|
||||
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;
|
||||
return getBootUserUnchecked();
|
||||
}
|
||||
|
||||
} // class LocalService
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
@@ -3011,8 +3011,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();
|
||||
|
||||
@@ -261,7 +261,7 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
|
||||
mUms.setBootUser(OTHER_USER_ID);
|
||||
|
||||
assertWithMessage("getBootUser")
|
||||
.that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID);
|
||||
.that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -274,7 +274,8 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
|
||||
mUms.setBootUser(PROFILE_USER_ID);
|
||||
|
||||
assertWithMessage("getBootUser")
|
||||
.that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM);
|
||||
.that(mUmi.getBootUser(/* waitUntilSet= */ false))
|
||||
.isEqualTo(UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -290,7 +291,7 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
|
||||
|
||||
// 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
|
||||
@@ -300,7 +301,8 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
|
||||
addUser(OTHER_USER_ID);
|
||||
|
||||
assertWithMessage("getBootUser")
|
||||
.that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM);
|
||||
.that(mUmi.getBootUser(/* waitUntilSet= */ false))
|
||||
.isEqualTo(UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -313,14 +315,15 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user