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 android.app.ActivityManager;
20 import android.app.IUserSwitchObserver;
21 import android.content.Context;
22 import android.content.IIntentReceiver;
23 import android.content.Intent;
24 import android.content.pm.UserInfo;
25 import android.os.Binder;
26 import android.os.Bundle;
27 import android.os.Handler;
28 import android.os.HandlerThread;
29 import android.os.IRemoteCallback;
30 import android.os.Looper;
31 import android.os.Message;
32 import android.os.RemoteException;
33 import android.os.UserManagerInternal;
34 import android.test.AndroidTestCase;
35 import android.test.suitebuilder.annotation.SmallTest;
36 import android.util.Log;
37 
38 import com.android.server.pm.UserManagerService;
39 import com.android.server.wm.WindowManagerService;
40 
41 import org.mockito.Mockito;
42 
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collections;
46 import java.util.HashSet;
47 import java.util.LinkedHashSet;
48 import java.util.List;
49 import java.util.Set;
50 
51 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
52 import static com.android.server.am.ActivityManagerService.CONTINUE_USER_SWITCH_MSG;
53 import static com.android.server.am.ActivityManagerService.REPORT_LOCKED_BOOT_COMPLETE_MSG;
54 import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG;
55 import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG;
56 import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
57 import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG;
58 import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG;
59 import static org.mockito.ArgumentMatchers.anyString;
60 import static org.mockito.ArgumentMatchers.nullable;
61 import static org.mockito.Matchers.any;
62 import static org.mockito.Matchers.anyBoolean;
63 import static org.mockito.Matchers.anyInt;
64 import static org.mockito.Matchers.eq;
65 import static org.mockito.Mockito.doAnswer;
66 import static org.mockito.Mockito.doNothing;
67 import static org.mockito.Mockito.mock;
68 import static org.mockito.Mockito.never;
69 import static org.mockito.Mockito.times;
70 import static org.mockito.Mockito.when;
71 
72 public class UserControllerTest extends AndroidTestCase {
73     private static final int TEST_USER_ID = 10;
74     private static final int NONEXIST_USER_ID = 2;
75     private static String TAG = UserControllerTest.class.getSimpleName();
76     private UserController mUserController;
77     private TestInjector mInjector;
78 
79     private static final List<String> START_FOREGROUND_USER_ACTIONS =
80             Arrays.asList(
81                     Intent.ACTION_USER_STARTED,
82                     Intent.ACTION_USER_SWITCHED,
83                     Intent.ACTION_USER_STARTING);
84 
85     private static final List<String> START_BACKGROUND_USER_ACTIONS =
86             Arrays.asList(
87                     Intent.ACTION_USER_STARTED,
88                     Intent.ACTION_LOCKED_BOOT_COMPLETED,
89                     Intent.ACTION_USER_STARTING);
90 
91     private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES =
92             new HashSet<>(Arrays.asList(REPORT_USER_SWITCH_MSG, USER_SWITCH_TIMEOUT_MSG,
93                     SYSTEM_USER_START_MSG, SYSTEM_USER_CURRENT_MSG));
94 
95     private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES =
96             new HashSet<>(Arrays.asList(SYSTEM_USER_START_MSG, REPORT_LOCKED_BOOT_COMPLETE_MSG));
97 
98     @Override
setUp()99     public void setUp() throws Exception {
100         super.setUp();
101         System.setProperty("dexmaker.share_classloader", "true");
102         mInjector = new TestInjector(getContext());
103         mUserController = new UserController(mInjector);
104         setUpUser(TEST_USER_ID, 0);
105     }
106 
107     @Override
tearDown()108     protected void tearDown() throws Exception {
109         super.tearDown();
110         mInjector.handlerThread.quit();
111     }
112 
113     @SmallTest
testStartUser_foreground()114     public void testStartUser_foreground() throws RemoteException {
115         mUserController.startUser(TEST_USER_ID, true /* foreground */);
116         Mockito.verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
117         Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
118         Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
119         Mockito.verify(mInjector.getWindowManager()).setSwitchingUser(true);
120         Mockito.verify(mInjector.getActivityStackSupervisor()).setLockTaskModeLocked(
121                 nullable(TaskRecord.class),
122                 eq(ActivityManager.LOCK_TASK_MODE_NONE),
123                 anyString(),
124                 anyBoolean());
125         startForegroundUserAssertions();
126     }
127 
128     @SmallTest
testStartUser_background()129     public void testStartUser_background() throws RemoteException {
130         mUserController.startUser(TEST_USER_ID, false /* foreground */);
131         Mockito.verify(
132                 mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
133         Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
134         Mockito.verify(mInjector.getActivityStackSupervisor(), never()).setLockTaskModeLocked(
135                 nullable(TaskRecord.class),
136                 eq(ActivityManager.LOCK_TASK_MODE_NONE),
137                 anyString(),
138                 anyBoolean());
139         startBackgroundUserAssertions();
140     }
141 
142     @SmallTest
testStartUserUIDisabled()143     public void testStartUserUIDisabled() throws RemoteException {
144         mUserController.mUserSwitchUiEnabled = false;
145         mUserController.startUser(TEST_USER_ID, true /* foreground */);
146         Mockito.verify(mInjector.getWindowManager(), never())
147                 .startFreezingScreen(anyInt(), anyInt());
148         Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
149         Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
150         startForegroundUserAssertions();
151     }
152 
startUserAssertions( List<String> expectedActions, Set<Integer> expectedMessageCodes)153     private void startUserAssertions(
154             List<String> expectedActions, Set<Integer> expectedMessageCodes)
155             throws RemoteException {
156         assertEquals(expectedActions, getActions(mInjector.sentIntents));
157         Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
158         assertEquals("Unexpected message sent", expectedMessageCodes, actualCodes);
159     }
160 
startBackgroundUserAssertions()161     private void startBackgroundUserAssertions() throws RemoteException {
162         startUserAssertions(START_BACKGROUND_USER_ACTIONS, START_BACKGROUND_USER_MESSAGE_CODES);
163     }
164 
startForegroundUserAssertions()165     private void startForegroundUserAssertions() throws RemoteException {
166         startUserAssertions(START_FOREGROUND_USER_ACTIONS, START_FOREGROUND_USER_MESSAGE_CODES);
167         Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
168         assertNotNull(reportMsg);
169         UserState userState = (UserState) reportMsg.obj;
170         assertNotNull(userState);
171         assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
172         assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
173         assertEquals("Unexpected old user id", 0, reportMsg.arg1);
174         assertEquals("Unexpected new user id", TEST_USER_ID, reportMsg.arg2);
175     }
176 
177     @SmallTest
testFailedStartUserInForeground()178     public void testFailedStartUserInForeground() throws RemoteException {
179         mUserController.mUserSwitchUiEnabled = false;
180         mUserController.startUserInForeground(NONEXIST_USER_ID);
181         Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
182         Mockito.verify(mInjector.getWindowManager()).setSwitchingUser(false);
183     }
184 
185     @SmallTest
testDispatchUserSwitch()186     public void testDispatchUserSwitch() throws RemoteException {
187         // Prepare mock observer and register it
188         IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
189         when(observer.asBinder()).thenReturn(new Binder());
190         doAnswer(invocation -> {
191             IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1];
192             callback.sendResult(null);
193             return null;
194         }).when(observer).onUserSwitching(anyInt(), any());
195         mUserController.registerUserSwitchObserver(observer, "mock");
196         // Start user -- this will update state of mUserController
197         mUserController.startUser(TEST_USER_ID, true);
198         Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
199         assertNotNull(reportMsg);
200         UserState userState = (UserState) reportMsg.obj;
201         int oldUserId = reportMsg.arg1;
202         int newUserId = reportMsg.arg2;
203         // Call dispatchUserSwitch and verify that observer was called only once
204         mInjector.handler.clearAllRecordedMessages();
205         mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
206         Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
207         Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG);
208         Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
209         assertEquals("Unexpected message sent", expectedCodes, actualCodes);
210         Message conMsg = mInjector.handler.getMessageForCode(CONTINUE_USER_SWITCH_MSG);
211         assertNotNull(conMsg);
212         userState = (UserState) conMsg.obj;
213         assertNotNull(userState);
214         assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
215         assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
216         assertEquals("Unexpected old user id", 0, conMsg.arg1);
217         assertEquals("Unexpected new user id", TEST_USER_ID, conMsg.arg2);
218     }
219 
220     @SmallTest
testDispatchUserSwitchBadReceiver()221     public void testDispatchUserSwitchBadReceiver() throws RemoteException {
222         // Prepare mock observer which doesn't notify the callback and register it
223         IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
224         when(observer.asBinder()).thenReturn(new Binder());
225         mUserController.registerUserSwitchObserver(observer, "mock");
226         // Start user -- this will update state of mUserController
227         mUserController.startUser(TEST_USER_ID, true);
228         Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
229         assertNotNull(reportMsg);
230         UserState userState = (UserState) reportMsg.obj;
231         int oldUserId = reportMsg.arg1;
232         int newUserId = reportMsg.arg2;
233         // Call dispatchUserSwitch and verify that observer was called only once
234         mInjector.handler.clearAllRecordedMessages();
235         mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
236         Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
237         // Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout)
238         Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
239         assertTrue("No messages should be sent", actualCodes.isEmpty());
240     }
241 
242     @SmallTest
testContinueUserSwitch()243     public void testContinueUserSwitch() throws RemoteException {
244         // Start user -- this will update state of mUserController
245         mUserController.startUser(TEST_USER_ID, true);
246         Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
247         assertNotNull(reportMsg);
248         UserState userState = (UserState) reportMsg.obj;
249         int oldUserId = reportMsg.arg1;
250         int newUserId = reportMsg.arg2;
251         mInjector.handler.clearAllRecordedMessages();
252         // Verify that continueUserSwitch worked as expected
253         mUserController.continueUserSwitch(userState, oldUserId, newUserId);
254         Mockito.verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
255         continueUserSwitchAssertions();
256     }
257 
258     @SmallTest
testContinueUserSwitchUIDisabled()259     public void testContinueUserSwitchUIDisabled() throws RemoteException {
260         mUserController.mUserSwitchUiEnabled = false;
261         // Start user -- this will update state of mUserController
262         mUserController.startUser(TEST_USER_ID, true);
263         Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
264         assertNotNull(reportMsg);
265         UserState userState = (UserState) reportMsg.obj;
266         int oldUserId = reportMsg.arg1;
267         int newUserId = reportMsg.arg2;
268         mInjector.handler.clearAllRecordedMessages();
269         // Verify that continueUserSwitch worked as expected
270         mUserController.continueUserSwitch(userState, oldUserId, newUserId);
271         Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
272         continueUserSwitchAssertions();
273     }
274 
continueUserSwitchAssertions()275     private void continueUserSwitchAssertions() throws RemoteException {
276         Set<Integer> expectedCodes = Collections.singleton(REPORT_USER_SWITCH_COMPLETE_MSG);
277         Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
278         assertEquals("Unexpected message sent", expectedCodes, actualCodes);
279         Message msg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_COMPLETE_MSG);
280         assertNotNull(msg);
281         assertEquals("Unexpected userId", TEST_USER_ID, msg.arg1);
282     }
283 
284     @SmallTest
testDispatchUserSwitchComplete()285     public void testDispatchUserSwitchComplete() throws RemoteException {
286         // Prepare mock observer and register it
287         IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
288         when(observer.asBinder()).thenReturn(new Binder());
289         mUserController.registerUserSwitchObserver(observer, "mock");
290         // Start user -- this will update state of mUserController
291         mUserController.startUser(TEST_USER_ID, true);
292         Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
293         assertNotNull(reportMsg);
294         int newUserId = reportMsg.arg2;
295         mInjector.handler.clearAllRecordedMessages();
296         // Mockito can't reset only interactions, so just verify that this hasn't been
297         // called with 'false' until after dispatchUserSwitchComplete.
298         Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(false);
299         // Call dispatchUserSwitchComplete
300         mUserController.dispatchUserSwitchComplete(newUserId);
301         Mockito.verify(observer, times(1)).onUserSwitchComplete(anyInt());
302         Mockito.verify(observer).onUserSwitchComplete(TEST_USER_ID);
303         Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(false);
304     }
305 
setUpUser(int userId, int flags)306     private void setUpUser(int userId, int flags) {
307         UserInfo userInfo = new UserInfo(userId, "User" + userId, flags);
308         when(mInjector.userManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo);
309     }
310 
getActions(List<Intent> intents)311     private static List<String> getActions(List<Intent> intents) {
312         List<String> result = new ArrayList<>();
313         for (Intent intent : intents) {
314             result.add(intent.getAction());
315         }
316         return result;
317     }
318 
319     private static class TestInjector extends UserController.Injector {
320         final Object lock = new Object();
321         TestHandler handler;
322         HandlerThread handlerThread;
323         UserManagerService userManagerMock;
324         UserManagerInternal userManagerInternalMock;
325         WindowManagerService windowManagerMock;
326         ActivityStackSupervisor activityStackSupervisor;
327         private Context mCtx;
328         List<Intent> sentIntents = new ArrayList<>();
329 
TestInjector(Context ctx)330         TestInjector(Context ctx) {
331             super(null);
332             mCtx = ctx;
333             handlerThread = new HandlerThread(TAG);
334             handlerThread.start();
335             handler = new TestHandler(handlerThread.getLooper());
336             userManagerMock = mock(UserManagerService.class);
337             userManagerInternalMock = mock(UserManagerInternal.class);
338             windowManagerMock = mock(WindowManagerService.class);
339             activityStackSupervisor = mock(ActivityStackSupervisor.class);
340         }
341 
342         @Override
getLock()343         protected Object getLock() {
344             return lock;
345         }
346 
347         @Override
getHandler()348         protected Handler getHandler() {
349             return handler;
350         }
351 
352         @Override
getUserManager()353         protected UserManagerService getUserManager() {
354             return userManagerMock;
355         }
356 
357         @Override
getUserManagerInternal()358         UserManagerInternal getUserManagerInternal() {
359             return userManagerInternalMock;
360         }
361 
362         @Override
getContext()363         protected Context getContext() {
364             return mCtx;
365         }
366 
367         @Override
checkCallingPermission(String permission)368         int checkCallingPermission(String permission) {
369             Log.i(TAG, "checkCallingPermission " + permission);
370             return PERMISSION_GRANTED;
371         }
372 
373         @Override
getWindowManager()374         WindowManagerService getWindowManager() {
375             return windowManagerMock;
376         }
377 
378         @Override
updateUserConfigurationLocked()379         void updateUserConfigurationLocked() {
380             Log.i(TAG, "updateUserConfigurationLocked");
381         }
382 
383         @Override
broadcastIntentLocked(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 userId)384         protected int broadcastIntentLocked(Intent intent, String resolvedType,
385                 IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
386                 String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered,
387                 boolean sticky, int callingPid, int callingUid, int userId) {
388             Log.i(TAG, "broadcastIntentLocked " + intent);
389             sentIntents.add(intent);
390             return 0;
391         }
392 
393         @Override
startHomeActivityLocked(int userId, String reason)394         void startHomeActivityLocked(int userId, String reason) {
395             Log.i(TAG, "startHomeActivityLocked " + userId);
396         }
397 
398         @Override
getActivityStackSupervisor()399         ActivityStackSupervisor getActivityStackSupervisor() {
400             return activityStackSupervisor;
401         }
402     }
403 
404     private static class TestHandler extends Handler {
405         private final List<Message> mMessages = new ArrayList<>();
406 
TestHandler(Looper looper)407         TestHandler(Looper looper) {
408             super(looper);
409         }
410 
getMessageCodes()411         Set<Integer> getMessageCodes() {
412             Set<Integer> result = new LinkedHashSet<>();
413             for (Message msg : mMessages) {
414                 result.add(msg.what);
415             }
416             return result;
417         }
418 
getMessageForCode(int what)419         Message getMessageForCode(int what) {
420             for (Message msg : mMessages) {
421                 if (msg.what == what) {
422                     return msg;
423                 }
424             }
425             return null;
426         }
427 
clearAllRecordedMessages()428         void clearAllRecordedMessages() {
429             mMessages.clear();
430         }
431 
432         @Override
sendMessageAtTime(Message msg, long uptimeMillis)433         public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
434             Message copy = new Message();
435             copy.copyFrom(msg);
436             mMessages.add(copy);
437             return super.sendMessageAtTime(msg, uptimeMillis);
438         }
439     }
440 }