UserControllerTest.java revision 3b24e5b9d06be5740383e132c02929ff9bfe8715
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
17package com.android.server.am;
18
19import android.app.IUserSwitchObserver;
20import android.content.Context;
21import android.content.IIntentReceiver;
22import android.content.Intent;
23import android.content.pm.UserInfo;
24import android.os.Binder;
25import android.os.Bundle;
26import android.os.Handler;
27import android.os.HandlerThread;
28import android.os.IRemoteCallback;
29import android.os.Looper;
30import android.os.Message;
31import android.os.RemoteException;
32import android.os.UserManagerInternal;
33import android.test.AndroidTestCase;
34import android.util.Log;
35
36import com.android.server.pm.UserManagerService;
37import com.android.server.wm.WindowManagerService;
38
39import org.mockito.Mockito;
40
41import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.Collections;
44import java.util.HashSet;
45import java.util.LinkedHashSet;
46import java.util.List;
47import java.util.Set;
48
49import static android.content.pm.PackageManager.PERMISSION_GRANTED;
50import static com.android.server.am.ActivityManagerService.CONTINUE_USER_SWITCH_MSG;
51import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG;
52import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG;
53import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
54import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG;
55import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG;
56import static org.mockito.Matchers.any;
57import static org.mockito.Matchers.anyInt;
58import static org.mockito.Matchers.eq;
59import static org.mockito.Mockito.doAnswer;
60import static org.mockito.Mockito.mock;
61import static org.mockito.Mockito.never;
62import static org.mockito.Mockito.times;
63import static org.mockito.Mockito.when;
64
65public class UserControllerTest extends AndroidTestCase {
66    private static final int TEST_USER_ID = 10;
67    private static String TAG = UserControllerTest.class.getSimpleName();
68    private UserController mUserController;
69    private TestInjector mInjector;
70
71    @Override
72    public void setUp() throws Exception {
73        super.setUp();
74        mInjector = new TestInjector(getContext());
75        mUserController = new UserController(mInjector);
76        setUpUser(TEST_USER_ID, 0);
77    }
78
79    @Override
80    protected void tearDown() throws Exception {
81        super.tearDown();
82        mInjector.handlerThread.quit();
83
84    }
85
86    public void testStartUser() throws RemoteException {
87        mUserController.startUser(TEST_USER_ID, true);
88        Mockito.verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
89        Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
90        List<String> expectedActions = Arrays.asList(Intent.ACTION_USER_STARTED,
91                Intent.ACTION_USER_SWITCHED, Intent.ACTION_USER_STARTING);
92        assertEquals(expectedActions, getActions(mInjector.sentIntents));
93        Set<Integer> expectedCodes = new HashSet<>(
94                Arrays.asList(REPORT_USER_SWITCH_MSG, USER_SWITCH_TIMEOUT_MSG,
95                        SYSTEM_USER_START_MSG, SYSTEM_USER_CURRENT_MSG));
96        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
97        assertEquals("Unexpected message sent", expectedCodes, actualCodes);
98        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
99        assertNotNull(reportMsg);
100        UserState userState = (UserState) reportMsg.obj;
101        assertNotNull(userState);
102        assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
103        assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
104        assertEquals("Unexpected old user id", 0, reportMsg.arg1);
105        assertEquals("Unexpected new user id", TEST_USER_ID, reportMsg.arg2);
106    }
107
108    public void testDispatchUserSwitch() throws RemoteException {
109        // Prepare mock observer and register it
110        IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
111        when(observer.asBinder()).thenReturn(new Binder());
112        doAnswer(invocation -> {
113            IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1];
114            callback.sendResult(null);
115            return null;
116        }).when(observer).onUserSwitching(anyInt(), any());
117        mUserController.registerUserSwitchObserver(observer, "mock");
118        // Start user -- this will update state of mUserController
119        mUserController.startUser(TEST_USER_ID, true);
120        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
121        assertNotNull(reportMsg);
122        UserState userState = (UserState) reportMsg.obj;
123        int oldUserId = reportMsg.arg1;
124        int newUserId = reportMsg.arg2;
125        // Call dispatchUserSwitch and verify that observer was called only once
126        mInjector.handler.clearAllRecordedMessages();
127        mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
128        Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
129        Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG);
130        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
131        assertEquals("Unexpected message sent", expectedCodes, actualCodes);
132        Message conMsg = mInjector.handler.getMessageForCode(CONTINUE_USER_SWITCH_MSG);
133        assertNotNull(conMsg);
134        userState = (UserState) conMsg.obj;
135        assertNotNull(userState);
136        assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
137        assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
138        assertEquals("Unexpected old user id", 0, conMsg.arg1);
139        assertEquals("Unexpected new user id", TEST_USER_ID, conMsg.arg2);
140    }
141
142    public void testDispatchUserSwitchBadReceiver() throws RemoteException {
143        // Prepare mock observer which doesn't notify the callback and register it
144        IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
145        when(observer.asBinder()).thenReturn(new Binder());
146        mUserController.registerUserSwitchObserver(observer, "mock");
147        // Start user -- this will update state of mUserController
148        mUserController.startUser(TEST_USER_ID, true);
149        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
150        assertNotNull(reportMsg);
151        UserState userState = (UserState) reportMsg.obj;
152        int oldUserId = reportMsg.arg1;
153        int newUserId = reportMsg.arg2;
154        // Call dispatchUserSwitch and verify that observer was called only once
155        mInjector.handler.clearAllRecordedMessages();
156        mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
157        Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
158        // Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout)
159        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
160        assertTrue("No messages should be sent", actualCodes.isEmpty());
161    }
162
163    public void testContinueUserSwitch() throws RemoteException {
164        // Start user -- this will update state of mUserController
165        mUserController.startUser(TEST_USER_ID, true);
166        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
167        assertNotNull(reportMsg);
168        UserState userState = (UserState) reportMsg.obj;
169        int oldUserId = reportMsg.arg1;
170        int newUserId = reportMsg.arg2;
171        mInjector.handler.clearAllRecordedMessages();
172        // Verify that continueUserSwitch worked as expected
173        mUserController.continueUserSwitch(userState, oldUserId, newUserId);
174        Mockito.verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
175        Set<Integer> expectedCodes = Collections.singleton(REPORT_USER_SWITCH_COMPLETE_MSG);
176        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
177        assertEquals("Unexpected message sent", expectedCodes, actualCodes);
178        Message msg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_COMPLETE_MSG);
179        assertNotNull(msg);
180        assertEquals("Unexpected userId", TEST_USER_ID, msg.arg1);
181    }
182
183    private void setUpUser(int userId, int flags) {
184        UserInfo userInfo = new UserInfo(userId, "User" + userId, flags);
185        when(mInjector.userManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo);
186    }
187
188    private static List<String> getActions(List<Intent> intents) {
189        List<String> result = new ArrayList<>();
190        for (Intent intent : intents) {
191            result.add(intent.getAction());
192        }
193        return result;
194    }
195
196    private static class TestInjector extends UserController.Injector {
197        final Object lock = new Object();
198        TestHandler handler;
199        HandlerThread handlerThread;
200        UserManagerService userManagerMock;
201        UserManagerInternal userManagerInternalMock;
202        WindowManagerService windowManagerMock;
203        private Context mCtx;
204        List<Intent> sentIntents = new ArrayList<>();
205
206        TestInjector(Context ctx) {
207            super(null);
208            mCtx = ctx;
209            handlerThread = new HandlerThread(TAG);
210            handlerThread.start();
211            handler = new TestHandler(handlerThread.getLooper());
212            userManagerMock = mock(UserManagerService.class);
213            userManagerInternalMock = mock(UserManagerInternal.class);
214            windowManagerMock = mock(WindowManagerService.class);
215        }
216
217        @Override
218        protected Object getLock() {
219            return lock;
220        }
221
222        @Override
223        protected Handler getHandler() {
224            return handler;
225        }
226
227        @Override
228        protected UserManagerService getUserManager() {
229            return userManagerMock;
230        }
231
232        @Override
233        UserManagerInternal getUserManagerInternal() {
234            return userManagerInternalMock;
235        }
236
237        @Override
238        protected Context getContext() {
239            return mCtx;
240        }
241
242        @Override
243        int checkCallingPermission(String permission) {
244            Log.i(TAG, "checkCallingPermission " + permission);
245            return PERMISSION_GRANTED;
246        }
247
248        @Override
249        void stackSupervisorSetLockTaskModeLocked(TaskRecord task, int lockTaskModeState,
250                String reason, boolean andResume) {
251            Log.i(TAG, "stackSupervisorSetLockTaskModeLocked");
252        }
253
254        @Override
255        WindowManagerService getWindowManager() {
256            return windowManagerMock;
257        }
258
259        @Override
260        void updateUserConfigurationLocked() {
261            Log.i(TAG, "updateUserConfigurationLocked");
262        }
263
264        @Override
265        protected int broadcastIntentLocked(Intent intent, String resolvedType,
266                IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
267                String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered,
268                boolean sticky, int callingPid, int callingUid, int userId) {
269            Log.i(TAG, "broadcastIntentLocked " + intent);
270            sentIntents.add(intent);
271            return 0;
272        }
273
274        @Override
275        boolean stackSupervisorSwitchUserLocked(int userId, UserState uss) {
276            Log.i(TAG, "stackSupervisorSwitchUserLocked " + userId);
277            return true;
278        }
279
280        @Override
281        void startHomeActivityLocked(int userId, String reason) {
282            Log.i(TAG, "startHomeActivityLocked " + userId);
283        }
284   }
285
286    private static class TestHandler extends Handler {
287        private final List<Message> mMessages = new ArrayList<>();
288
289        TestHandler(Looper looper) {
290            super(looper);
291        }
292
293        Set<Integer> getMessageCodes() {
294            Set<Integer> result = new LinkedHashSet<>();
295            for (Message msg : mMessages) {
296                result.add(msg.what);
297            }
298            return result;
299        }
300
301        Message getMessageForCode(int what) {
302            for (Message msg : mMessages) {
303                if (msg.what == what) {
304                    return msg;
305                }
306            }
307            return null;
308        }
309
310        void clearAllRecordedMessages() {
311            mMessages.clear();
312        }
313
314        @Override
315        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
316            Message copy = new Message();
317            copy.copyFrom(msg);
318            mMessages.add(copy);
319            return super.sendMessageAtTime(msg, uptimeMillis);
320        }
321    }
322}