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 }