Merge "Wait for keyguard to be shown before completing the user switch." into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
df14a8f71f
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -1171,6 +1216,11 @@ public class UserControllerTest {
|
||||
return mWindowManagerMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
ActivityTaskManagerInternal getActivityTaskManagerInternal() {
|
||||
return mActivityTaskManagerInternal;
|
||||
}
|
||||
|
||||
@Override
|
||||
KeyguardManager getKeyguardManager() {
|
||||
return mKeyguardManagerMock;
|
||||
|
||||
Reference in New Issue
Block a user