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