1 /* 2 * Copyright (C) 2021 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 package android.car.apitest; 17 18 import static android.car.test.util.UserTestingHelper.setMaxSupportedUsers; 19 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING; 20 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED; 21 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING; 22 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING; 23 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED; 24 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING; 25 26 import static com.google.common.truth.Truth.assertThat; 27 import static com.google.common.truth.Truth.assertWithMessage; 28 29 import android.annotation.UserIdInt; 30 import android.app.ActivityManager; 31 import android.app.IActivityManager; 32 import android.car.testapi.BlockingUserLifecycleListener; 33 import android.car.user.CarUserManager.UserLifecycleEvent; 34 import android.os.RemoteException; 35 import android.os.UserManager; 36 import android.util.Log; 37 38 import org.junit.AfterClass; 39 import org.junit.BeforeClass; 40 import org.junit.Test; 41 42 import java.util.List; 43 import java.util.concurrent.Executor; 44 import java.util.concurrent.atomic.AtomicBoolean; 45 46 // DO NOT ADD ANY TEST TO THIS CLASS 47 // This class will have only one test testLifecycleListener. 48 public final class CarUserManagerLifeCycleTest extends CarMultiUserTestBase { 49 50 private static final String TAG = CarUserManagerLifeCycleTest.class.getSimpleName(); 51 52 private static final int PIN = 2345; 53 54 private static final int SWITCH_TIMEOUT_MS = 70_000; 55 // A large stop timeout is required as sometimes stop user broadcast takes a significantly 56 // long time to complete. This happen when there are multiple users starting/stopping in 57 // background which is the case in this test class. 58 private static final int STOP_TIMEOUT_MS = 600_000; 59 60 /** 61 * Stopping the user takes a while, even when calling force stop - change it to {@code false} 62 * if {@code testLifecycleListener} becomes flaky. 63 */ 64 private static final boolean TEST_STOP_EVENTS = true; 65 66 private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers(); 67 private static boolean sChangedMaxNumberUsers; 68 69 @BeforeClass setupMaxNumberOfUsers()70 public static void setupMaxNumberOfUsers() { 71 int requiredUsers = 3; // system user, current user, 1 extra user 72 if (sMaxNumberUsersBefore < requiredUsers) { 73 sChangedMaxNumberUsers = true; 74 Log.i(TAG, "Increasing maximing number of users from " + sMaxNumberUsersBefore + " to " 75 + requiredUsers); 76 setMaxSupportedUsers(requiredUsers); 77 } 78 } 79 80 @AfterClass restoreMaxNumberOfUsers()81 public static void restoreMaxNumberOfUsers() { 82 if (sChangedMaxNumberUsers) { 83 Log.i(TAG, "Restoring maximum number of users to " + sMaxNumberUsersBefore); 84 setMaxSupportedUsers(sMaxNumberUsersBefore); 85 } 86 } 87 88 @Test(timeout = 600_000) testLifecycleListener()89 public void testLifecycleListener() throws Exception { 90 int initialUserId = getCurrentUserId(); 91 int newUserId = createUser().id; 92 93 BlockingUserLifecycleListener startListener = BlockingUserLifecycleListener 94 .forSpecificEvents() 95 .forUser(newUserId) 96 .setTimeout(SWITCH_TIMEOUT_MS) 97 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING) 98 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING) 99 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING) 100 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) 101 .build(); 102 103 Log.d(TAG, "registering start listener: " + startListener); 104 AtomicBoolean executedRef = new AtomicBoolean(); 105 106 Executor mExecutor = (r) -> { 107 executedRef.set(true); 108 r.run(); 109 }; 110 mCarUserManager.addListener(mExecutor, startListener); 111 112 // Switch while listener is registered 113 switchUser(newUserId); 114 115 List<UserLifecycleEvent> startEvents = startListener.waitForEvents(); 116 Log.d(TAG, "Received start events: " + startEvents); 117 118 // Make sure listener callback was executed in the proper threaqd 119 assertWithMessage("executed on executor").that(executedRef.get()).isTrue(); 120 121 // Assert user ids 122 List<UserLifecycleEvent> expectedEvents = startListener.waitForEvents(); 123 Log.d(TAG, "Received expected events: " + expectedEvents); 124 for (UserLifecycleEvent event : expectedEvents) { 125 assertWithMessage("userId on event %s", event) 126 .that(event.getUserId()).isEqualTo(newUserId); 127 assertWithMessage("userHandle on event %s", event) 128 .that(event.getUserHandle().getIdentifier()).isEqualTo(newUserId); 129 if (event.getEventType() == USER_LIFECYCLE_EVENT_TYPE_SWITCHING) { 130 assertWithMessage("previousUserId on event %s", event) 131 .that(event.getPreviousUserId()).isEqualTo(initialUserId); 132 assertWithMessage("previousUserHandle on event %s", event) 133 .that(event.getPreviousUserHandle().getIdentifier()).isEqualTo(initialUserId); 134 } 135 } 136 137 Log.d(TAG, "unregistering start listener: " + startListener); 138 mCarUserManager.removeListener(startListener); 139 140 BlockingUserLifecycleListener stopListener = BlockingUserLifecycleListener 141 .forSpecificEvents() 142 .forUser(newUserId) 143 .setTimeout(STOP_TIMEOUT_MS) 144 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING) 145 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED) 146 .build(); 147 148 Log.d(TAG, "registering stop listener: " + stopListener); 149 mCarUserManager.addListener(mExecutor, stopListener); 150 151 // Switch back to the initial user 152 switchUser(initialUserId); 153 154 if (TEST_STOP_EVENTS) { 155 // Must force stop the user, otherwise it can take minutes for its process to finish 156 forceStopUser(newUserId); 157 158 List<UserLifecycleEvent> stopEvents = stopListener.waitForEvents(); 159 Log.d(TAG, "stopEvents: " + stopEvents + "; all events on stop listener: " 160 + stopListener.getAllReceivedEvents()); 161 162 // Assert user ids 163 for (UserLifecycleEvent event : stopEvents) { 164 assertWithMessage("userId on %s", event) 165 .that(event.getUserId()).isEqualTo(newUserId); 166 assertWithMessage("wrong userHandle on %s", event) 167 .that(event.getUserHandle().getIdentifier()).isEqualTo(newUserId); 168 } 169 } else { 170 Log.w(TAG, "NOT testing user stop events"); 171 } 172 173 // Make sure unregistered listener didn't receive any more events 174 List<UserLifecycleEvent> allStartEvents = startListener.getAllReceivedEvents(); 175 Log.d(TAG, "All start events: " + startEvents); 176 assertThat(allStartEvents).containsAtLeastElementsIn(startEvents).inOrder(); 177 178 Log.d(TAG, "unregistering stop listener: " + stopListener); 179 mCarUserManager.removeListener(stopListener); 180 } 181 forceStopUser(@serIdInt int userId)182 private static void forceStopUser(@UserIdInt int userId) throws RemoteException { 183 Log.i(TAG, "Force-stopping user " + userId); 184 IActivityManager am = ActivityManager.getService(); 185 am.stopUser(userId, /* force=*/ true, /* listener= */ null); 186 } 187 } 188