Loading services/core/java/com/android/server/am/UserController.java +47 −1 Original line number Diff line number Diff line Loading @@ -151,6 +151,8 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; Loading Loading @@ -1707,7 +1709,8 @@ class UserController implements Handler.Callback { mInjector.getWindowManager().setSwitchingUser(true); // Only lock if the user has a secure keyguard PIN/Pattern/Pwd if (mInjector.getKeyguardManager().isDeviceSecure(userId)) { mInjector.getWindowManager().lockNow(null); // Make sure the device is locked before moving on with the user switch mInjector.lockDeviceNowAndWaitForKeyguardShown(); } } Loading Loading @@ -3444,6 +3447,11 @@ class UserController implements Handler.Callback { WindowManagerService getWindowManager() { return mService.mWindowManager; } ActivityTaskManagerInternal getActivityTaskManagerInternal() { return mService.mAtmInternal; } void activityManagerOnUserStopped(@UserIdInt int userId) { LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId); } Loading Loading @@ -3667,5 +3675,43 @@ class UserController implements Handler.Callback { void onSystemUserVisibilityChanged(boolean visible) { getUserManagerInternal().onSystemUserVisibilityChanged(visible); } void lockDeviceNowAndWaitForKeyguardShown() { if (getWindowManager().isKeyguardLocked()) { return; } final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("lockDeviceNowAndWaitForKeyguardShown"); final CountDownLatch latch = new CountDownLatch(1); ActivityTaskManagerInternal.ScreenObserver screenObserver = new ActivityTaskManagerInternal.ScreenObserver() { @Override public void onAwakeStateChanged(boolean isAwake) { } @Override public void onKeyguardStateChanged(boolean isShowing) { if (isShowing) { latch.countDown(); } } }; getActivityTaskManagerInternal().registerScreenObserver(screenObserver); getWindowManager().lockDeviceNow(); try { if (!latch.await(20, TimeUnit.SECONDS)) { throw new RuntimeException("Keyguard is not shown in 20 seconds"); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { getActivityTaskManagerInternal().unregisterScreenObserver(screenObserver); t.traceEnd(); } } } } services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +8 −0 Original line number Diff line number Diff line Loading @@ -262,8 +262,16 @@ public abstract class ActivityTaskManagerInternal { */ public abstract void setVr2dDisplayId(int vr2dDisplayId); /** * Registers a {@link ScreenObserver}. */ public abstract void registerScreenObserver(ScreenObserver observer); /** * Unregisters the given {@link ScreenObserver}. */ public abstract void unregisterScreenObserver(ScreenObserver observer); /** * Returns is the caller has the same uid as the Recents component */ Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +8 −1 Original line number Diff line number Diff line Loading @@ -296,6 +296,7 @@ import java.text.DateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; Loading Loading @@ -652,7 +653,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ float mMinPercentageMultiWindowSupportWidth; final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>(); final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = Collections.synchronizedList(new ArrayList<>()); // VR Vr2d Display Id. int mVr2dDisplayId = INVALID_DISPLAY; Loading Loading @@ -5868,6 +5870,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mScreenObservers.add(observer); } @Override public void unregisterScreenObserver(ScreenObserver observer) { mScreenObservers.remove(observer); } @Override public boolean isCallerRecents(int callingUid) { return ActivityTaskManagerService.this.isCallerRecents(callingUid); Loading services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +50 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; Loading Loading @@ -103,11 +104,13 @@ import com.android.server.am.UserState.KeyEvictedCallback; import com.android.server.pm.UserJourneyLogger; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.UserManagerService; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.WindowManagerService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -187,6 +190,7 @@ public class UserControllerTest { doNothing().when(mInjector).activityManagerOnUserStopped(anyInt()); doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt()); doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt()); doNothing().when(mInjector).lockDeviceNowAndWaitForKeyguardShown(); mockIsUsersOnSecondaryDisplaysEnabled(false); // All UserController params are set to default. Loading Loading @@ -951,6 +955,45 @@ public class UserControllerTest { .systemServiceManagerOnUserCompletedEvent(eq(user2), eq(event2a)); } @Test public void testStallUserSwitchUntilTheKeyguardIsShown() throws Exception { // enable user switch ui, because keyguard is only shown then mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true, /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false); // mock the device to be secure in order to expect the keyguard to be shown when(mInjector.mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true); // call real lockDeviceNowAndWaitForKeyguardShown method for this test doCallRealMethod().when(mInjector).lockDeviceNowAndWaitForKeyguardShown(); // call startUser on a thread because we're expecting it to be blocked Thread threadStartUser = new Thread(()-> { mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); }); threadStartUser.start(); // make sure the switch is stalled... Thread.sleep(2000); // by checking REPORT_USER_SWITCH_MSG is not sent yet assertNull(mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG)); // and the thread is still alive assertTrue(threadStartUser.isAlive()); // mock send the keyguard shown event ArgumentCaptor<ActivityTaskManagerInternal.ScreenObserver> captor = ArgumentCaptor.forClass( ActivityTaskManagerInternal.ScreenObserver.class); verify(mInjector.mActivityTaskManagerInternal).registerScreenObserver(captor.capture()); captor.getValue().onKeyguardStateChanged(true); // verify the switch now moves on... Thread.sleep(1000); // by checking REPORT_USER_SWITCH_MSG is sent assertNotNull(mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG)); // and the thread is finished assertFalse(threadStartUser.isAlive()); } private void setUpAndStartUserInBackground(int userId) throws Exception { setUpUser(userId, 0); mUserController.startUser(userId, USER_START_MODE_BACKGROUND); Loading Loading @@ -1092,6 +1135,7 @@ public class UserControllerTest { private final IStorageManager mStorageManagerMock; private final UserManagerInternal mUserManagerInternalMock; private final WindowManagerService mWindowManagerMock; private final ActivityTaskManagerInternal mActivityTaskManagerInternal; private final KeyguardManager mKeyguardManagerMock; private final LockPatternUtils mLockPatternUtilsMock; Loading @@ -1111,6 +1155,7 @@ public class UserControllerTest { mUserManagerMock = mock(UserManagerService.class); mUserManagerInternalMock = mock(UserManagerInternal.class); mWindowManagerMock = mock(WindowManagerService.class); mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class); mStorageManagerMock = mock(IStorageManager.class); mKeyguardManagerMock = mock(KeyguardManager.class); when(mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true); Loading Loading @@ -1171,6 +1216,11 @@ public class UserControllerTest { return mWindowManagerMock; } @Override ActivityTaskManagerInternal getActivityTaskManagerInternal() { return mActivityTaskManagerInternal; } @Override KeyguardManager getKeyguardManager() { return mKeyguardManagerMock; Loading Loading
services/core/java/com/android/server/am/UserController.java +47 −1 Original line number Diff line number Diff line Loading @@ -151,6 +151,8 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; Loading Loading @@ -1707,7 +1709,8 @@ class UserController implements Handler.Callback { mInjector.getWindowManager().setSwitchingUser(true); // Only lock if the user has a secure keyguard PIN/Pattern/Pwd if (mInjector.getKeyguardManager().isDeviceSecure(userId)) { mInjector.getWindowManager().lockNow(null); // Make sure the device is locked before moving on with the user switch mInjector.lockDeviceNowAndWaitForKeyguardShown(); } } Loading Loading @@ -3444,6 +3447,11 @@ class UserController implements Handler.Callback { WindowManagerService getWindowManager() { return mService.mWindowManager; } ActivityTaskManagerInternal getActivityTaskManagerInternal() { return mService.mAtmInternal; } void activityManagerOnUserStopped(@UserIdInt int userId) { LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId); } Loading Loading @@ -3667,5 +3675,43 @@ class UserController implements Handler.Callback { void onSystemUserVisibilityChanged(boolean visible) { getUserManagerInternal().onSystemUserVisibilityChanged(visible); } void lockDeviceNowAndWaitForKeyguardShown() { if (getWindowManager().isKeyguardLocked()) { return; } final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("lockDeviceNowAndWaitForKeyguardShown"); final CountDownLatch latch = new CountDownLatch(1); ActivityTaskManagerInternal.ScreenObserver screenObserver = new ActivityTaskManagerInternal.ScreenObserver() { @Override public void onAwakeStateChanged(boolean isAwake) { } @Override public void onKeyguardStateChanged(boolean isShowing) { if (isShowing) { latch.countDown(); } } }; getActivityTaskManagerInternal().registerScreenObserver(screenObserver); getWindowManager().lockDeviceNow(); try { if (!latch.await(20, TimeUnit.SECONDS)) { throw new RuntimeException("Keyguard is not shown in 20 seconds"); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { getActivityTaskManagerInternal().unregisterScreenObserver(screenObserver); t.traceEnd(); } } } }
services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +8 −0 Original line number Diff line number Diff line Loading @@ -262,8 +262,16 @@ public abstract class ActivityTaskManagerInternal { */ public abstract void setVr2dDisplayId(int vr2dDisplayId); /** * Registers a {@link ScreenObserver}. */ public abstract void registerScreenObserver(ScreenObserver observer); /** * Unregisters the given {@link ScreenObserver}. */ public abstract void unregisterScreenObserver(ScreenObserver observer); /** * Returns is the caller has the same uid as the Recents component */ Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +8 −1 Original line number Diff line number Diff line Loading @@ -296,6 +296,7 @@ import java.text.DateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; Loading Loading @@ -652,7 +653,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ float mMinPercentageMultiWindowSupportWidth; final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>(); final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = Collections.synchronizedList(new ArrayList<>()); // VR Vr2d Display Id. int mVr2dDisplayId = INVALID_DISPLAY; Loading Loading @@ -5868,6 +5870,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mScreenObservers.add(observer); } @Override public void unregisterScreenObserver(ScreenObserver observer) { mScreenObservers.remove(observer); } @Override public boolean isCallerRecents(int callingUid) { return ActivityTaskManagerService.this.isCallerRecents(callingUid); Loading
services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +50 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; Loading Loading @@ -103,11 +104,13 @@ import com.android.server.am.UserState.KeyEvictedCallback; import com.android.server.pm.UserJourneyLogger; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.UserManagerService; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.WindowManagerService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -187,6 +190,7 @@ public class UserControllerTest { doNothing().when(mInjector).activityManagerOnUserStopped(anyInt()); doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt()); doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt()); doNothing().when(mInjector).lockDeviceNowAndWaitForKeyguardShown(); mockIsUsersOnSecondaryDisplaysEnabled(false); // All UserController params are set to default. Loading Loading @@ -951,6 +955,45 @@ public class UserControllerTest { .systemServiceManagerOnUserCompletedEvent(eq(user2), eq(event2a)); } @Test public void testStallUserSwitchUntilTheKeyguardIsShown() throws Exception { // enable user switch ui, because keyguard is only shown then mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true, /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false); // mock the device to be secure in order to expect the keyguard to be shown when(mInjector.mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true); // call real lockDeviceNowAndWaitForKeyguardShown method for this test doCallRealMethod().when(mInjector).lockDeviceNowAndWaitForKeyguardShown(); // call startUser on a thread because we're expecting it to be blocked Thread threadStartUser = new Thread(()-> { mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); }); threadStartUser.start(); // make sure the switch is stalled... Thread.sleep(2000); // by checking REPORT_USER_SWITCH_MSG is not sent yet assertNull(mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG)); // and the thread is still alive assertTrue(threadStartUser.isAlive()); // mock send the keyguard shown event ArgumentCaptor<ActivityTaskManagerInternal.ScreenObserver> captor = ArgumentCaptor.forClass( ActivityTaskManagerInternal.ScreenObserver.class); verify(mInjector.mActivityTaskManagerInternal).registerScreenObserver(captor.capture()); captor.getValue().onKeyguardStateChanged(true); // verify the switch now moves on... Thread.sleep(1000); // by checking REPORT_USER_SWITCH_MSG is sent assertNotNull(mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG)); // and the thread is finished assertFalse(threadStartUser.isAlive()); } private void setUpAndStartUserInBackground(int userId) throws Exception { setUpUser(userId, 0); mUserController.startUser(userId, USER_START_MODE_BACKGROUND); Loading Loading @@ -1092,6 +1135,7 @@ public class UserControllerTest { private final IStorageManager mStorageManagerMock; private final UserManagerInternal mUserManagerInternalMock; private final WindowManagerService mWindowManagerMock; private final ActivityTaskManagerInternal mActivityTaskManagerInternal; private final KeyguardManager mKeyguardManagerMock; private final LockPatternUtils mLockPatternUtilsMock; Loading @@ -1111,6 +1155,7 @@ public class UserControllerTest { mUserManagerMock = mock(UserManagerService.class); mUserManagerInternalMock = mock(UserManagerInternal.class); mWindowManagerMock = mock(WindowManagerService.class); mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class); mStorageManagerMock = mock(IStorageManager.class); mKeyguardManagerMock = mock(KeyguardManager.class); when(mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true); Loading Loading @@ -1171,6 +1216,11 @@ public class UserControllerTest { return mWindowManagerMock; } @Override ActivityTaskManagerInternal getActivityTaskManagerInternal() { return mActivityTaskManagerInternal; } @Override KeyguardManager getKeyguardManager() { return mKeyguardManagerMock; Loading