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