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