1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.am;
18 
19 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
20 import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
21 
22 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
23 
24 import static com.android.server.am.UserController.CONTINUE_USER_SWITCH_MSG;
25 import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG;
26 import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG;
27 import static com.android.server.am.UserController.REPORT_USER_SWITCH_MSG;
28 import static com.android.server.am.UserController.USER_CURRENT_MSG;
29 import static com.android.server.am.UserController.USER_START_MSG;
30 import static com.android.server.am.UserController.USER_SWITCH_TIMEOUT_MSG;
31 
32 import static com.google.android.collect.Lists.newArrayList;
33 import static com.google.android.collect.Sets.newHashSet;
34 import static com.google.common.truth.Truth.assertThat;
35 import static com.google.common.truth.Truth.assertWithMessage;
36 
37 import static org.junit.Assert.assertEquals;
38 import static org.junit.Assert.assertFalse;
39 import static org.junit.Assert.assertNotNull;
40 import static org.junit.Assert.assertTrue;
41 import static org.mockito.ArgumentMatchers.anyString;
42 import static org.mockito.Matchers.any;
43 import static org.mockito.Matchers.anyBoolean;
44 import static org.mockito.Matchers.anyInt;
45 import static org.mockito.Matchers.eq;
46 import static org.mockito.Mockito.doAnswer;
47 import static org.mockito.Mockito.doNothing;
48 import static org.mockito.Mockito.doReturn;
49 import static org.mockito.Mockito.mock;
50 import static org.mockito.Mockito.never;
51 import static org.mockito.Mockito.spy;
52 import static org.mockito.Mockito.times;
53 import static org.mockito.Mockito.validateMockitoUsage;
54 import static org.mockito.Mockito.verify;
55 import static org.mockito.Mockito.when;
56 
57 import android.annotation.UserIdInt;
58 import android.app.ActivityManager;
59 import android.app.IUserSwitchObserver;
60 import android.content.Context;
61 import android.content.IIntentReceiver;
62 import android.content.Intent;
63 import android.content.pm.UserInfo;
64 import android.content.pm.UserInfo.UserInfoFlag;
65 import android.os.Binder;
66 import android.os.Bundle;
67 import android.os.Handler;
68 import android.os.HandlerThread;
69 import android.os.IRemoteCallback;
70 import android.os.Looper;
71 import android.os.Message;
72 import android.os.RemoteException;
73 import android.os.UserHandle;
74 import android.os.UserManagerInternal;
75 import android.os.storage.IStorageManager;
76 import android.platform.test.annotations.Presubmit;
77 import android.util.Log;
78 
79 import androidx.test.filters.SmallTest;
80 
81 import com.android.server.FgThread;
82 import com.android.server.am.UserState.KeyEvictedCallback;
83 import com.android.server.pm.UserManagerService;
84 import com.android.server.wm.WindowManagerService;
85 
86 import org.junit.After;
87 import org.junit.Before;
88 import org.junit.Test;
89 
90 import java.util.ArrayList;
91 import java.util.Arrays;
92 import java.util.Collections;
93 import java.util.HashMap;
94 import java.util.LinkedHashSet;
95 import java.util.List;
96 import java.util.Set;
97 
98 /**
99  * Tests for {@link UserController}.
100  *
101  * Build/Install/Run:
102  *  atest FrameworksServicesTests:UserControllerTest
103  */
104 @SmallTest
105 @Presubmit
106 
107 public class UserControllerTest {
108     // Use big enough user id to avoid picking up already active user id.
109     private static final int TEST_USER_ID = 100;
110     private static final int TEST_USER_ID1 = 101;
111     private static final int TEST_USER_ID2 = 102;
112     private static final int TEST_USER_ID3 = 103;
113     private static final int NONEXIST_USER_ID = 2;
114     private static final int TEST_PRE_CREATED_USER_ID = 103;
115 
116     private static final int NO_USERINFO_FLAGS = 0;
117 
118     private static final String TAG = UserControllerTest.class.getSimpleName();
119 
120     private static final long HANDLER_WAIT_TIME_MS = 100;
121 
122     private UserController mUserController;
123     private TestInjector mInjector;
124     private final HashMap<Integer, UserState> mUserStates = new HashMap<>();
125 
126     private final KeyEvictedCallback mKeyEvictedCallback = (userId) -> { /* ignore */ };
127 
128     private static final List<String> START_FOREGROUND_USER_ACTIONS = newArrayList(
129             Intent.ACTION_USER_STARTED,
130             Intent.ACTION_USER_SWITCHED,
131             Intent.ACTION_USER_STARTING);
132 
133     private static final List<String> START_BACKGROUND_USER_ACTIONS = newArrayList(
134             Intent.ACTION_USER_STARTED,
135             Intent.ACTION_LOCKED_BOOT_COMPLETED,
136             Intent.ACTION_USER_STARTING);
137 
138     private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES = newHashSet(
139             REPORT_USER_SWITCH_MSG,
140             USER_SWITCH_TIMEOUT_MSG,
141             USER_START_MSG,
142             USER_CURRENT_MSG);
143 
144     private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES = newHashSet(
145             USER_START_MSG,
146             REPORT_LOCKED_BOOT_COMPLETE_MSG);
147 
148     @Before
setUp()149     public void setUp() throws Exception {
150         runWithDexmakerShareClassLoader(() -> {
151             mInjector = spy(new TestInjector(getInstrumentation().getTargetContext()));
152             doNothing().when(mInjector).clearAllLockedTasks(anyString());
153             doNothing().when(mInjector).startHomeActivity(anyInt(), anyString());
154             doReturn(false).when(mInjector).stackSupervisorSwitchUser(anyInt(), any());
155             doNothing().when(mInjector).stackSupervisorResumeFocusedStackTopActivity();
156             doNothing().when(mInjector).systemServiceManagerCleanupUser(anyInt());
157             doNothing().when(mInjector).activityManagerForceStopPackage(anyInt(), anyString());
158             doNothing().when(mInjector).activityManagerOnUserStopped(anyInt());
159             doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt());
160             doNothing().when(mInjector).stackSupervisorRemoveUser(anyInt());
161             // All UserController params are set to default.
162             mUserController = new UserController(mInjector);
163             setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
164             setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated=*/ true);
165         });
166     }
167 
168     @After
tearDown()169     public void tearDown() throws Exception {
170         mInjector.mHandlerThread.quit();
171         validateMockitoUsage();
172     }
173 
174     @Test
testStartUser_foreground()175     public void testStartUser_foreground() {
176         mUserController.startUser(TEST_USER_ID, true /* foreground */);
177         verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
178         verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
179         verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
180         verify(mInjector.getWindowManager()).setSwitchingUser(true);
181         verify(mInjector).clearAllLockedTasks(anyString());
182         startForegroundUserAssertions();
183     }
184 
185     @Test
testStartUser_background()186     public void testStartUser_background() {
187         mUserController.startUser(TEST_USER_ID, false /* foreground */);
188         verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
189         verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
190         verify(mInjector, never()).clearAllLockedTasks(anyString());
191         startBackgroundUserAssertions();
192     }
193 
194     @Test
testStartUserUIDisabled()195     public void testStartUserUIDisabled() {
196         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ false,
197                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
198 
199         mUserController.startUser(TEST_USER_ID, true /* foreground */);
200         verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
201         verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
202         verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
203         startForegroundUserAssertions();
204     }
205 
206     @Test
testStartPreCreatedUser_foreground()207     public void testStartPreCreatedUser_foreground() {
208         assertFalse(mUserController.startUser(TEST_PRE_CREATED_USER_ID, /* foreground= */ true));
209     }
210 
211     @Test
testStartPreCreatedUser_background()212     public void testStartPreCreatedUser_background() throws Exception {
213         assertTrue(mUserController.startUser(TEST_PRE_CREATED_USER_ID, /* foreground= */ false));
214 
215         verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
216         verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
217         verify(mInjector, never()).clearAllLockedTasks(anyString());
218 
219         assertWithMessage("should not have received intents")
220                 .that(getActions(mInjector.mSentIntents)).isEmpty();
221         // TODO(b/140868593): should have received a USER_UNLOCK_MSG message as well, but it doesn't
222         // because StorageManager.isUserKeyUnlocked(TEST_PRE_CREATED_USER_ID) returns false - to
223         // properly fix it, we'd need to move this class to FrameworksMockingServicesTests so we can
224         // mock static methods (but moving this class would involve changing the presubmit tests,
225         // and the cascade effect goes on...). In fact, a better approach would to not assert the
226         // binder calls, but their side effects (in this case, that the user is stopped right away)
227         assertWithMessage("wrong binder message calls").that(mInjector.mHandler.getMessageCodes())
228                 .containsExactly(USER_START_MSG);
229     }
230 
startUserAssertions( List<String> expectedActions, Set<Integer> expectedMessageCodes)231     private void startUserAssertions(
232             List<String> expectedActions, Set<Integer> expectedMessageCodes) {
233         assertEquals(expectedActions, getActions(mInjector.mSentIntents));
234         Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes();
235         assertEquals("Unexpected message sent", expectedMessageCodes, actualCodes);
236     }
237 
startBackgroundUserAssertions()238     private void startBackgroundUserAssertions() {
239         startUserAssertions(START_BACKGROUND_USER_ACTIONS, START_BACKGROUND_USER_MESSAGE_CODES);
240     }
241 
startForegroundUserAssertions()242     private void startForegroundUserAssertions() {
243         startUserAssertions(START_FOREGROUND_USER_ACTIONS, START_FOREGROUND_USER_MESSAGE_CODES);
244         Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
245         assertNotNull(reportMsg);
246         UserState userState = (UserState) reportMsg.obj;
247         assertNotNull(userState);
248         assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
249         assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
250         assertEquals("Unexpected old user id", 0, reportMsg.arg1);
251         assertEquals("Unexpected new user id", TEST_USER_ID, reportMsg.arg2);
252     }
253 
254     @Test
testFailedStartUserInForeground()255     public void testFailedStartUserInForeground() {
256         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ false,
257                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
258 
259         mUserController.startUserInForeground(NONEXIST_USER_ID);
260         verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
261         verify(mInjector.getWindowManager()).setSwitchingUser(false);
262     }
263 
264     @Test
testDispatchUserSwitch()265     public void testDispatchUserSwitch() throws RemoteException {
266         // Prepare mock observer and register it
267         IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
268         when(observer.asBinder()).thenReturn(new Binder());
269         doAnswer(invocation -> {
270             IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1];
271             callback.sendResult(null);
272             return null;
273         }).when(observer).onUserSwitching(anyInt(), any());
274         mUserController.registerUserSwitchObserver(observer, "mock");
275         // Start user -- this will update state of mUserController
276         mUserController.startUser(TEST_USER_ID, true);
277         Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
278         assertNotNull(reportMsg);
279         UserState userState = (UserState) reportMsg.obj;
280         int oldUserId = reportMsg.arg1;
281         int newUserId = reportMsg.arg2;
282         // Call dispatchUserSwitch and verify that observer was called only once
283         mInjector.mHandler.clearAllRecordedMessages();
284         mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
285         verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
286         Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG);
287         Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes();
288         assertEquals("Unexpected message sent", expectedCodes, actualCodes);
289         Message conMsg = mInjector.mHandler.getMessageForCode(CONTINUE_USER_SWITCH_MSG);
290         assertNotNull(conMsg);
291         userState = (UserState) conMsg.obj;
292         assertNotNull(userState);
293         assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
294         assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
295         assertEquals("Unexpected old user id", 0, conMsg.arg1);
296         assertEquals("Unexpected new user id", TEST_USER_ID, conMsg.arg2);
297     }
298 
299     @Test
testDispatchUserSwitchBadReceiver()300     public void testDispatchUserSwitchBadReceiver() throws RemoteException {
301         // Prepare mock observer which doesn't notify the callback and register it
302         IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
303         when(observer.asBinder()).thenReturn(new Binder());
304         mUserController.registerUserSwitchObserver(observer, "mock");
305         // Start user -- this will update state of mUserController
306         mUserController.startUser(TEST_USER_ID, true);
307         Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
308         assertNotNull(reportMsg);
309         UserState userState = (UserState) reportMsg.obj;
310         int oldUserId = reportMsg.arg1;
311         int newUserId = reportMsg.arg2;
312         // Call dispatchUserSwitch and verify that observer was called only once
313         mInjector.mHandler.clearAllRecordedMessages();
314         mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
315         verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
316         // Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout)
317         Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes();
318         assertWithMessage("No messages should be sent").that(actualCodes).isEmpty();
319     }
320 
321     @Test
testContinueUserSwitch()322     public void testContinueUserSwitch() throws RemoteException {
323         // Start user -- this will update state of mUserController
324         mUserController.startUser(TEST_USER_ID, true);
325         Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
326         assertNotNull(reportMsg);
327         UserState userState = (UserState) reportMsg.obj;
328         int oldUserId = reportMsg.arg1;
329         int newUserId = reportMsg.arg2;
330         mInjector.mHandler.clearAllRecordedMessages();
331         // Verify that continueUserSwitch worked as expected
332         mUserController.continueUserSwitch(userState, oldUserId, newUserId);
333         verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
334         continueUserSwitchAssertions(TEST_USER_ID, false);
335     }
336 
337     @Test
testContinueUserSwitchUIDisabled()338     public void testContinueUserSwitchUIDisabled() throws RemoteException {
339         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ false,
340                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
341 
342         // Start user -- this will update state of mUserController
343         mUserController.startUser(TEST_USER_ID, true);
344         Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
345         assertNotNull(reportMsg);
346         UserState userState = (UserState) reportMsg.obj;
347         int oldUserId = reportMsg.arg1;
348         int newUserId = reportMsg.arg2;
349         mInjector.mHandler.clearAllRecordedMessages();
350         // Verify that continueUserSwitch worked as expected
351         mUserController.continueUserSwitch(userState, oldUserId, newUserId);
352         verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
353         continueUserSwitchAssertions(TEST_USER_ID, false);
354     }
355 
continueUserSwitchAssertions(int expectedUserId, boolean backgroundUserStopping)356     private void continueUserSwitchAssertions(int expectedUserId, boolean backgroundUserStopping)
357             throws RemoteException {
358         Set<Integer> expectedCodes = new LinkedHashSet<>();
359         expectedCodes.add(REPORT_USER_SWITCH_COMPLETE_MSG);
360         if (backgroundUserStopping) {
361             expectedCodes.add(0); // this is for directly posting in stopping.
362         }
363         Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes();
364         assertEquals("Unexpected message sent", expectedCodes, actualCodes);
365         Message msg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_COMPLETE_MSG);
366         assertNotNull(msg);
367         assertEquals("Unexpected userId", expectedUserId, msg.arg1);
368     }
369 
370     @Test
testDispatchUserSwitchComplete()371     public void testDispatchUserSwitchComplete() throws RemoteException {
372         // Prepare mock observer and register it
373         IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
374         when(observer.asBinder()).thenReturn(new Binder());
375         mUserController.registerUserSwitchObserver(observer, "mock");
376         // Start user -- this will update state of mUserController
377         mUserController.startUser(TEST_USER_ID, true);
378         Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
379         assertNotNull(reportMsg);
380         int newUserId = reportMsg.arg2;
381         mInjector.mHandler.clearAllRecordedMessages();
382         // Mockito can't reset only interactions, so just verify that this hasn't been
383         // called with 'false' until after dispatchUserSwitchComplete.
384         verify(mInjector.getWindowManager(), never()).setSwitchingUser(false);
385         // Call dispatchUserSwitchComplete
386         mUserController.dispatchUserSwitchComplete(newUserId);
387         verify(observer, times(1)).onUserSwitchComplete(anyInt());
388         verify(observer).onUserSwitchComplete(TEST_USER_ID);
389         verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(false);
390     }
391 
392     @Test
testExplicitSystenUserStartInBackground()393     public void testExplicitSystenUserStartInBackground() {
394         setUpUser(UserHandle.USER_SYSTEM, 0);
395         assertFalse(mUserController.isSystemUserStarted());
396         assertTrue(mUserController.startUser(UserHandle.USER_SYSTEM, false, null));
397         assertTrue(mUserController.isSystemUserStarted());
398     }
399 
400     /**
401      * Test stopping of user from max running users limit.
402      */
403     @Test
testUserLockingFromUserSwitchingForMultipleUsersNonDelayedLocking()404     public void testUserLockingFromUserSwitchingForMultipleUsersNonDelayedLocking()
405             throws InterruptedException, RemoteException {
406         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
407                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
408 
409         setUpUser(TEST_USER_ID1, 0);
410         setUpUser(TEST_USER_ID2, 0);
411         int numerOfUserSwitches = 1;
412         addForegroundUserAndContinueUserSwitch(TEST_USER_ID, UserHandle.USER_SYSTEM,
413                 numerOfUserSwitches, false);
414         // running: user 0, USER_ID
415         assertTrue(mUserController.canStartMoreUsers());
416         assertEquals(Arrays.asList(new Integer[] {0, TEST_USER_ID}),
417                 mUserController.getRunningUsersLU());
418 
419         numerOfUserSwitches++;
420         addForegroundUserAndContinueUserSwitch(TEST_USER_ID1, TEST_USER_ID,
421                 numerOfUserSwitches, false);
422         // running: user 0, USER_ID, USER_ID1
423         assertFalse(mUserController.canStartMoreUsers());
424         assertEquals(Arrays.asList(new Integer[] {0, TEST_USER_ID, TEST_USER_ID1}),
425                 mUserController.getRunningUsersLU());
426 
427         numerOfUserSwitches++;
428         addForegroundUserAndContinueUserSwitch(TEST_USER_ID2, TEST_USER_ID1,
429                 numerOfUserSwitches, false);
430         UserState ussUser2 = mUserStates.get(TEST_USER_ID2);
431         // skip middle step and call this directly.
432         mUserController.finishUserSwitch(ussUser2);
433         waitForHandlerToComplete(mInjector.mHandler, HANDLER_WAIT_TIME_MS);
434         // running: user 0, USER_ID1, USER_ID2
435         // USER_ID should be stopped as it is least recently used non user0.
436         assertFalse(mUserController.canStartMoreUsers());
437         assertEquals(Arrays.asList(new Integer[] {0, TEST_USER_ID1, TEST_USER_ID2}),
438                 mUserController.getRunningUsersLU());
439     }
440 
441     /**
442      * This test tests delayed locking mode using 4 users. As core logic of delayed locking is
443      * happening in finishUserStopped call, the test also calls finishUserStopped while skipping
444      * all middle steps which takes too much work to mock.
445      */
446     @Test
testUserLockingFromUserSwitchingForMultipleUsersDelayedLockingMode()447     public void testUserLockingFromUserSwitchingForMultipleUsersDelayedLockingMode()
448             throws InterruptedException, RemoteException {
449         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
450                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ true);
451 
452         setUpUser(TEST_USER_ID1, 0);
453         setUpUser(TEST_USER_ID2, 0);
454         int numerOfUserSwitches = 1;
455         addForegroundUserAndContinueUserSwitch(TEST_USER_ID, UserHandle.USER_SYSTEM,
456                 numerOfUserSwitches, false);
457         // running: user 0, USER_ID
458         assertTrue(mUserController.canStartMoreUsers());
459         assertEquals(Arrays.asList(new Integer[] {0, TEST_USER_ID}),
460                 mUserController.getRunningUsersLU());
461         numerOfUserSwitches++;
462 
463         addForegroundUserAndContinueUserSwitch(TEST_USER_ID1, TEST_USER_ID,
464                 numerOfUserSwitches, true);
465         // running: user 0, USER_ID1
466         // stopped + unlocked: USER_ID
467         numerOfUserSwitches++;
468         assertTrue(mUserController.canStartMoreUsers());
469         assertEquals(Arrays.asList(new Integer[] {0, TEST_USER_ID1}),
470                 mUserController.getRunningUsersLU());
471         // Skip all other steps and test unlock delaying only
472         UserState uss = mUserStates.get(TEST_USER_ID);
473         uss.setState(UserState.STATE_SHUTDOWN); // necessary state change from skipped part
474         mUserController.finishUserStopped(uss, /* allowDelayedLocking= */ true);
475         // Cannot mock FgThread handler, so confirm that there is no posted message left before
476         // checking.
477         waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS);
478         verify(mInjector.mStorageManagerMock, times(0))
479                 .lockUserKey(anyInt());
480 
481         addForegroundUserAndContinueUserSwitch(TEST_USER_ID2, TEST_USER_ID1,
482                 numerOfUserSwitches, true);
483         // running: user 0, USER_ID2
484         // stopped + unlocked: USER_ID1
485         // stopped + locked: USER_ID
486         assertTrue(mUserController.canStartMoreUsers());
487         assertEquals(Arrays.asList(new Integer[] {0, TEST_USER_ID2}),
488                 mUserController.getRunningUsersLU());
489         UserState ussUser1 = mUserStates.get(TEST_USER_ID1);
490         ussUser1.setState(UserState.STATE_SHUTDOWN);
491         mUserController.finishUserStopped(ussUser1, /* allowDelayedLocking= */ true);
492         waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS);
493         verify(mInjector.mStorageManagerMock, times(1))
494                 .lockUserKey(TEST_USER_ID);
495     }
496 
497     /**
498      * Test locking user with mDelayUserDataLocking false.
499      */
500     @Test
testUserLockingWithStopUserForNonDelayedLockingMode()501     public void testUserLockingWithStopUserForNonDelayedLockingMode() throws Exception {
502         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
503                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
504 
505         setUpAndStartUserInBackground(TEST_USER_ID);
506         assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID, /* delayedLocking= */ true,
507                 /* keyEvictedCallback= */ null, /* expectLocking= */ true);
508 
509         setUpAndStartUserInBackground(TEST_USER_ID1);
510         assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
511                 /* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);
512 
513         setUpAndStartUserInBackground(TEST_USER_ID2);
514         assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* delayedLocking= */ false,
515                 /* keyEvictedCallback= */ null, /* expectLocking= */ true);
516 
517         setUpAndStartUserInBackground(TEST_USER_ID3);
518         assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID3, /* delayedLocking= */ false,
519                 /* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);
520     }
521 
522     /**
523      * Test conditional delayed locking with mDelayUserDataLocking true.
524      */
525     @Test
testUserLockingForDelayedLockingMode()526     public void testUserLockingForDelayedLockingMode() throws Exception {
527         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
528                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ true);
529 
530         // delayedLocking set and no KeyEvictedCallback, so it should not lock.
531         setUpAndStartUserInBackground(TEST_USER_ID);
532         assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID, /* delayedLocking= */ true,
533                 /* keyEvictedCallback= */ null, /* expectLocking= */ false);
534 
535         setUpAndStartUserInBackground(TEST_USER_ID1);
536         assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* delayedLocking= */ true,
537                 /* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);
538 
539         setUpAndStartUserInBackground(TEST_USER_ID2);
540         assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID2, /* delayedLocking= */ false,
541                 /* keyEvictedCallback= */ null, /* expectLocking= */ true);
542 
543         setUpAndStartUserInBackground(TEST_USER_ID3);
544         assertUserLockedOrUnlockedAfterStopping(TEST_USER_ID3, /* delayedLocking= */ false,
545                 /* keyEvictedCallback= */ mKeyEvictedCallback, /* expectLocking= */ true);
546     }
547 
setUpAndStartUserInBackground(int userId)548     private void setUpAndStartUserInBackground(int userId) throws Exception {
549         setUpUser(userId, 0);
550         mUserController.startUser(userId, /* foreground= */ false);
551         verify(mInjector.mStorageManagerMock, times(1))
552                 .unlockUserKey(TEST_USER_ID, 0, null, null);
553         mUserStates.put(userId, mUserController.getStartedUserState(userId));
554     }
555 
assertUserLockedOrUnlockedAfterStopping(int userId, boolean delayedLocking, KeyEvictedCallback keyEvictedCallback, boolean expectLocking)556     private void assertUserLockedOrUnlockedAfterStopping(int userId, boolean delayedLocking,
557             KeyEvictedCallback keyEvictedCallback, boolean expectLocking)  throws Exception {
558         int r = mUserController.stopUser(userId, /* force= */ true, /* delayedLocking= */
559                 delayedLocking, null, keyEvictedCallback);
560         assertThat(r).isEqualTo(ActivityManager.USER_OP_SUCCESS);
561         // fake all interim steps
562         UserState ussUser = mUserStates.get(userId);
563         ussUser.setState(UserState.STATE_SHUTDOWN);
564         // Passing delayedLocking invalidates incorrect internal data passing but currently there is
565         // no easy way to get that information passed through lambda.
566         mUserController.finishUserStopped(ussUser, delayedLocking);
567         waitForHandlerToComplete(FgThread.getHandler(), HANDLER_WAIT_TIME_MS);
568         verify(mInjector.mStorageManagerMock, times(expectLocking ? 1 : 0))
569                 .lockUserKey(userId);
570     }
571 
addForegroundUserAndContinueUserSwitch(int newUserId, int expectedOldUserId, int expectedNumberOfCalls, boolean expectOldUserStopping)572     private void addForegroundUserAndContinueUserSwitch(int newUserId, int expectedOldUserId,
573             int expectedNumberOfCalls, boolean expectOldUserStopping)
574             throws RemoteException {
575         // Start user -- this will update state of mUserController
576         mUserController.startUser(newUserId, true);
577         Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
578         assertNotNull(reportMsg);
579         UserState userState = (UserState) reportMsg.obj;
580         int oldUserId = reportMsg.arg1;
581         assertEquals(expectedOldUserId, oldUserId);
582         assertEquals(newUserId, reportMsg.arg2);
583         mUserStates.put(newUserId, userState);
584         mInjector.mHandler.clearAllRecordedMessages();
585         // Verify that continueUserSwitch worked as expected
586         mUserController.continueUserSwitch(userState, oldUserId, newUserId);
587         verify(mInjector.getWindowManager(), times(expectedNumberOfCalls))
588                 .stopFreezingScreen();
589         continueUserSwitchAssertions(newUserId, expectOldUserStopping);
590     }
591 
setUpUser(@serIdInt int userId, @UserInfoFlag int flags)592     private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags) {
593         setUpUser(userId, flags, /* preCreated= */ false);
594     }
595 
setUpUser(@serIdInt int userId, @UserInfoFlag int flags, boolean preCreated)596     private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags, boolean preCreated) {
597         UserInfo userInfo = new UserInfo(userId, "User" + userId, flags);
598         userInfo.preCreated = preCreated;
599         when(mInjector.mUserManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo);
600         when(mInjector.mUserManagerMock.isPreCreated(userId)).thenReturn(preCreated);
601     }
602 
getActions(List<Intent> intents)603     private static List<String> getActions(List<Intent> intents) {
604         List<String> result = new ArrayList<>();
605         for (Intent intent : intents) {
606             result.add(intent.getAction());
607         }
608         return result;
609     }
610 
waitForHandlerToComplete(Handler handler, long waitTimeMs)611     private void waitForHandlerToComplete(Handler handler, long waitTimeMs)
612             throws InterruptedException {
613         final Object lock = new Object();
614         synchronized (lock) {
615             handler.post(() -> {
616                 synchronized (lock) {
617                     lock.notify();
618                 }
619             });
620             lock.wait(waitTimeMs);
621         }
622     }
623 
624     // Should be public to allow mocking
625     private static class TestInjector extends UserController.Injector {
626         public final TestHandler mHandler;
627         public final HandlerThread mHandlerThread;
628         public final UserManagerService mUserManagerMock;
629         public final List<Intent> mSentIntents = new ArrayList<>();
630 
631         private final TestHandler mUiHandler;
632 
633         private final IStorageManager mStorageManagerMock;
634         private final UserManagerInternal mUserManagerInternalMock;
635         private final WindowManagerService mWindowManagerMock;
636 
637         private final Context mCtx;
638 
TestInjector(Context ctx)639         TestInjector(Context ctx) {
640             super(null);
641             mCtx = ctx;
642             mHandlerThread = new HandlerThread(TAG);
643             mHandlerThread.start();
644             mHandler = new TestHandler(mHandlerThread.getLooper());
645             mUiHandler = new TestHandler(mHandlerThread.getLooper());
646             mUserManagerMock = mock(UserManagerService.class);
647             mUserManagerInternalMock = mock(UserManagerInternal.class);
648             mWindowManagerMock = mock(WindowManagerService.class);
649             mStorageManagerMock = mock(IStorageManager.class);
650         }
651 
652         @Override
getHandler(Handler.Callback callback)653         protected Handler getHandler(Handler.Callback callback) {
654             return mHandler;
655         }
656 
657         @Override
getUiHandler(Handler.Callback callback)658         protected Handler getUiHandler(Handler.Callback callback) {
659             return mUiHandler;
660         }
661 
662         @Override
getUserManager()663         protected UserManagerService getUserManager() {
664             return mUserManagerMock;
665         }
666 
667         @Override
getUserManagerInternal()668         UserManagerInternal getUserManagerInternal() {
669             return mUserManagerInternalMock;
670         }
671 
672         @Override
getContext()673         protected Context getContext() {
674             return mCtx;
675         }
676 
677         @Override
checkCallingPermission(String permission)678         int checkCallingPermission(String permission) {
679             Log.i(TAG, "checkCallingPermission " + permission);
680             return PERMISSION_GRANTED;
681         }
682 
683         @Override
getWindowManager()684         WindowManagerService getWindowManager() {
685             return mWindowManagerMock;
686         }
687 
688         @Override
updateUserConfiguration()689         void updateUserConfiguration() {
690             Log.i(TAG, "updateUserConfiguration");
691         }
692 
693         @Override
broadcastIntent(Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid, int realCallingPid, int userId)694         protected int broadcastIntent(Intent intent, String resolvedType,
695                 IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
696                 String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered,
697                 boolean sticky, int callingPid, int callingUid, int realCallingUid,
698                 int realCallingPid, int userId) {
699             Log.i(TAG, "broadcastIntentLocked " + intent);
700             mSentIntents.add(intent);
701             return 0;
702         }
703 
704         @Override
reportGlobalUsageEventLocked(int event)705         void reportGlobalUsageEventLocked(int event) {
706         }
707 
708         @Override
reportCurWakefulnessUsageEvent()709         void reportCurWakefulnessUsageEvent() {
710         }
711 
712         @Override
isRuntimeRestarted()713         boolean isRuntimeRestarted() {
714             // to pass all metrics related calls
715             return true;
716         }
717 
718         @Override
getStorageManager()719         protected IStorageManager getStorageManager() {
720             return mStorageManagerMock;
721         }
722     }
723 
724     private static class TestHandler extends Handler {
725         private final List<Message> mMessages = new ArrayList<>();
726 
TestHandler(Looper looper)727         TestHandler(Looper looper) {
728             super(looper);
729         }
730 
getMessageCodes()731         Set<Integer> getMessageCodes() {
732             Set<Integer> result = new LinkedHashSet<>();
733             for (Message msg : mMessages) {
734                 result.add(msg.what);
735             }
736             return result;
737         }
738 
getMessageForCode(int what)739         Message getMessageForCode(int what) {
740             for (Message msg : mMessages) {
741                 if (msg.what == what) {
742                     return msg;
743                 }
744             }
745             return null;
746         }
747 
clearAllRecordedMessages()748         void clearAllRecordedMessages() {
749             mMessages.clear();
750         }
751 
752         @Override
sendMessageAtTime(Message msg, long uptimeMillis)753         public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
754             Message copy = new Message();
755             copy.copyFrom(msg);
756             mMessages.add(copy);
757             return super.sendMessageAtTime(msg, uptimeMillis);
758         }
759     }
760 }
761