Merge "Wait for keyguard to be shown before completing the user switch." into udc-dev

This commit is contained in:
Yasin Kilicdere
2023-05-25 15:32:35 +00:00
committed by Android (Google) Code Review
4 changed files with 113 additions and 2 deletions

View File

@@ -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();
}
}
}
}

View File

@@ -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
*/

View File

@@ -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);

View File

@@ -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;