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