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.user;
17 
18 import static android.car.test.mock.CarMockitoHelper.mockHandleRemoteExceptionFromCarServiceWithDefaultValue;
19 import static android.car.test.util.CarTestingHelper.getResult;
20 import static android.os.UserHandle.SYSTEM;
21 import static android.os.UserHandle.USER_SYSTEM;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.junit.Assert.assertThrows;
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.ArgumentMatchers.anyBoolean;
28 import static org.mockito.ArgumentMatchers.anyInt;
29 import static org.mockito.ArgumentMatchers.eq;
30 import static org.mockito.ArgumentMatchers.isNull;
31 import static org.mockito.ArgumentMatchers.notNull;
32 import static org.mockito.ArgumentMatchers.same;
33 import static org.mockito.Mockito.doAnswer;
34 import static org.mockito.Mockito.doThrow;
35 import static org.mockito.Mockito.times;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.when;
38 
39 import android.annotation.NonNull;
40 import android.annotation.Nullable;
41 import android.annotation.UserIdInt;
42 import android.car.ICarUserService;
43 import android.car.SyncResultCallback;
44 import android.car.test.AbstractExpectableTestCase;
45 import android.car.test.util.UserTestingHelper;
46 import android.car.user.CarUserManager.UserHandleSwitchUiCallback;
47 import android.car.user.CarUserManager.UserLifecycleListener;
48 import android.car.user.CarUserManager.UserSwitchUiCallback;
49 import android.car.util.concurrent.AndroidFuture;
50 import android.car.util.concurrent.AsyncFuture;
51 import android.content.Context;
52 import android.content.pm.UserInfo;
53 import android.content.pm.UserInfo.UserInfoFlag;
54 import android.hardware.automotive.vehicle.UserIdentificationAssociationSetValue;
55 import android.hardware.automotive.vehicle.UserIdentificationAssociationType;
56 import android.hardware.automotive.vehicle.UserIdentificationAssociationValue;
57 import android.os.RemoteException;
58 import android.os.UserHandle;
59 import android.os.UserManager;
60 import android.platform.test.ravenwood.RavenwoodRule;
61 
62 import com.android.car.internal.ICarBase;
63 import com.android.car.internal.ResultCallbackImpl;
64 
65 import org.junit.Before;
66 import org.junit.Rule;
67 import org.junit.Test;
68 import org.junit.runner.RunWith;
69 import org.mockito.Mock;
70 import org.mockito.junit.MockitoJUnitRunner;
71 
72 import java.util.Arrays;
73 import java.util.List;
74 import java.util.stream.Collectors;
75 
76 @RunWith(MockitoJUnitRunner.class)
77 public final class CarUserManagerUnitTest extends AbstractExpectableTestCase {
78 
79     // Need to a rule to setup host implementation for SystemProperties.get which is used inside
80     // CarSystemProperties.getUserHalTimeout() during CarUserManager initialization.
81     @Rule
82     public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
83             .setSystemPropertyImmutable("android.car.user_hal_timeout", "")
84             // AndroidFuture uses getMainHandler
85             .setProvideMainThread(true)
86             .build();
87 
88     @Mock
89     private ICarBase mCar;
90     @Mock
91     private UserManager mUserManager;
92     @Mock
93     private ICarUserService mService;
94     @Mock
95     private Context mMockContext;
96 
97     private CarUserManager mMgr;
98 
99     @Before
setFixtures()100     public void setFixtures() {
101         mMgr = new CarUserManager(mCar, mService, mUserManager,
102                 /* isHeadlessSystemUserMode= */ true);
103         when(mCar.getContext()).thenReturn(mMockContext);
104     }
105 
106     @Test
testUserIdentificationAssociationType()107     public void testUserIdentificationAssociationType() {
108         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_KEY_FOB)
109                 .isEqualTo(UserIdentificationAssociationType.KEY_FOB);
110         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_1)
111                 .isEqualTo(UserIdentificationAssociationType.CUSTOM_1);
112         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_2)
113                 .isEqualTo(UserIdentificationAssociationType.CUSTOM_2);
114         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_3)
115                 .isEqualTo(UserIdentificationAssociationType.CUSTOM_3);
116         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_4)
117                 .isEqualTo(UserIdentificationAssociationType.CUSTOM_4);
118     }
119 
120     @Test
testUserIdentificationAssociationSetValue()121     public void testUserIdentificationAssociationSetValue() {
122         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_ASSOCIATE_CURRENT_USER)
123                 .isEqualTo(UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER);
124         assertThat(
125                 CarUserManager.USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_CURRENT_USER)
126                         .isEqualTo(UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER);
127         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_ALL_USERS)
128                 .isEqualTo(UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS);
129     }
130 
131     @Test
testUserIdentificationAssociationValue()132     public void testUserIdentificationAssociationValue() {
133         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_VALUE_UNKNOWN)
134                 .isEqualTo(UserIdentificationAssociationValue.UNKNOWN);
135         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATE_CURRENT_USER)
136                 .isEqualTo(UserIdentificationAssociationValue.ASSOCIATED_CURRENT_USER);
137         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATED_ANOTHER_USER)
138                 .isEqualTo(UserIdentificationAssociationValue.ASSOCIATED_ANOTHER_USER);
139         assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_VALUE_NOT_ASSOCIATED_ANY_USER)
140                 .isEqualTo(UserIdentificationAssociationValue.NOT_ASSOCIATED_ANY_USER);
141     }
142 
143     @Test
testIsValidUserId_headlessSystemUser()144     public void testIsValidUserId_headlessSystemUser() {
145         setExistingUsers(USER_SYSTEM);
146 
147         assertThat(mMgr.isValidUser(USER_SYSTEM)).isFalse();
148     }
149 
150     @Test
testIsValidUser_headlessSystemUser()151     public void testIsValidUser_headlessSystemUser() {
152         setExistingUsers(USER_SYSTEM);
153 
154         assertThat(mMgr.isValidUser(SYSTEM)).isFalse();
155     }
156 
157     @Test
testIsValidUserId_nonHeadlessSystemUser()158     public void testIsValidUserId_nonHeadlessSystemUser() {
159         mockIsHeadlessSystemUserMode(false);
160         setExistingUsers(USER_SYSTEM);
161 
162         assertThat(mMgr.isValidUser(USER_SYSTEM)).isTrue();
163     }
164 
165     @Test
testIsValidUser_nonHeadlessSystemUser()166     public void testIsValidUser_nonHeadlessSystemUser() {
167         mockIsHeadlessSystemUserMode(false);
168         setExistingUsers(USER_SYSTEM);
169 
170         assertThat(mMgr.isValidUser(SYSTEM)).isTrue();
171     }
172 
173     @Test
testIsValidUserId_found()174     public void testIsValidUserId_found() {
175         setExistingUsers(1, 2, 3);
176 
177         expectThat(mMgr.isValidUser(1)).isTrue();
178         expectThat(mMgr.isValidUser(2)).isTrue();
179         expectThat(mMgr.isValidUser(3)).isTrue();
180     }
181 
182     @Test
testIsValidUser_found()183     public void testIsValidUser_found() {
184         setExistingUsers(1, 2, 3);
185 
186         expectThat(mMgr.isValidUser(UserHandle.of(1))).isTrue();
187         expectThat(mMgr.isValidUser(UserHandle.of(2))).isTrue();
188         expectThat(mMgr.isValidUser(UserHandle.of(3))).isTrue();
189     }
190 
191     @Test
testIsValidUserId_notFound()192     public void testIsValidUserId_notFound() {
193         setExistingUsers(1, 2, 3);
194 
195         assertThat(mMgr.isValidUser(4)).isFalse();
196     }
197 
198     @Test
testIsValidUser_notFound()199     public void testIsValidUser_notFound() {
200         setExistingUsers(1, 2, 3);
201 
202         assertThat(mMgr.isValidUser(UserHandle.of(4))).isFalse();
203     }
204 
205     @Test
testIsValidUserId_emptyUsers()206     public void testIsValidUserId_emptyUsers() {
207         assertThat(mMgr.isValidUser(666)).isFalse();
208     }
209 
210     @Test
testIsValidUser_emptyUsers()211     public void testIsValidUser_emptyUsers() {
212         assertThat(mMgr.isValidUser(UserHandle.of(666))).isFalse();
213     }
214 
215     @Test
testAddListener_nullExecutor()216     public void testAddListener_nullExecutor() {
217         assertThrows(NullPointerException.class, () -> mMgr.addListener(null, (e) -> { }));
218     }
219 
220     @Test
testAddListener_nullListener()221     public void testAddListener_nullListener() {
222         assertThrows(NullPointerException.class, () -> mMgr.addListener(Runnable::run, null));
223     }
224 
225     @Test
testAddListener_nullFilter()226     public void testAddListener_nullFilter() {
227         assertThrows(NullPointerException.class,
228                 () -> mMgr.addListener(Runnable::run, /* filter= */null, (e) -> {}));
229     }
230 
231     @Test
testAddListener_sameListenerAddedTwice()232     public void testAddListener_sameListenerAddedTwice() {
233         UserLifecycleListener listener = (e) -> { };
234 
235         mMgr.addListener(Runnable::run, listener);
236         assertThrows(IllegalStateException.class, () -> mMgr.addListener(Runnable::run, listener));
237     }
238 
239     @Test
testAddListener_differentListenersAddedTwice()240     public void testAddListener_differentListenersAddedTwice() throws Exception {
241         mMgr.addListener(Runnable::run, (e) -> { });
242         mMgr.addListener(Runnable::run, (e) -> { });
243 
244         verify(mService, times(2)).setLifecycleListenerForApp(any(), isNull(), any());
245     }
246 
247     @Test
testAddListener_differentListenersWithFilter()248     public void testAddListener_differentListenersWithFilter() throws Exception {
249         UserLifecycleEventFilter filter1 = new UserLifecycleEventFilter.Builder()
250                 .addEventType(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING).build();
251         mMgr.addListener(Runnable::run, filter1, (e) -> { });
252         UserLifecycleEventFilter filter2 = new UserLifecycleEventFilter.Builder()
253                 .addUser(UserHandle.CURRENT).build();
254         mMgr.addListener(Runnable::run, filter2, (e) -> { });
255 
256         verify(mService).setLifecycleListenerForApp(any(), eq(filter1), any());
257         verify(mService).setLifecycleListenerForApp(any(), eq(filter2), any());
258     }
259 
260     @Test
testRemoveListener_nullListener()261     public void testRemoveListener_nullListener() {
262         assertThrows(NullPointerException.class, () -> mMgr.removeListener(null));
263     }
264 
265     @Test
testRemoveListener_notAddedBefore()266     public void testRemoveListener_notAddedBefore() {
267         UserLifecycleListener listener = (e) -> { };
268 
269         assertThrows(IllegalStateException.class, () -> mMgr.removeListener(listener));
270     }
271 
272     @Test
testRemoveListener_addAndRemove()273     public void testRemoveListener_addAndRemove() {
274         UserLifecycleListener listener = (e) -> { };
275 
276         mMgr.addListener(Runnable::run, listener);
277         mMgr.removeListener(listener);
278 
279         // Make sure it was removed
280         assertThrows(IllegalStateException.class, () -> mMgr.removeListener(listener));
281     }
282 
283     @Test
testSwitchUser_success()284     public void testSwitchUser_success() throws Exception {
285         expectServiceSwitchUserSucceeds(11, UserSwitchResult.STATUS_SUCCESSFUL);
286 
287         mMgr.switchUser(new UserSwitchRequest.Builder(
288                         UserHandle.of(11)).build(), Runnable::run, response -> {
289                     assertThat(response.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
290                     assertThat(response.getErrorMessage()).isNull();
291                 }
292         );
293 
294     }
295 
296     @Test
testSwitchUserId_success()297     public void testSwitchUserId_success() throws Exception {
298         expectServiceSwitchUserSucceeds(11, UserSwitchResult.STATUS_SUCCESSFUL);
299 
300         AsyncFuture<UserSwitchResult> future = mMgr.switchUser(11);
301 
302         assertThat(future).isNotNull();
303         UserSwitchResult result = getResult(future);
304         assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
305         assertThat(result.getErrorMessage()).isNull();
306     }
307 
308     @Test
testSwitchUser_remoteException()309     public void testSwitchUser_remoteException() throws Exception {
310         expectServiceSwitchUserFails(11, new RemoteException("D'OH!"));
311         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
312 
313         mMgr.switchUser(new UserSwitchRequest.Builder(
314                         UserHandle.of(11)).build(), Runnable::run, response -> {
315                     assertThat(response.getStatus()).isEqualTo(
316                             UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
317                     assertThat(response.getErrorMessage()).isNull();
318                 }
319         );
320     }
321 
322     @Test
testSwitchUserId_remoteException()323     public void testSwitchUserId_remoteException() throws Exception {
324         expectServiceSwitchUserFails(11, new RemoteException("D'OH!"));
325         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
326 
327         AsyncFuture<UserSwitchResult> future = mMgr.switchUser(11);
328 
329         assertThat(future).isNotNull();
330         UserSwitchResult result = getResult(future);
331         assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
332         assertThat(result.getErrorMessage()).isNull();
333     }
334 
335     @Test
testSwitchUser_runtimeException()336     public void testSwitchUser_runtimeException() throws Exception {
337         expectServiceSwitchUserFails(11, new RuntimeException("D'OH!"));
338 
339         mMgr.switchUser(new UserSwitchRequest.Builder(
340                         UserHandle.of(11)).build(), Runnable::run, response -> {
341                     assertThat(response.getStatus()).isEqualTo(
342                             UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
343                     assertThat(response.getErrorMessage()).isNull();
344                 }
345         );
346     }
347 
348     @Test
testSwitchUserId_runtimeException()349     public void testSwitchUserId_runtimeException() throws Exception {
350         expectServiceSwitchUserFails(11, new RuntimeException("D'OH!"));
351 
352         AsyncFuture<UserSwitchResult> future = mMgr.switchUser(11);
353 
354         assertThat(future).isNotNull();
355         UserSwitchResult result = getResult(future);
356         assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
357         assertThat(result.getErrorMessage()).isNull();
358     }
359 
360     @Test
testLogoutUser_success()361     public void testLogoutUser_success() throws Exception {
362         expectServiceLogoutUserSucceeds(UserSwitchResult.STATUS_SUCCESSFUL);
363 
364         AsyncFuture<UserSwitchResult> future = mMgr.logoutUser();
365 
366         assertThat(future).isNotNull();
367         UserSwitchResult result = getResult(future);
368         assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
369         assertThat(result.getErrorMessage()).isNull();
370     }
371 
372     @Test
testLogoutUser_remoteException()373     public void testLogoutUser_remoteException() throws Exception {
374         expectServiceLogoutUserFails(new RemoteException("D'OH!"));
375         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
376 
377         AsyncFuture<UserSwitchResult> future = mMgr.logoutUser();
378 
379         assertThat(future).isNotNull();
380         UserSwitchResult result = getResult(future);
381         assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
382         assertThat(result.getErrorMessage()).isNull();
383     }
384 
385     @Test
testLogoutUser_runtimeException()386     public void testLogoutUser_runtimeException() throws Exception {
387         expectServiceLogoutUserFails(new RuntimeException("D'OH!"));
388 
389         AsyncFuture<UserSwitchResult> future = mMgr.logoutUser();
390 
391         assertThat(future).isNotNull();
392         UserSwitchResult result = getResult(future);
393         assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
394         assertThat(result.getErrorMessage()).isNull();
395     }
396 
397     @Test
testRemoveUser_success()398     public void testRemoveUser_success() throws Exception {
399         expectServiceRemoveUserSucceeds(100);
400 
401         mMgr.removeUser(new UserRemovalRequest.Builder(
402                 UserHandle.of(100)).build(), Runnable::run, response ->
403                 assertThat(response.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL)
404         );
405     }
406 
407     @Test
testRemoveUserId_success()408     public void testRemoveUserId_success() throws Exception {
409         expectServiceRemoveUserSucceeds(100);
410 
411         UserRemovalResult result = mMgr.removeUser(100);
412 
413         assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
414     }
415 
416     @Test
testRemoveUser_remoteException()417     public void testRemoveUser_remoteException() throws Exception {
418         doThrow(new RemoteException("D'OH!")).when(mService).removeUser(eq(100), any());
419         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
420 
421         mMgr.removeUser(new UserRemovalRequest.Builder(
422                 UserHandle.of(100)).build(), Runnable::run, response ->
423                 assertThat(response.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE)
424         );
425     }
426 
427     @Test
testRemoveUserId_remoteException()428     public void testRemoveUserId_remoteException() throws Exception {
429         doThrow(new RemoteException("D'OH!")).when(mService).removeUser(eq(100), any());
430         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
431 
432         UserRemovalResult result = mMgr.removeUser(100);
433 
434         assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE);
435     }
436 
437     @Test
testRemoveUser_runtimeException()438     public void testRemoveUser_runtimeException() throws Exception {
439         doThrow(new RuntimeException("D'OH!")).when(mService).removeUser(eq(100), any());
440 
441         mMgr.removeUser(new UserRemovalRequest.Builder(
442                 UserHandle.of(100)).build(), Runnable::run, response ->
443                 assertThat(response.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE)
444         );
445     }
446 
447     @Test
testRemoveUserId_runtimeException()448     public void testRemoveUserId_runtimeException() throws Exception {
449         doThrow(new RuntimeException("D'OH!")).when(mService).removeUser(eq(100), any());
450 
451         UserRemovalResult result = mMgr.removeUser(100);
452 
453         assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE);
454     }
455 
456     @Test
testSetSwitchUserIdUICallback_success()457     public void testSetSwitchUserIdUICallback_success() throws Exception {
458         UserSwitchUiCallback callback = (u)-> {};
459 
460         mMgr.setUserSwitchUiCallback(callback);
461 
462         verify(mService).setUserSwitchUiCallback(any());
463     }
464 
465     @Test
testSetSwitchUserUICallback_nullCallback()466     public void testSetSwitchUserUICallback_nullCallback() throws Exception {
467         assertThrows(IllegalArgumentException.class, () -> mMgr.setUserSwitchUiCallback(null));
468     }
469 
470     @Test
testSetSwitchUserUICallback_success()471     public void testSetSwitchUserUICallback_success() throws Exception {
472         UserHandleSwitchUiCallback callback = (u)-> {};
473 
474         mMgr.setUserSwitchUiCallback(Runnable::run, callback);
475 
476         verify(mService).setUserSwitchUiCallback(any());
477     }
478 
479     @Test
testCreateUser_success()480     public void testCreateUser_success() throws Exception {
481         expectServiceCreateUserSucceeds("dude", UserManager.USER_TYPE_FULL_SECONDARY, 42,
482                 UserCreationResult.STATUS_SUCCESSFUL);
483         SyncResultCallback<UserCreationResult> userCreationResultCallback =
484                 new SyncResultCallback<>();
485 
486         mMgr.createUser(new UserCreationRequest.Builder().setName("dude").build(), Runnable::run,
487                 userCreationResultCallback);
488 
489         UserCreationResult result = userCreationResultCallback.get();
490         assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
491         assertThat(result.isSuccess()).isTrue();
492         assertThat(result.getErrorMessage()).isNull();
493 
494         UserHandle newUser = result.getUser();
495         assertThat(newUser).isNotNull();
496         assertThat(newUser.getIdentifier()).isEqualTo(108);
497     }
498 
499     @Test
testCreateUserId_success()500     public void testCreateUserId_success() throws Exception {
501         expectServiceCreateUserSucceeds("dude", UserManager.USER_TYPE_FULL_SECONDARY, 42,
502                 UserCreationResult.STATUS_SUCCESSFUL);
503 
504         AsyncFuture<UserCreationResult> future = mMgr.createUser("dude", 42);
505         assertThat(future).isNotNull();
506 
507         UserCreationResult result = getResult(future);
508         assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
509         assertThat(result.isSuccess()).isTrue();
510         assertThat(result.getErrorMessage()).isNull();
511 
512         UserHandle newUser = result.getUser();
513         assertThat(newUser).isNotNull();
514         assertThat(newUser.getIdentifier()).isEqualTo(108);
515     }
516 
517     @Test
testCreateUser_remoteException()518     public void testCreateUser_remoteException() throws Exception {
519         expectServiceCreateUserFails();
520         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
521         SyncResultCallback<UserCreationResult> userCreationResultCallback =
522                 new SyncResultCallback<>();
523 
524         mMgr.createUser(new UserCreationRequest.Builder().setName("dude").build(), Runnable::run,
525                 userCreationResultCallback);
526 
527         UserCreationResult result = userCreationResultCallback.get();
528         assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
529         assertThat(result.isSuccess()).isFalse();
530         assertThat(result.getErrorMessage()).isNull();
531         assertThat(result.getUser()).isNull();
532     }
533 
534     @Test
testCreateUserId_remoteException()535     public void testCreateUserId_remoteException() throws Exception {
536         expectServiceCreateUserFails();
537         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
538 
539         AsyncFuture<UserCreationResult> future = mMgr.createUser("dude", 42);
540         assertThat(future).isNotNull();
541 
542         UserCreationResult result = getResult(future);
543         assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
544         assertThat(result.isSuccess()).isFalse();
545         assertThat(result.getErrorMessage()).isNull();
546         assertThat(result.getUser()).isNull();
547     }
548 
549     @Test
testCreateUser_runtimeException()550     public void testCreateUser_runtimeException() throws Exception {
551         doThrow(new RuntimeException("D'OH!")).when(mService).createUser(notNull(), anyInt(),
552                 notNull());
553         SyncResultCallback<UserCreationResult> userCreationResultCallback =
554                 new SyncResultCallback<>();
555 
556         mMgr.createUser(new UserCreationRequest.Builder().setName("dude").build(), Runnable::run,
557                 userCreationResultCallback);
558 
559         UserCreationResult result = userCreationResultCallback.get();
560         assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
561         assertThat(result.isSuccess()).isFalse();
562         assertThat(result.getErrorMessage()).isNull();
563         assertThat(result.getUser()).isNull();
564     }
565 
566     @Test
testCreateUserId_runtimeException()567     public void testCreateUserId_runtimeException() throws Exception {
568         doThrow(new RuntimeException("D'OH!")).when(mService).createUser(notNull(), anyInt(),
569                 notNull());
570 
571         AsyncFuture<UserCreationResult> future = mMgr.createUser("dude", 42);
572         assertThat(future).isNotNull();
573 
574         UserCreationResult result = getResult(future);
575         assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
576         assertThat(result.isSuccess()).isFalse();
577         assertThat(result.getErrorMessage()).isNull();
578         assertThat(result.getUser()).isNull();
579     }
580 
581     @Test
testCreateGuest_success()582     public void testCreateGuest_success() throws Exception {
583         expectServiceCreateUserSucceeds("dudeGuest", UserManager.USER_TYPE_FULL_GUEST, 0,
584                 UserCreationResult.STATUS_SUCCESSFUL);
585 
586         AsyncFuture<UserCreationResult> future = mMgr.createGuest("dudeGuest");
587         assertThat(future).isNotNull();
588 
589         UserCreationResult result = getResult(future);
590         assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
591         assertThat(result.isSuccess()).isTrue();
592         assertThat(result.getErrorMessage()).isNull();
593 
594         UserHandle newUser = result.getUser();
595         assertThat(newUser).isNotNull();
596         assertThat(newUser.getIdentifier()).isEqualTo(108);
597     }
598 
599     @Test
testCreateGuest_remoteException()600     public void testCreateGuest_remoteException() throws Exception {
601         expectServiceCreateUserFails();
602         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
603 
604         AsyncFuture<UserCreationResult> future = mMgr.createGuest("dudeGuest");
605         assertThat(future).isNotNull();
606 
607         UserCreationResult result = getResult(future);
608         assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
609         assertThat(result.isSuccess()).isFalse();
610         assertThat(result.getErrorMessage()).isNull();
611         assertThat(result.getUser()).isNull();
612     }
613 
614     @Test
testGetUserIdentificationAssociation_nullTypes()615     public void testGetUserIdentificationAssociation_nullTypes() throws Exception {
616         assertThrows(IllegalArgumentException.class,
617                 () -> mMgr.getUserIdentificationAssociation(null));
618     }
619 
620     @Test
testGetUserIdentificationAssociation_emptyTypes()621     public void testGetUserIdentificationAssociation_emptyTypes() throws Exception {
622         assertThrows(IllegalArgumentException.class,
623                 () -> mMgr.getUserIdentificationAssociation(new int[] {}));
624     }
625 
626     @Test
testGetUserIdentificationAssociation_remoteException()627     public void testGetUserIdentificationAssociation_remoteException() throws Exception {
628         int[] types = new int[] {1};
629         when(mService.getUserIdentificationAssociation(types))
630                 .thenThrow(new RemoteException("D'OH!"));
631         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
632 
633         UserIdentificationAssociationResponse response =
634                 mMgr.getUserIdentificationAssociation(types);
635 
636         assertThat(response).isNotNull();
637         assertThat(response.isSuccess()).isFalse();
638     }
639 
640     @Test
testGetUserIdentificationAssociation_runtimeException()641     public void testGetUserIdentificationAssociation_runtimeException() throws Exception {
642         int[] types = new int[] {1};
643         when(mService.getUserIdentificationAssociation(types))
644                 .thenThrow(new RuntimeException("D'OH!"));
645         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
646 
647         UserIdentificationAssociationResponse response =
648                 mMgr.getUserIdentificationAssociation(types);
649 
650         assertThat(response).isNotNull();
651         assertThat(response.isSuccess()).isFalse();
652     }
653 
654     @Test
testGetUserIdentificationAssociation_ok()655     public void testGetUserIdentificationAssociation_ok() throws Exception {
656         int[] types = new int[] { 4, 8, 15, 16, 23, 42 };
657         UserIdentificationAssociationResponse expectedResponse =
658                 UserIdentificationAssociationResponse.forSuccess(types);
659         when(mService.getUserIdentificationAssociation(types)).thenReturn(expectedResponse);
660 
661         UserIdentificationAssociationResponse actualResponse =
662                 mMgr.getUserIdentificationAssociation(types);
663 
664         assertThat(actualResponse).isSameInstanceAs(expectedResponse);
665     }
666 
667     @Test
testSetUserIdentificationAssociation_nullTypes()668     public void testSetUserIdentificationAssociation_nullTypes() throws Exception {
669         assertThrows(IllegalArgumentException.class,
670                 () -> mMgr.setUserIdentificationAssociation(null, new int[] {42}));
671     }
672 
673     @Test
testSetUserIdentificationAssociation_emptyTypes()674     public void testSetUserIdentificationAssociation_emptyTypes() throws Exception {
675         assertThrows(IllegalArgumentException.class,
676                 () -> mMgr.setUserIdentificationAssociation(new int[0], new int[] {42}));
677     }
678 
679     @Test
testSetUserIdentificationAssociation_nullValues()680     public void testSetUserIdentificationAssociation_nullValues() throws Exception {
681         assertThrows(IllegalArgumentException.class,
682                 () -> mMgr.setUserIdentificationAssociation(new int[] {42}, null));
683     }
684 
685     @Test
testSetUserIdentificationAssociation_emptyValues()686     public void testSetUserIdentificationAssociation_emptyValues() throws Exception {
687         assertThrows(IllegalArgumentException.class,
688                 () -> mMgr.setUserIdentificationAssociation(new int[] {42}, new int[0]));
689     }
690 
691     @Test
testSetUserIdentificationAssociation_sizeMismatch()692     public void testSetUserIdentificationAssociation_sizeMismatch() throws Exception {
693         assertThrows(IllegalArgumentException.class,
694                 () -> mMgr.setUserIdentificationAssociation(new int[] {1}, new int[] {2, 3}));
695     }
696 
697     @Test
testSetUserIdentificationAssociation_remoteException()698     public void testSetUserIdentificationAssociation_remoteException() throws Exception {
699         int[] types = new int[] {1};
700         int[] values = new int[] {2};
701         doThrow(new RemoteException("D'OH!")).when(mService)
702                 .setUserIdentificationAssociation(anyInt(), same(types), same(values), notNull());
703         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
704 
705         AsyncFuture<UserIdentificationAssociationResponse> future =
706                 mMgr.setUserIdentificationAssociation(types, values);
707 
708         assertThat(future).isNotNull();
709         UserIdentificationAssociationResponse result = getResult(future);
710         assertThat(result.isSuccess()).isFalse();
711         assertThat(result.getValues()).isNull();
712         assertThat(result.getErrorMessage()).isNull();
713     }
714 
715     @Test
testSetUserIdentificationAssociation_runtimeException()716     public void testSetUserIdentificationAssociation_runtimeException() throws Exception {
717         int[] types = new int[] {1};
718         int[] values = new int[] {2};
719         doThrow(new RuntimeException("D'OH!")).when(mService)
720                 .setUserIdentificationAssociation(anyInt(), same(types), same(values), notNull());
721         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
722 
723         AsyncFuture<UserIdentificationAssociationResponse> future =
724                 mMgr.setUserIdentificationAssociation(types, values);
725 
726         assertThat(future).isNotNull();
727         UserIdentificationAssociationResponse result = getResult(future);
728         assertThat(result.isSuccess()).isFalse();
729         assertThat(result.getValues()).isNull();
730         assertThat(result.getErrorMessage()).isNull();
731     }
732 
733     @Test
testSetUserIdentificationAssociation_ok()734     public void testSetUserIdentificationAssociation_ok() throws Exception {
735         int[] types = new int[] { 1, 2, 3 };
736         int[] values = new int[] { 10, 20, 30 };
737         doAnswer((inv) -> {
738             @SuppressWarnings("unchecked")
739             AndroidFuture<UserIdentificationAssociationResponse> future =
740                     (AndroidFuture<UserIdentificationAssociationResponse>) inv
741                             .getArguments()[3];
742             UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse
743                     .forSuccess(values, "D'OH!");
744             future.complete(response);
745             return null;
746         }).when(mService)
747                 .setUserIdentificationAssociation(anyInt(), same(types), same(values), notNull());
748         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
749 
750         AsyncFuture<UserIdentificationAssociationResponse> future =
751                 mMgr.setUserIdentificationAssociation(types, values);
752 
753         assertThat(future).isNotNull();
754         UserIdentificationAssociationResponse result = getResult(future);
755         assertThat(result.isSuccess()).isTrue();
756         assertThat(result.getValues()).asList().containsAtLeast(10, 20, 30).inOrder();
757         assertThat(result.getErrorMessage()).isEqualTo("D'OH!");
758     }
759 
760     @Test
testIsUserHalUserAssociation()761     public void testIsUserHalUserAssociation() throws Exception {
762         when(mService.isUserHalUserAssociationSupported()).thenReturn(false).thenReturn(true);
763 
764         assertThat(mMgr.isUserHalUserAssociationSupported()).isFalse();
765         assertThat(mMgr.isUserHalUserAssociationSupported()).isTrue();
766     }
767 
768     @Test
testIsUserHalUserAssociation_remoteException()769     public void testIsUserHalUserAssociation_remoteException() throws Exception {
770         doThrow(new RemoteException("D'OH!")).when(mService).isUserHalUserAssociationSupported();
771         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
772 
773         assertThat(mMgr.isUserHalUserAssociationSupported()).isFalse();
774     }
775 
776     @Test
testIsUserHalUserAssociation_runtimeException()777     public void testIsUserHalUserAssociation_runtimeException() throws Exception {
778         doThrow(new RuntimeException("D'OH!")).when(mService).isUserHalUserAssociationSupported();
779 
780         assertThat(mMgr.isUserHalUserAssociationSupported()).isFalse();
781     }
782 
expectServiceSwitchUserSucceeds(@serIdInt int userId, @UserSwitchResult.Status int status)783     private void expectServiceSwitchUserSucceeds(@UserIdInt int userId,
784             @UserSwitchResult.Status int status) throws RemoteException {
785         doAnswer((invocation) -> {
786             @SuppressWarnings("unchecked")
787             ResultCallbackImpl<UserSwitchResult> resultCallbackImpl =
788                     (ResultCallbackImpl<UserSwitchResult>) invocation.getArguments()[2];
789             resultCallbackImpl.complete(new UserSwitchResult(status, /* errorMessage= */ null));
790             return null;
791         }).when(mService).switchUser(eq(userId), anyInt(), notNull(), anyBoolean());
792     }
793 
expectServiceSwitchUserFails(@serIdInt int userId, Exception e)794     private void expectServiceSwitchUserFails(@UserIdInt int userId, Exception e) throws Exception {
795         doThrow(e).when(mService).switchUser(eq(userId), anyInt(), notNull(), anyBoolean());
796     }
797 
expectServiceLogoutUserSucceeds(@serSwitchResult.Status int status)798     private void expectServiceLogoutUserSucceeds(@UserSwitchResult.Status int status)
799             throws RemoteException {
800         doAnswer((invocation) -> {
801             @SuppressWarnings("unchecked")
802             ResultCallbackImpl<UserSwitchResult> resultCallbackImpl =
803                     (ResultCallbackImpl<UserSwitchResult>) invocation.getArguments()[1];
804             resultCallbackImpl.complete(new UserSwitchResult(status, /* errorMessage= */ null));
805             return null;
806         }).when(mService).logoutUser(anyInt(), notNull());
807     }
808 
expectServiceLogoutUserFails(Exception e)809     private void expectServiceLogoutUserFails(Exception e) throws Exception {
810         doThrow(e).when(mService).logoutUser(anyInt(), notNull());
811     }
812 
expectServiceRemoveUserSucceeds(@serIdInt int userId)813     private void expectServiceRemoveUserSucceeds(@UserIdInt int userId) throws RemoteException {
814         doAnswer((invocation) -> {
815             @SuppressWarnings("unchecked")
816             ResultCallbackImpl<UserRemovalResult> resultResultCallbackImpl =
817                     (ResultCallbackImpl<UserRemovalResult>) invocation.getArguments()[1];
818             resultResultCallbackImpl.complete(
819                     new UserRemovalResult(UserRemovalResult.STATUS_SUCCESSFUL));
820             return null;
821         }).when(mService).removeUser(eq(userId), notNull());
822     }
823 
expectServiceCreateUserSucceeds(@ullable String name, @NonNull String userType, @UserInfoFlag int flags, @UserCreationResult.Status int status)824     private void expectServiceCreateUserSucceeds(@Nullable String name,
825             @NonNull String userType, @UserInfoFlag int flags,
826             @UserCreationResult.Status int status) throws RemoteException {
827         doAnswer((invocation) -> {
828             @SuppressWarnings("unchecked")
829             UserInfo newUser = new UserTestingHelper.UserInfoBuilder(108)
830                     .setName(name).setType(userType).setFlags(flags).build();
831             ResultCallbackImpl<UserCreationResult> resultCallbackImpl =
832                     (ResultCallbackImpl<UserCreationResult>) invocation.getArguments()[2];
833             resultCallbackImpl.complete(new UserCreationResult(status, newUser.getUserHandle()));
834             return null;
835         }).when(mService).createUser(notNull(), anyInt(), notNull());
836     }
837 
expectServiceCreateUserFails()838     private void expectServiceCreateUserFails() throws RemoteException {
839         doThrow(new RemoteException("D'OH!")).when(mService).createUser(notNull(), anyInt(),
840                 notNull());
841     }
842 
setExistingUsers(int... userIds)843     private void setExistingUsers(int... userIds) {
844         // TODO(b/197184481): move this logic to helper classes (UserTestingHelper.java &
845         // AndroidMockitoHelper.java)
846         List<UserHandle> userHandles =  Arrays.stream(userIds)
847                 .mapToObj(id -> UserHandle.of(id))
848                 .collect(Collectors.toList());
849         when(mUserManager.getUserHandles(/* excludeDying= */ true)).thenReturn(userHandles);
850     }
851 
mockIsHeadlessSystemUserMode(boolean mode)852     private void mockIsHeadlessSystemUserMode(boolean mode) {
853         mMgr = new CarUserManager(mCar, mService, mUserManager,
854                 /* isHeadlessSystemUserMode= */ mode);
855     }
856 }
857