diff options
| -rw-r--r-- | services/core/java/com/android/server/am/UserController.java | 70 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/am/UserControllerTest.java | 53 |
2 files changed, 112 insertions, 11 deletions
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index a075a13bc64a..d52f52e59d39 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -103,6 +103,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; 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.widget.LockPatternUtils; @@ -162,6 +163,7 @@ class UserController implements Handler.Callback { static final int USER_UNLOCKED_MSG = 105; static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 110; static final int START_USER_SWITCH_FG_MSG = 120; + static final int COMPLETE_USER_SWITCH_MSG = 130; // Message constant to clear {@link UserJourneySession} from {@link mUserIdToUserJourneyMap} if // the user journey, defined in the UserLifecycleJourneyReported atom for statsd, is not @@ -385,6 +387,7 @@ class UserController implements Handler.Callback { @VisibleForTesting UserController(Injector injector) { mInjector = injector; + // This should be called early to avoid a null mHandler inside the injector mHandler = mInjector.getHandler(this); mUiHandler = mInjector.getUiHandler(this); // User 0 is the first and only user that runs at boot. @@ -1535,7 +1538,10 @@ class UserController implements Handler.Callback { // with the option to show the user switcher on the keyguard. if (userSwitchUiEnabled) { mInjector.getWindowManager().setSwitchingUser(true); - mInjector.getWindowManager().lockNow(null); + // Only lock if the user has a secure keyguard PIN/Pattern/Pwd + if (mInjector.getKeyguardManager().isDeviceSecure(userId)) { + mInjector.getWindowManager().lockNow(null); + } } } else { final Integer currentUserIdInt = mCurrentUserId; @@ -1967,11 +1973,10 @@ class UserController implements Handler.Callback { EventLog.writeEvent(EventLogTags.UC_CONTINUE_USER_SWITCH, oldUserId, newUserId); - if (isUserSwitchUiEnabled()) { - t.traceBegin("stopFreezingScreen"); - mInjector.getWindowManager().stopFreezingScreen(); - t.traceEnd(); - } + // Do the keyguard dismiss and unfreeze later + mHandler.removeMessages(COMPLETE_USER_SWITCH_MSG); + mHandler.sendMessage(mHandler.obtainMessage(COMPLETE_USER_SWITCH_MSG, newUserId, 0)); + uss.switching = false; mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG); mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG, newUserId, 0)); @@ -1981,6 +1986,34 @@ class UserController implements Handler.Callback { t.traceEnd(); // end continueUserSwitch } + @VisibleForTesting + void completeUserSwitch(int newUserId) { + if (isUserSwitchUiEnabled()) { + // If there is no challenge set, dismiss the keyguard right away + if (!mInjector.getKeyguardManager().isDeviceSecure(newUserId)) { + // Wait until the keyguard is dismissed to unfreeze + mInjector.dismissKeyguard( + new Runnable() { + public void run() { + unfreezeScreen(); + } + }, + "User Switch"); + return; + } else { + unfreezeScreen(); + } + } + } + + @VisibleForTesting + void unfreezeScreen() { + TimingsTraceAndSlog t = new TimingsTraceAndSlog(); + t.traceBegin("stopFreezingScreen"); + mInjector.getWindowManager().stopFreezingScreen(); + t.traceEnd(); + } + private void moveUserToForeground(UserState uss, int oldUserId, int newUserId) { boolean homeInFront = mInjector.taskSupervisorSwitchUser(newUserId, uss); if (homeInFront) { @@ -2772,6 +2805,9 @@ class UserController implements Handler.Callback { case CLEAR_USER_JOURNEY_SESSION_MSG: logAndClearSessionId(msg.arg1); break; + case COMPLETE_USER_SWITCH_MSG: + completeUserSwitch(msg.arg1); + break; } return false; } @@ -2961,13 +2997,14 @@ class UserController implements Handler.Callback { private final ActivityManagerService mService; private UserManagerService mUserManager; private UserManagerInternal mUserManagerInternal; + private Handler mHandler; Injector(ActivityManagerService service) { mService = service; } protected Handler getHandler(Handler.Callback callback) { - return new Handler(mService.mHandlerThread.getLooper(), callback); + return mHandler = new Handler(mService.mHandlerThread.getLooper(), callback); } protected Handler getUiHandler(Handler.Callback callback) { @@ -3165,5 +3202,24 @@ class UserController implements Handler.Callback { protected IStorageManager getStorageManager() { return IStorageManager.Stub.asInterface(ServiceManager.getService("mount")); } + + protected void dismissKeyguard(Runnable runnable, String reason) { + getWindowManager().dismissKeyguard(new IKeyguardDismissCallback.Stub() { + @Override + public void onDismissError() throws RemoteException { + mHandler.post(runnable); + } + + @Override + public void onDismissSucceeded() throws RemoteException { + mHandler.post(runnable); + } + + @Override + public void onDismissCancelled() throws RemoteException { + mHandler.post(runnable); + } + }, reason); + } } } 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 9ffb50176f0e..f1a63bcb0602 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -21,6 +21,7 @@ import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareC import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.server.am.UserController.COMPLETE_USER_SWITCH_MSG; import static com.android.server.am.UserController.CONTINUE_USER_SWITCH_MSG; import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG; import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG; @@ -59,6 +60,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.IUserSwitchObserver; +import android.app.KeyguardManager; import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; @@ -325,8 +327,16 @@ public class UserControllerTest { assertWithMessage("No messages should be sent").that(actualCodes).isEmpty(); } + private void continueAndCompleteUserSwitch(UserState userState, int oldUserId, int newUserId) { + mUserController.continueUserSwitch(userState, oldUserId, newUserId); + mInjector.mHandler.removeMessages(UserController.COMPLETE_USER_SWITCH_MSG); + mUserController.completeUserSwitch(newUserId); + } + @Test public void testContinueUserSwitch() throws RemoteException { + mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true, + /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, true); Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); @@ -336,7 +346,28 @@ public class UserControllerTest { int newUserId = reportMsg.arg2; mInjector.mHandler.clearAllRecordedMessages(); // Verify that continueUserSwitch worked as expected - mUserController.continueUserSwitch(userState, oldUserId, newUserId); + continueAndCompleteUserSwitch(userState, oldUserId, newUserId); + verify(mInjector, times(0)).dismissKeyguard(any(), anyString()); + verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen(); + continueUserSwitchAssertions(TEST_USER_ID, false); + } + + @Test + public void testContinueUserSwitchDismissKeyguard() throws RemoteException { + when(mInjector.mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(false); + mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true, + /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false); + // Start user -- this will update state of mUserController + mUserController.startUser(TEST_USER_ID, true); + Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); + assertNotNull(reportMsg); + UserState userState = (UserState) reportMsg.obj; + int oldUserId = reportMsg.arg1; + int newUserId = reportMsg.arg2; + mInjector.mHandler.clearAllRecordedMessages(); + // Verify that continueUserSwitch worked as expected + continueAndCompleteUserSwitch(userState, oldUserId, newUserId); + verify(mInjector, times(1)).dismissKeyguard(any(), anyString()); verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen(); continueUserSwitchAssertions(TEST_USER_ID, false); } @@ -355,7 +386,7 @@ public class UserControllerTest { int newUserId = reportMsg.arg2; mInjector.mHandler.clearAllRecordedMessages(); // Verify that continueUserSwitch worked as expected - mUserController.continueUserSwitch(userState, oldUserId, newUserId); + continueAndCompleteUserSwitch(userState, oldUserId, newUserId); verify(mInjector.getWindowManager(), never()).stopFreezingScreen(); continueUserSwitchAssertions(TEST_USER_ID, false); } @@ -363,6 +394,7 @@ public class UserControllerTest { private void continueUserSwitchAssertions(int expectedUserId, boolean backgroundUserStopping) throws RemoteException { Set<Integer> expectedCodes = new LinkedHashSet<>(); + expectedCodes.add(COMPLETE_USER_SWITCH_MSG); expectedCodes.add(REPORT_USER_SWITCH_COMPLETE_MSG); if (backgroundUserStopping) { expectedCodes.add(0); // this is for directly posting in stopping. @@ -397,7 +429,7 @@ public class UserControllerTest { } @Test - public void testExplicitSystenUserStartInBackground() { + public void testExplicitSystemUserStartInBackground() { setUpUser(UserHandle.USER_SYSTEM, 0); assertFalse(mUserController.isSystemUserStarted()); assertTrue(mUserController.startUser(UserHandle.USER_SYSTEM, false, null)); @@ -646,7 +678,7 @@ public class UserControllerTest { mUserStates.put(newUserId, userState); mInjector.mHandler.clearAllRecordedMessages(); // Verify that continueUserSwitch worked as expected - mUserController.continueUserSwitch(userState, oldUserId, newUserId); + continueAndCompleteUserSwitch(userState, oldUserId, newUserId); verify(mInjector.getWindowManager(), times(expectedNumberOfCalls)) .stopFreezingScreen(); continueUserSwitchAssertions(newUserId, expectOldUserStopping); @@ -701,6 +733,7 @@ public class UserControllerTest { private final IStorageManager mStorageManagerMock; private final UserManagerInternal mUserManagerInternalMock; private final WindowManagerService mWindowManagerMock; + private final KeyguardManager mKeyguardManagerMock; private final Context mCtx; @@ -715,6 +748,8 @@ public class UserControllerTest { mUserManagerInternalMock = mock(UserManagerInternal.class); mWindowManagerMock = mock(WindowManagerService.class); mStorageManagerMock = mock(IStorageManager.class); + mKeyguardManagerMock = mock(KeyguardManager.class); + when(mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true); } @Override @@ -754,6 +789,11 @@ public class UserControllerTest { } @Override + KeyguardManager getKeyguardManager() { + return mKeyguardManagerMock; + } + + @Override void updateUserConfiguration() { Log.i(TAG, "updateUserConfiguration"); } @@ -787,6 +827,11 @@ public class UserControllerTest { protected IStorageManager getStorageManager() { return mStorageManagerMock; } + + @Override + protected void dismissKeyguard(Runnable runnable, String reason) { + runnable.run(); + } } private static class TestHandler extends Handler { |