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}