summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/UserController.java65
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java15
2 files changed, 80 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 7ffea26638f5..44b186e1541f 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -106,6 +106,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.FactoryResetter;
import com.android.server.FgThread;
@@ -368,6 +369,11 @@ class UserController implements Handler.Callback {
private boolean mDelayUserDataLocking;
/**
+ * Users are only allowed to be unlocked after boot complete.
+ */
+ private volatile boolean mAllowUserUnlocking;
+
+ /**
* Keep track of last active users for mDelayUserDataLocking.
* The latest stopped user is placed in front while the least recently stopped user in back.
*/
@@ -426,6 +432,11 @@ class UserController implements Handler.Callback {
mUserLru.add(UserHandle.USER_SYSTEM);
mLockPatternUtils = mInjector.getLockPatternUtils();
updateStartedUserArrayLU();
+
+ // TODO(b/232452368): currently mAllowUserUnlocking is only used on devices with HSUM
+ // (Headless System User Mode), but on master it will be used by all devices (and hence this
+ // initial assignment should be removed).
+ mAllowUserUnlocking = !UserManager.isHeadlessSystemUserMode();
}
void setInitialConfig(boolean userSwitchUiEnabled, int maxRunningUsers,
@@ -1742,6 +1753,22 @@ class UserController implements Handler.Callback {
private boolean unlockUserCleared(final @UserIdInt int userId, byte[] secret,
IProgressListener listener) {
+ // Delay user unlocking for headless system user mode until the system boot
+ // completes. When the system boot completes, the {@link #onBootCompleted()}
+ // method unlocks all started users for headless system user mode. This is done
+ // to prevent unlocking the users too early during the system boot up.
+ // Otherwise, emulated volumes are mounted too early during the system
+ // boot up. When vold is reset on boot complete, vold kills all apps/services
+ // (that use these emulated volumes) before unmounting the volumes(b/241929666).
+ // In the past, these killings have caused the system to become too unstable on
+ // some occasions.
+ // Any unlocks that get delayed by this will be done by onBootComplete() instead.
+ if (!mAllowUserUnlocking) {
+ Slogf.i(TAG, "Not unlocking user %d yet because boot hasn't completed", userId);
+ notifyFinished(userId, listener);
+ return false;
+ }
+
UserState uss;
if (!StorageManager.isUserKeyUnlocked(userId)) {
final UserInfo userInfo = getUserInfo(userId);
@@ -2331,7 +2358,44 @@ class UserController implements Handler.Callback {
}
}
+ @VisibleForTesting
+ void setAllowUserUnlocking(boolean allowed) {
+ mAllowUserUnlocking = allowed;
+ if (DEBUG_MU) {
+ // TODO(b/245335748): use Slogf.d instead
+ // Slogf.d(TAG, new Exception(), "setAllowUserUnlocking(%b)", allowed);
+ android.util.Slog.d(TAG, "setAllowUserUnlocking():" + allowed, new Exception());
+ }
+ }
+
+ /**
+ * @deprecated TODO(b/232452368): this logic will be merged into sendBootCompleted
+ */
+ @Deprecated
+ private void onBootCompletedOnHeadlessSystemUserModeDevices() {
+ setAllowUserUnlocking(true);
+
+ // Get a copy of mStartedUsers to use outside of lock.
+ SparseArray<UserState> startedUsers;
+ synchronized (mLock) {
+ startedUsers = mStartedUsers.clone();
+ }
+ // USER_SYSTEM must be processed first. It will be first in the array, as its ID is lowest.
+ Preconditions.checkArgument(startedUsers.keyAt(0) == UserHandle.USER_SYSTEM);
+ for (int i = 0; i < startedUsers.size(); i++) {
+ UserState uss = startedUsers.valueAt(i);
+ int userId = uss.mHandle.getIdentifier();
+ Slogf.i(TAG, "Attempting to unlock user %d on boot complete", userId);
+ maybeUnlockUser(userId);
+ }
+ }
+
void sendBootCompleted(IIntentReceiver resultTo) {
+ if (UserManager.isHeadlessSystemUserMode()) {
+ // Unlocking users is delayed until boot complete for headless system user mode.
+ onBootCompletedOnHeadlessSystemUserModeDevices();
+ }
+
// Get a copy of mStartedUsers to use outside of lock
SparseArray<UserState> startedUsers;
synchronized (mLock) {
@@ -2773,6 +2837,7 @@ class UserController implements Handler.Callback {
pw.println(" mTargetUserId:" + mTargetUserId);
pw.println(" mLastActiveUsers:" + mLastActiveUsers);
pw.println(" mDelayUserDataLocking:" + mDelayUserDataLocking);
+ pw.println(" mAllowUserUnlocking:" + mAllowUserUnlocking);
pw.println(" shouldStopUserOnSwitch():" + shouldStopUserOnSwitch());
pw.println(" mStopUserOnSwitch:" + mStopUserOnSwitch);
pw.println(" mMaxRunningUsers:" + mMaxRunningUsers);
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index db1209224bd5..1508055263ef 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -179,6 +179,11 @@ public class UserControllerTest {
doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt());
// All UserController params are set to default.
mUserController = new UserController(mInjector);
+
+ // TODO(b/232452368): need to explicitly call setAllowUserUnlocking(), otherwise most
+ // tests would fail. But we might need to disable it for the onBootComplete() test (i.e,
+ // to make sure the users are unlocked at the right time)
+ mUserController.setAllowUserUnlocking(true);
setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated=*/ true, null);
});
@@ -600,6 +605,16 @@ public class UserControllerTest {
}
@Test
+ public void testUserNotUnlockedBeforeAllowed() throws Exception {
+ mUserController.setAllowUserUnlocking(false);
+
+ mUserController.startUser(TEST_USER_ID, /* foreground= */ false);
+
+ verify(mInjector.mStorageManagerMock, never())
+ .unlockUserKey(eq(TEST_USER_ID), anyInt(), any());
+ }
+
+ @Test
public void testStartProfile_fullUserFails() {
setUpUser(TEST_USER_ID1, 0);
assertThrows(IllegalArgumentException.class,