• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.test.util.UserTestingHelper.clearUserLockCredentials;
19 import static android.car.test.util.UserTestingHelper.setMaxSupportedUsers;
20 import static android.car.test.util.UserTestingHelper.setUserLockCredentials;
21 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
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 import static android.car.user.UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE;
26 
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.Car;
33 import android.car.SyncResultCallback;
34 import android.car.testapi.BlockingUserLifecycleListener;
35 import android.car.user.CarUserManager;
36 import android.car.user.CarUserManager.UserLifecycleEvent;
37 import android.car.user.UserLifecycleEventFilter;
38 import android.car.user.UserSwitchRequest;
39 import android.car.user.UserSwitchResult;
40 import android.content.pm.UserInfo;
41 import android.os.Process;
42 import android.os.SystemProperties;
43 import android.os.UserHandle;
44 import android.os.UserManager;
45 import android.util.Log;
46 
47 import androidx.test.filters.FlakyTest;
48 
49 import com.android.compatibility.common.util.ApiTest;
50 
51 import org.junit.AfterClass;
52 import org.junit.BeforeClass;
53 import org.junit.Ignore;
54 import org.junit.Test;
55 
56 import java.util.List;
57 import java.util.Objects;
58 import java.util.concurrent.TimeUnit;
59 
60 public final class CarUserManagerTest extends CarMultiUserTestBase {
61 
62     private static final String TAG = CarUserManagerTest.class.getSimpleName();
63 
64     private static final int PIN = 2345;
65 
66     private static final int START_TIMEOUT_MS = 20_000;
67     private static final int SWITCH_TIMEOUT_MS = 70_000;
68     private static final long TEST_WAIT_MS = 50;
69     private static final long TEST_TIMEOUT_MS = 10_000;
70 
71     private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers();
72     private static boolean sChangedMaxNumberUsers;
73 
74     @BeforeClass
setupMaxNumberOfUsers()75     public static void setupMaxNumberOfUsers() {
76         int requiredUsers = 3; // system user, current user, 1 extra user
77         if (sMaxNumberUsersBefore < requiredUsers) {
78             sChangedMaxNumberUsers = true;
79             Log.i(TAG, "Increasing maximing number of users from " + sMaxNumberUsersBefore + " to "
80                     + requiredUsers);
81             setMaxSupportedUsers(requiredUsers);
82         }
83     }
84 
85     @AfterClass
restoreMaxNumberOfUsers()86     public static void restoreMaxNumberOfUsers() {
87         if (sChangedMaxNumberUsers) {
88             Log.i(TAG, "Restoring maximum number of users to " + sMaxNumberUsersBefore);
89             setMaxSupportedUsers(sMaxNumberUsersBefore);
90         }
91     }
92 
93     @Test
94     @ApiTest(apis = {"android.car.user.CarUserManager#createUser(String, int)"})
testCreateUser()95     public void testCreateUser() throws Exception {
96         UserInfo newUser = createUser("DaNewUserInTheBlock");
97         assertWithMessage("(%s).isGuest()", newUser.toFullString()).that(newUser.isGuest())
98                 .isFalse();
99 
100         assertWithMessage("user(%s).name", newUser.toFullString()).that(newUser.name)
101                 .contains("DaNewUserInTheBlock");
102 
103         // Make sure the user exists
104         UserInfo loadedUser = getUser(newUser.id);
105         assertUserInfo(newUser, loadedUser);
106     }
107 
108     @Test
109     @ApiTest(apis = {"android.car.user.CarUserManager#createGuest(String)"})
testCreateGuest()110     public void testCreateGuest() throws Exception {
111         UserInfo newGuest = createGuest("DaNewGuestInTheBlock");
112         assertWithMessage("(%s).isGuest()", newGuest.toFullString()).that(newGuest.isGuest())
113                 .isTrue();
114 
115         assertWithMessage("guest(%s).name ", newGuest.toFullString()).that(newGuest.name)
116                 .contains("DaNewGuestInTheBlock");
117 
118         // Make sure the guest exists
119         UserInfo loadedGuest = getUser(newGuest.id);
120         assertUserInfo(newGuest, loadedGuest);
121     }
122 
123     @Test
124     @ApiTest(apis = {
125             "android.car.user.CarUserManager#addListener(Executor,UserLifecycleListener)",
126             "android.car.user.CarUserManager#removeListener(UserLifecycleListener)"
127     })
testLifecycleMultipleListeners()128     public void testLifecycleMultipleListeners() throws Exception {
129         int newUserId = createUser("Test").id;
130         Car car2 = Car.createCar(getContext().getApplicationContext());
131         CarUserManager mgr2 = (CarUserManager) car2.getCarManager(Car.CAR_USER_SERVICE);
132         CarUserManager mgr1 = mCarUserManager;
133         Log.d(TAG, "myUid=" + Process.myUid() + ",mgr1=" + mgr1 + ", mgr2=" + mgr2);
134         assertWithMessage("mgrs").that(mgr1).isNotSameInstanceAs(mgr2);
135 
136         BlockingUserLifecycleListener listener1 = BlockingUserLifecycleListener
137                 .forSpecificEvents()
138                 .forUser(newUserId)
139                 .setTimeout(START_TIMEOUT_MS)
140                 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
141                 .build();
142         BlockingUserLifecycleListener listener2 = BlockingUserLifecycleListener
143                 .forSpecificEvents()
144                 .forUser(newUserId)
145                 .setTimeout(START_TIMEOUT_MS)
146                 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
147                 .build();
148         BlockingUserLifecycleListener listener3 = BlockingUserLifecycleListener
149                 .forSpecificEvents()
150                 .forUser(newUserId)
151                 .setTimeout(START_TIMEOUT_MS)
152                 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
153                 .build();
154         UserLifecycleEventFilter unlockingEventFilter = new UserLifecycleEventFilter.Builder()
155                 .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING).build();
156         UserLifecycleEventFilter userFilter = new UserLifecycleEventFilter.Builder()
157                 .addUser(UserHandle.of(newUserId)).build();
158 
159         Log.d(TAG, "registering listener1: " + listener1);
160         mgr1.addListener(Runnable::run, listener1);
161         Log.v(TAG, "ok");
162         try {
163             Log.d(TAG, "registering listener2: " + listener2 + " with filter: "
164                     + unlockingEventFilter);
165             mgr2.addListener(Runnable::run, unlockingEventFilter, listener2);
166             Log.v(TAG, "ok");
167             Log.d(TAG, "registering listener3: " + listener3 + " with filter: " + userFilter);
168             mgr2.addListener(Runnable::run, userFilter, listener3);
169             Log.v(TAG, "ok");
170             try {
171                 IActivityManager am = ActivityManager.getService();
172                 Log.d(TAG, "Starting user " + newUserId);
173                 am.startUserInBackground(newUserId);
174                 Log.v(TAG, "ok");
175 
176                 Log.d(TAG, "Waiting for events");
177                 List<UserLifecycleEvent> events1 = listener1.waitForEvents();
178                 Log.d(TAG, "events1: " + events1);
179                 List<UserLifecycleEvent> events3 = listener3.waitForEvents();
180                 Log.d(TAG, "events2: " + events3);
181                 assertStartUserEvent(events1, newUserId);
182                 assertStartUserEvent(events3, newUserId);
183                 assertWithMessage("all events received by listener %s", listener2)
184                         .that(listener2.getAllReceivedEvents()).isEmpty();
185             } finally {
186                 Log.d(TAG, "unregistering listener2: " + listener2);
187                 mgr2.removeListener(listener2);
188                 Log.v(TAG, "ok");
189                 Log.d(TAG, "unregistering listener3: " + listener3);
190                 mgr2.removeListener(listener3);
191                 Log.v(TAG, "ok");
192             }
193         } finally {
194             Log.d(TAG, "unregistering listener1: " + listener1);
195             mgr1.removeListener(listener1);
196             Log.v(TAG, "ok");
197         }
198     }
199 
assertStartUserEvent(List<UserLifecycleEvent> events, @UserIdInt int userId)200     private void assertStartUserEvent(List<UserLifecycleEvent> events, @UserIdInt int userId) {
201         assertWithMessage("events").that(events).hasSize(1);
202 
203         UserLifecycleEvent event = events.get(0);
204         assertWithMessage("type").that(event.getEventType())
205                 .isEqualTo(USER_LIFECYCLE_EVENT_TYPE_STARTING);
206         assertWithMessage("user id on %s", event).that(event.getUserId()).isEqualTo(userId);
207         assertWithMessage("user handle on %s", event).that(event.getUserHandle().getIdentifier())
208                 .isEqualTo(userId);
209         assertWithMessage("previous user id on %s", event).that(event.getPreviousUserId())
210                 .isEqualTo(UserHandle.USER_NULL);
211         assertWithMessage("previous user handle on %s", event).that(event.getPreviousUserHandle())
212                 .isNull();
213     }
214 
215     /**
216      * Tests resume behavior when current user is ephemeral guest, a new guest user should be
217      * created and switched to.
218      */
219     @Ignore("b/233164303")
220     @Test
221     @ApiTest(apis = {
222             "android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED",
223             "android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_SWITCHING",
224     })
testGuestUserResumeToNewGuestUser()225     public void testGuestUserResumeToNewGuestUser() throws Exception {
226         // TODO(b/241837415): Create a host-side test and move this test there.
227         if (!isDeviceEmulator()) return;
228 
229         // Create new guest user
230         UserInfo guestUser = createGuest();
231         int guestUserId = guestUser.id;
232 
233         // Wait for this user to be active
234         BlockingUserLifecycleListener listener1 = BlockingUserLifecycleListener
235                 .forSpecificEvents()
236                 .forUser(guestUserId)
237                 .setTimeout(SWITCH_TIMEOUT_MS)
238                 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
239                 .build();
240         mCarUserManager.addListener(Runnable::run, listener1);
241         try {
242             switchUser(guestUserId);
243             listener1.waitForEvents();
244         } finally {
245             mCarUserManager.removeListener(listener1);
246         }
247 
248         BlockingUserLifecycleListener listener2 = BlockingUserLifecycleListener
249                 .forSpecificEvents()
250                 .forPreviousUser(guestUserId)
251                 .setTimeout(SWITCH_TIMEOUT_MS)
252                 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
253                 .build();
254         // Make sure listener callback was executed in the proper thread
255         mCarUserManager.addListener(Runnable::run, listener2);
256 
257         try {
258             // Emulate suspend to RAM
259             suspendToRamAndResume();
260             UserLifecycleEvent event = listener2.waitForEvents().get(0);
261 
262             int newGuestId = event.getUserId();
263 
264             assertWithMessage("userId on event %s", event).that(newGuestId)
265                     .isNotEqualTo(guestUserId);
266             assertWithMessage("current user id").that(newGuestId).isEqualTo(getCurrentUserId());
267             UserInfo newGuest = mUserManager.getUserInfo(newGuestId);
268             assertWithMessage("new user (%s) is a guest", newGuest.toFullString())
269                     .that(newGuest.isGuest()).isTrue();
270             assertWithMessage("name of new guest(%s)", newGuest.toFullString())
271                     .that(newGuest.name).isNotEqualTo(guestUser.name);
272         } finally {
273             mCarUserManager.removeListener(listener2);
274         }
275     }
276 
277     /**
278      * Tests resume behavior when current user is guest but with secured lock screen,
279      * resume to same guest user.
280      */
281     @FlakyTest(bugId = 357135725)
282     @Test
283     @ApiTest(apis = {
284             "android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED",
285     })
testSecuredGuestUserResumeToSameUser()286     public void testSecuredGuestUserResumeToSameUser() throws Exception {
287         // TODO(b/241837415): Create a host-side test and move this test there.
288         if (!isDeviceEmulator()) return;
289 
290         // Create new guest user
291         UserInfo guestUser = createGuest();
292         int guestUserId = guestUser.id;
293 
294         // Wait for this user to be active
295         BlockingUserLifecycleListener listener = BlockingUserLifecycleListener
296                 .forSpecificEvents()
297                 .forUser(guestUserId)
298                 .setTimeout(SWITCH_TIMEOUT_MS)
299                 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
300                 .build();
301         mCarUserManager.addListener(Runnable::run, listener);
302 
303         try {
304             switchUser(guestUserId);
305 
306             listener.waitForEvents();
307         } finally {
308             mCarUserManager.removeListener(listener);
309         }
310 
311         setUserLockCredentials(guestUserId, PIN);
312         try {
313             // Emulate suspend to RAM
314             suspendToRamAndResume();
315 
316             assertWithMessage("current user remains guest user (%s)", guestUser)
317                     .that(getCurrentUserId()).isEqualTo(guestUserId);
318         } finally {
319             clearUserLockCredentials(guestUserId, PIN);
320         }
321     }
322 
323     /**
324      * Tests resume behavior when current user is persistent user.
325      */
326     @FlakyTest(bugId = 357135725)
327     @Test
328     @ApiTest(apis = {
329             "android.car.user.CarUserManager#USER_LIFECYCLE_EVENT_TYPE_UNLOCKED",
330     })
testPersistentUserResumeToUser()331     public void testPersistentUserResumeToUser() throws Exception {
332         // TODO(b/241837415): Create a host-side test and move this test there.
333         if (!isDeviceEmulator()) return;
334 
335         int newUserId = createUser().id;
336         BlockingUserLifecycleListener listener = BlockingUserLifecycleListener
337                 .forSpecificEvents()
338                 .forUser(newUserId)
339                 .setTimeout(SWITCH_TIMEOUT_MS)
340                 .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
341                 .build();
342         mCarUserManager.addListener(Runnable::run, listener);
343         try {
344             switchUser(newUserId);
345             listener.waitForEvents();
346 
347             // Emulate suspend to RAM
348             suspendToRamAndResume();
349 
350             listener.waitForEvents();
351             assertWithMessage("current user remains new user (%s)", newUserId)
352                     .that(ActivityManager.getCurrentUser()).isEqualTo(newUserId);
353         } finally {
354             mCarUserManager.removeListener(listener);
355         }
356     }
357 
358     @Test
testSwitchUserUxRestrictionFailure()359     public void testSwitchUserUxRestrictionFailure() throws Exception {
360         SyncResultCallback<UserSwitchResult> userSwitchResultCallback = new SyncResultCallback<>();
361         int initialUserId = getCurrentUserId();
362         try {
363             Log.i(TAG, "Changing driving state to driving");
364             executeShellCommand("cmd car_service emulate-driving-state drive");
365             assertWithMessage("Waiting for driving state change").that(
366                     waitForDrivingStateChanged("Current Driving State: 2",
367                             TEST_TIMEOUT_MS)).isTrue();
368 
369             int newUserId = createUser().id;
370             mCarUserManager.switchUser(
371                     new UserSwitchRequest.Builder(UserHandle.of(newUserId)).build(), Runnable::run,
372                     userSwitchResultCallback);
373             UserSwitchResult userSwitchResult = userSwitchResultCallback.get(
374                     DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
375 
376             assertWithMessage("switchUser(%s) ", newUserId).that(
377                     userSwitchResult.getStatus()).isEqualTo(STATUS_UX_RESTRICTION_FAILURE);
378         } finally {
379             Log.i(TAG, "Restoring driving state to parked");
380             executeShellCommand("cmd car_service emulate-driving-state park");
381             switchUser(initialUserId);
382         }
383     }
384 
isDeviceEmulator()385     private static boolean isDeviceEmulator() {
386         return Objects.equals(SystemProperties.get("ro.product.system.device"), "generic");
387     }
388 
waitForDrivingStateChanged(String expected, long timeout)389     private boolean waitForDrivingStateChanged(String expected, long timeout) {
390         long start = System.currentTimeMillis();
391         while (start + timeout > System.currentTimeMillis()) {
392             try {
393                 String result = executeShellCommand(
394                         "dumpsys car_service --services CarDrivingStateService");
395                 if (result.contains(expected)) {
396                     return true;
397                 }
398                 Thread.sleep(TEST_WAIT_MS);
399             } catch (InterruptedException e) {
400                 Log.e(TAG, "Test interrupted: " + e);
401                 return false;
402             } catch (Exception e) {
403                 Log.e(TAG, "executeCommand failed: " + e);
404                 return false;
405             }
406         }
407         return false;
408     }
409 }
410