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 com.android.car.hal; 17 18 import static android.car.VehiclePropertyIds.CREATE_USER; 19 import static android.car.VehiclePropertyIds.CURRENT_GEAR; 20 import static android.car.VehiclePropertyIds.INITIAL_USER_INFO; 21 import static android.car.VehiclePropertyIds.REMOVE_USER; 22 import static android.car.VehiclePropertyIds.SWITCH_USER; 23 import static android.car.VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION; 24 import static android.hardware.automotive.vehicle.InitialUserInfoRequestType.COLD_BOOT; 25 import static android.hardware.automotive.vehicle.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER; 26 import static android.hardware.automotive.vehicle.UserIdentificationAssociationType.CUSTOM_1; 27 import static android.hardware.automotive.vehicle.UserIdentificationAssociationType.KEY_FOB; 28 import static android.hardware.automotive.vehicle.UserIdentificationAssociationValue.ASSOCIATED_CURRENT_USER; 29 30 import static com.android.car.hal.HalPropValueMatcher.isProperty; 31 import static com.android.car.hal.HalPropValueMatcher.isPropertyWithValues; 32 import static com.android.car.hal.VehicleHalTestingHelper.newConfig; 33 import static com.android.car.hal.VehicleHalTestingHelper.newSubscribableConfig; 34 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 35 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 36 37 import static com.google.common.truth.Truth.assertThat; 38 import static com.google.common.truth.Truth.assertWithMessage; 39 40 import static org.junit.Assert.assertThrows; 41 import static org.junit.Assert.fail; 42 import static org.mockito.ArgumentMatchers.anyInt; 43 import static org.mockito.ArgumentMatchers.anyString; 44 import static org.mockito.ArgumentMatchers.eq; 45 import static org.mockito.Mockito.doAnswer; 46 import static org.mockito.Mockito.doThrow; 47 import static org.mockito.Mockito.never; 48 import static org.mockito.Mockito.spy; 49 import static org.mockito.Mockito.timeout; 50 import static org.mockito.Mockito.times; 51 import static org.mockito.Mockito.when; 52 53 import android.annotation.NonNull; 54 import android.annotation.Nullable; 55 import android.car.hardware.property.VehicleHalStatusCode; 56 import android.car.test.mocks.AbstractExtendedMockitoTestCase; 57 import android.car.test.mocks.JavaMockitoHelper; 58 import android.hardware.automotive.vehicle.CreateUserRequest; 59 import android.hardware.automotive.vehicle.CreateUserResponse; 60 import android.hardware.automotive.vehicle.CreateUserStatus; 61 import android.hardware.automotive.vehicle.InitialUserInfoResponse; 62 import android.hardware.automotive.vehicle.InitialUserInfoResponseAction; 63 import android.hardware.automotive.vehicle.RemoveUserRequest; 64 import android.hardware.automotive.vehicle.SwitchUserMessageType; 65 import android.hardware.automotive.vehicle.SwitchUserRequest; 66 import android.hardware.automotive.vehicle.SwitchUserResponse; 67 import android.hardware.automotive.vehicle.SwitchUserStatus; 68 import android.hardware.automotive.vehicle.UserIdentificationAssociation; 69 import android.hardware.automotive.vehicle.UserIdentificationGetRequest; 70 import android.hardware.automotive.vehicle.UserIdentificationResponse; 71 import android.hardware.automotive.vehicle.UserIdentificationSetAssociation; 72 import android.hardware.automotive.vehicle.UserIdentificationSetRequest; 73 import android.hardware.automotive.vehicle.UserInfo; 74 import android.hardware.automotive.vehicle.UsersInfo; 75 import android.os.Handler; 76 import android.os.Looper; 77 import android.os.ServiceSpecificException; 78 import android.os.SystemClock; 79 import android.os.UserHandle; 80 import android.util.Log; 81 import android.util.Pair; 82 83 import com.android.car.CarLocalServices; 84 import com.android.car.CarStatsLog; 85 import com.android.car.internal.os.CarSystemProperties; 86 import com.android.car.user.CarUserService; 87 88 import org.junit.After; 89 import org.junit.Before; 90 import org.junit.Test; 91 import org.junit.runner.RunWith; 92 import org.mockito.ArgumentCaptor; 93 import org.mockito.Mock; 94 import org.mockito.junit.MockitoJUnitRunner; 95 96 import java.util.ArrayList; 97 import java.util.Arrays; 98 import java.util.Collections; 99 import java.util.List; 100 import java.util.Optional; 101 import java.util.concurrent.CountDownLatch; 102 import java.util.concurrent.TimeUnit; 103 import java.util.concurrent.atomic.AtomicReference; 104 105 @RunWith(MockitoJUnitRunner.class) 106 public final class UserHalServiceTest extends AbstractExtendedMockitoTestCase { 107 108 private static final String TAG = UserHalServiceTest.class.getSimpleName(); 109 110 /** 111 * Timeout passed to {@link UserHalService} methods. This is the timeout for which 112 * {@link UserHalService} wait for the property change event and return 113 * {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} if HAL doesn't respond. This timeout is used 114 * where we expect HAL to return something and {@link UserHalService} methods are not expected 115 * to timeout. Tests are not supposed to wait for this much so this value can be high. If test 116 * requires HAL to timeout, then use {@link HAL_TIMEOUT_MS}. 117 */ 118 private static final int HAL_TIMEOUT_MS = 5_000; 119 120 /** 121 * Timeout passed to {@link UserHalService} methods only if test expects that call will be 122 * timeout and {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} is expected response. A higher 123 * value for this is going to slow down tests. If this timeout is used, then it is expected that 124 * {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} is checked. 125 */ 126 private static final int HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS = 250; 127 128 /** 129 * If tests expect {@link UserHalService} call to timeout, and if they require to sleep then 130 * sleep for this much time. This value should be higher than {@link HAL_TIMEOUT_MS}. A much 131 * higher value for this is going to slow down the test. 132 */ 133 private static final int WAITING_TIME_FOR_NEGATIVE_TESTS_MS = HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS 134 + 100; 135 136 /** 137 * Timeout for {@link GenericHalCallback#assertCalled()} for tests. In each case, 138 * {@link UserHalService} is supposed to return something - either a valid response or a 139 * timeout. This timeout is for the callback to wait for the response. A higher value of this 140 * timeout should not affect the test duration. 141 */ 142 private static final int CALLBACK_TIMEOUT = 5_000; 143 144 // Used when crafting a request property - the real value will be set by the mock. 145 private static final int REQUEST_ID_PLACE_HOLDER = 1111; 146 147 private static final int DEFAULT_REQUEST_ID = 2222; 148 149 private static final int DEFAULT_USER_ID = 333; 150 private static final int DEFAULT_USER_FLAGS = 444; 151 152 private static final int INITIAL_USER_INFO_RESPONSE_ACTION = 108; 153 154 @Mock 155 private VehicleHal mVehicleHal; 156 @Mock 157 private CarUserService mCarUserService; 158 159 private final Handler mHandler = new Handler(Looper.getMainLooper()); 160 161 private final UserInfo mUser0 = new UserInfo(); 162 private final UserInfo mUser100 = new UserInfo(); 163 164 private final UsersInfo mUsersInfo = UserHalHelper.emptyUsersInfo(); 165 166 // Must be a spy so we can mock getNextRequestId() 167 private UserHalService mUserHalService; 168 169 private final HalPropValueBuilder mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/true); 170 UserHalServiceTest()171 public UserHalServiceTest() { 172 super(UserHalService.TAG); 173 } 174 175 @Override onSessionBuilder(CustomMockitoSessionBuilder builder)176 protected void onSessionBuilder(CustomMockitoSessionBuilder builder) { 177 builder.spyStatic(CarSystemProperties.class) 178 .spyStatic(CarStatsLog.class); 179 } 180 181 @Before setFixtures()182 public void setFixtures() { 183 mockUserHalEnabled(true); 184 when(mVehicleHal.getHalPropValueBuilder()).thenReturn(mPropValueBuilder); 185 mUserHalService = spy(new UserHalService(mVehicleHal, mHandler)); 186 // Needs at least one property, otherwise isSupported() and isUserAssociationSupported() 187 // will return false 188 mUserHalService.takeProperties( 189 Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 190 newSubscribableConfig(CREATE_USER), 191 newSubscribableConfig(REMOVE_USER), 192 newSubscribableConfig(SWITCH_USER), 193 newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION))); 194 195 mUser0.userId = 0; 196 mUser0.flags = 100; 197 mUser100.userId = 100; 198 mUser100.flags = 110; 199 200 mUsersInfo.currentUser = mUser0; 201 mUsersInfo.numberUsers = 2; 202 mUsersInfo.existingUsers = new UserInfo[]{mUser0, mUser100}; 203 204 CarLocalServices.addService(CarUserService.class, mCarUserService); 205 } 206 207 @After clearFixtures()208 public void clearFixtures() { 209 CarLocalServices.removeServiceForTest(CarUserService.class); 210 } 211 212 @Test testTakeSupportedProperties_supportedNoProperties()213 public void testTakeSupportedProperties_supportedNoProperties() { 214 // Cannot use mUserHalService because it's already set with supported properties 215 UserHalService myHalService = new UserHalService(mVehicleHal); 216 217 myHalService.takeProperties(Collections.emptyList()); 218 assertThat(myHalService.isSupported()).isFalse(); 219 assertThat(myHalService.isUserAssociationSupported()).isFalse(); 220 } 221 222 @Test testTakeSupportedProperties_supportedFewProperties()223 public void testTakeSupportedProperties_supportedFewProperties() { 224 // Cannot use mUserHalService because it's already set with supported properties 225 UserHalService myHalService = new UserHalService(mVehicleHal); 226 myHalService.takeProperties( 227 Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 228 newSubscribableConfig(CREATE_USER), 229 newSubscribableConfig(REMOVE_USER))); 230 231 assertThat(myHalService.isSupported()).isFalse(); 232 assertThat(myHalService.isUserAssociationSupported()).isFalse(); 233 } 234 235 @Test testTakeSupportedProperties_supportedAllCorePropertiesButEnabledPropertyNotSet()236 public void testTakeSupportedProperties_supportedAllCorePropertiesButEnabledPropertyNotSet() { 237 mockUserHalEnabled(null); 238 // Cannot use mUserHalService because it's already set with supported properties 239 UserHalService myHalService = new UserHalService(mVehicleHal); 240 myHalService.takeProperties( 241 Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 242 newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER), 243 newSubscribableConfig(SWITCH_USER))); 244 245 assertThat(myHalService.isSupported()).isFalse(); 246 assertThat(myHalService.isUserAssociationSupported()).isFalse(); 247 } 248 249 @Test testTakeSupportedProperties_supportedAllCorePropertiesButDisabled()250 public void testTakeSupportedProperties_supportedAllCorePropertiesButDisabled() { 251 mockUserHalEnabled(false); 252 // Cannot use mUserHalService because it's already set with supported properties 253 UserHalService myHalService = new UserHalService(mVehicleHal); 254 myHalService.takeProperties( 255 Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 256 newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER), 257 newSubscribableConfig(SWITCH_USER))); 258 259 assertThat(myHalService.isSupported()).isFalse(); 260 assertThat(myHalService.isUserAssociationSupported()).isFalse(); 261 } 262 263 @Test testTakeSupportedProperties_supportedAllCoreProperties()264 public void testTakeSupportedProperties_supportedAllCoreProperties() { 265 // Cannot use mUserHalService because it's already set with supported properties 266 UserHalService myHalService = new UserHalService(mVehicleHal); 267 myHalService.takeProperties( 268 Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 269 newSubscribableConfig(CREATE_USER), 270 newSubscribableConfig(REMOVE_USER), 271 newSubscribableConfig(SWITCH_USER))); 272 273 assertThat(myHalService.isSupported()).isTrue(); 274 assertThat(myHalService.isUserAssociationSupported()).isFalse(); 275 } 276 277 @Test testTakeSupportedProperties_supportedAllPropertiesButDisabled()278 public void testTakeSupportedProperties_supportedAllPropertiesButDisabled() { 279 mockUserHalEnabled(false); 280 // Cannot use mUserHalService because it's already set with supported properties 281 UserHalService myHalService = new UserHalService(mVehicleHal); 282 myHalService.takeProperties( 283 Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 284 newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER), 285 newSubscribableConfig(SWITCH_USER), 286 newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION))); 287 288 assertThat(myHalService.isSupported()).isFalse(); 289 assertThat(myHalService.isUserAssociationSupported()).isTrue(); 290 } 291 292 @Test testTakeSupportedProperties_supportedAllPropertiesButEnablePropertyNotSet()293 public void testTakeSupportedProperties_supportedAllPropertiesButEnablePropertyNotSet() { 294 mockUserHalEnabled(null); 295 // Cannot use mUserHalService because it's already set with supported properties 296 UserHalService myHalService = new UserHalService(mVehicleHal); 297 myHalService.takeProperties( 298 Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 299 newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER), 300 newSubscribableConfig(SWITCH_USER), 301 newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION))); 302 303 assertThat(myHalService.isSupported()).isFalse(); 304 assertThat(myHalService.isUserAssociationSupported()).isTrue(); 305 } 306 307 @Test testTakeSupportedProperties_supportedAllProperties()308 public void testTakeSupportedProperties_supportedAllProperties() { 309 // Cannot use mUserHalService because it's already set with supported properties 310 UserHalService myHalService = new UserHalService(mVehicleHal); 311 myHalService.takeProperties( 312 Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 313 newSubscribableConfig(CREATE_USER), 314 newSubscribableConfig(REMOVE_USER), 315 newSubscribableConfig(SWITCH_USER), 316 newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION))); 317 318 assertThat(myHalService.isSupported()).isTrue(); 319 assertThat(myHalService.isUserAssociationSupported()).isTrue(); 320 } 321 322 @Test testTakeSupportedPropertiesAndInit()323 public void testTakeSupportedPropertiesAndInit() { 324 // Cannot use mUserHalService because it's already set with supported properties 325 UserHalService myHalService = new UserHalService(mVehicleHal); 326 HalPropConfig unsupportedConfig = newConfig(CURRENT_GEAR); 327 328 myHalService.takeProperties( 329 Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 330 newSubscribableConfig(CREATE_USER), 331 newSubscribableConfig(REMOVE_USER), 332 newSubscribableConfig(SWITCH_USER), unsupportedConfig, 333 newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION))); 334 335 336 // Ideally there should be 2 test methods (one for takeSupportedProperties() and one for 337 // init()), but on "real life" VehicleHal calls these 2 methods in sequence, and the latter 338 // depends on the properties set by the former, so it's ok to test both here... 339 myHalService.init(); 340 verify(mVehicleHal).subscribePropertySafe(myHalService, INITIAL_USER_INFO); 341 verify(mVehicleHal).subscribePropertySafe(myHalService, CREATE_USER); 342 verify(mVehicleHal).subscribePropertySafe(myHalService, REMOVE_USER); 343 verify(mVehicleHal).subscribePropertySafe(myHalService, SWITCH_USER); 344 verify(mVehicleHal).subscribePropertySafe(myHalService, USER_IDENTIFICATION_ASSOCIATION); 345 } 346 347 @Test testSupportedProperties()348 public void testSupportedProperties() { 349 assertThat(mUserHalService.getAllSupportedProperties()).asList().containsExactly( 350 INITIAL_USER_INFO, CREATE_USER, REMOVE_USER, SWITCH_USER, 351 USER_IDENTIFICATION_ASSOCIATION); 352 } 353 354 @Test testGetUserInfo_noHalSupported()355 public void testGetUserInfo_noHalSupported() { 356 // Cannot use mUserHalService because it's already set with supported properties 357 UserHalService myHalService = new UserHalService(mVehicleHal); 358 359 assertThrows(IllegalStateException.class, () -> myHalService.getInitialUserInfo(COLD_BOOT, 360 HAL_TIMEOUT_MS, mUsersInfo, noOpCallback())); 361 } 362 363 @Test testGetUserInfo_invalidTimeout()364 public void testGetUserInfo_invalidTimeout() { 365 assertThrows(IllegalArgumentException.class, () -> 366 mUserHalService.getInitialUserInfo(COLD_BOOT, 0, mUsersInfo, noOpCallback())); 367 assertThrows(IllegalArgumentException.class, () -> 368 mUserHalService.getInitialUserInfo(COLD_BOOT, -1, mUsersInfo, noOpCallback())); 369 } 370 371 @Test testGetUserInfo_noUsersInfo()372 public void testGetUserInfo_noUsersInfo() { 373 assertThrows(NullPointerException.class, () -> mUserHalService.getInitialUserInfo(COLD_BOOT, 374 HAL_TIMEOUT_MS, null, noOpCallback())); 375 } 376 377 @Test testGetUserInfo_noCallback()378 public void testGetUserInfo_noCallback() { 379 assertThrows(NullPointerException.class, 380 () -> mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, 381 mUsersInfo, null)); 382 } 383 384 @Test testGetUserInfo_halSetTimedOut()385 public void testGetUserInfo_halSetTimedOut() throws Exception { 386 replySetPropertyWithTimeoutException(INITIAL_USER_INFO); 387 388 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 389 CALLBACK_TIMEOUT); 390 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 391 callback); 392 393 callback.assertCalled(); 394 assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT); 395 assertThat(callback.response).isNull(); 396 397 // Make sure the pending request was removed 398 SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS); 399 callback.assertNotCalledAgain(); 400 } 401 402 @Test testGetUserInfo_halDidNotReply()403 public void testGetUserInfo_halDidNotReply() throws Exception { 404 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 405 CALLBACK_TIMEOUT); 406 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo, 407 callback); 408 409 callback.assertCalled(); 410 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 411 assertThat(callback.response).isNull(); 412 } 413 414 @Test testGetUserInfo_secondCallFailWhilePending()415 public void testGetUserInfo_secondCallFailWhilePending() throws Exception { 416 GenericHalCallback<InitialUserInfoResponse> callback1 = new GenericHalCallback<>( 417 CALLBACK_TIMEOUT); 418 GenericHalCallback<InitialUserInfoResponse> callback2 = new GenericHalCallback<>( 419 CALLBACK_TIMEOUT); 420 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo, 421 callback1); 422 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 423 callback2); 424 425 callback1.assertCalled(); 426 assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 427 assertThat(callback1.response).isNull(); 428 429 callback2.assertCalled(); 430 assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION); 431 assertThat(callback1.response).isNull(); 432 } 433 434 @Test testGetUserInfo_halReplyWithWrongRequestId()435 public void testGetUserInfo_halReplyWithWrongRequestId() throws Exception { 436 HalPropValue propResponse = createPropRequest(INITIAL_USER_INFO, 437 REQUEST_ID_PLACE_HOLDER, INITIAL_USER_INFO_RESPONSE_ACTION); 438 439 replySetPropertyWithOnChangeEvent(INITIAL_USER_INFO, propResponse, 440 /* rightRequestId= */ false); 441 442 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 443 CALLBACK_TIMEOUT); 444 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo, 445 callback); 446 447 callback.assertCalled(); 448 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 449 assertThat(callback.response).isNull(); 450 } 451 452 @Test testGetUserInfo_halReturnedInvalidAction()453 public void testGetUserInfo_halReturnedInvalidAction() throws Exception { 454 HalPropValue propResponse = createPropRequest(INITIAL_USER_INFO, 455 REQUEST_ID_PLACE_HOLDER, INITIAL_USER_INFO_RESPONSE_ACTION); 456 457 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 458 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true); 459 460 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 461 CALLBACK_TIMEOUT); 462 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 463 callback); 464 465 callback.assertCalled(); 466 467 // Make sure the arguments were properly converted 468 assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT); 469 470 // Assert response 471 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 472 assertThat(callback.response).isNull(); 473 } 474 475 @Test testGetUserInfo_successDefault()476 public void testGetUserInfo_successDefault() throws Exception { 477 getUserInfoSuccessTest(1); 478 } 479 getUserInfoSuccessTest(int count)480 private void getUserInfoSuccessTest(int count) throws Exception { 481 HalPropValue propResponse = createPropRequest(INITIAL_USER_INFO, 482 REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.DEFAULT); 483 484 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 485 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true); 486 487 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 488 CALLBACK_TIMEOUT); 489 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 490 callback); 491 492 callback.assertCalled(); 493 494 // Make sure the arguments were properly converted 495 assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT); 496 497 // Assert response 498 assertCallbackStatus(callback, HalCallback.STATUS_OK); 499 InitialUserInfoResponse actualResponse = callback.response; 500 assertThat(actualResponse.action).isEqualTo(InitialUserInfoResponseAction.DEFAULT); 501 assertThat(actualResponse.userNameToCreate).isEmpty(); 502 assertThat(actualResponse.userToSwitchOrCreate).isNotNull(); 503 assertThat(actualResponse.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL); 504 assertThat(actualResponse.userToSwitchOrCreate.flags).isEqualTo(0); 505 506 int responseActionDefault = CarStatsLog 507 .CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED__RESPONSE_ACTION__DEFAULT; 508 verify(() -> CarStatsLog.write( 509 eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED), 510 anyInt(), 511 eq(CarStatsLog 512 .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__COLD_BOOT), 513 eq(HAL_TIMEOUT_MS)), times(count)); 514 verify(() -> CarStatsLog.write( 515 eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED), 516 anyInt(), 517 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK), 518 eq(responseActionDefault), 519 eq(UserHandle.USER_NULL), eq(0), eq("")), timeout(CALLBACK_TIMEOUT).times(count)); 520 } 521 522 @Test testGetUserInfo_successSwitchUser()523 public void testGetUserInfo_successSwitchUser() throws Exception { 524 int userIdToSwitch = 42; 525 HalPropValue propResponse = createPropRequest(INITIAL_USER_INFO, 526 REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.SWITCH, 527 new int[]{userIdToSwitch}); 528 529 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 530 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true); 531 532 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 533 CALLBACK_TIMEOUT); 534 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 535 callback); 536 537 callback.assertCalled(); 538 539 // Make sure the arguments were properly converted 540 assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT); 541 542 assertCallbackStatus(callback, HalCallback.STATUS_OK); 543 InitialUserInfoResponse actualResponse = callback.response; 544 assertThat(actualResponse.action).isEqualTo(InitialUserInfoResponseAction.SWITCH); 545 assertThat(actualResponse.userNameToCreate).isEmpty(); 546 UserInfo userToSwitch = actualResponse.userToSwitchOrCreate; 547 assertThat(userToSwitch).isNotNull(); 548 assertThat(userToSwitch.userId).isEqualTo(userIdToSwitch); 549 assertThat(userToSwitch.flags).isEqualTo(0); 550 551 verify(() -> CarStatsLog.write( 552 eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED), 553 anyInt(), 554 eq(CarStatsLog 555 .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__COLD_BOOT), 556 eq(HAL_TIMEOUT_MS))); 557 verify(() -> CarStatsLog.write( 558 eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED), 559 anyInt(), 560 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK), 561 eq(CarStatsLog 562 .CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED__RESPONSE_ACTION__SWITCH), 563 eq(userIdToSwitch), eq(0), eq("")), timeout(CALLBACK_TIMEOUT)); 564 } 565 566 @Test testGetUserInfo_successCreateUser()567 public void testGetUserInfo_successCreateUser() throws Exception { 568 int newUserFlags = 108; 569 String newUserName = "Groot"; 570 int unusedUserId = 666; 571 HalPropValue propResponse = createPropRequest(INITIAL_USER_INFO, 572 REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.CREATE, 573 new int[]{unusedUserId, newUserFlags}, "||" + newUserName); 574 575 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 576 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true); 577 578 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 579 CALLBACK_TIMEOUT); 580 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 581 callback); 582 583 callback.assertCalled(); 584 585 // Make sure the arguments were properly converted 586 assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT); 587 588 assertCallbackStatus(callback, HalCallback.STATUS_OK); 589 assertThat(callback.status).isEqualTo(HalCallback.STATUS_OK); 590 InitialUserInfoResponse actualResponse = callback.response; 591 assertThat(actualResponse.action).isEqualTo(InitialUserInfoResponseAction.CREATE); 592 assertThat(actualResponse.userLocales).isEmpty(); 593 assertThat(actualResponse.userNameToCreate).isEqualTo(newUserName); 594 UserInfo newUser = actualResponse.userToSwitchOrCreate; 595 assertThat(newUser).isNotNull(); 596 assertThat(newUser.userId).isEqualTo(UserHandle.USER_NULL); 597 assertThat(newUser.flags).isEqualTo(newUserFlags); 598 599 verify(() -> CarStatsLog.write( 600 eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED), 601 anyInt(), 602 eq(CarStatsLog 603 .CAR_USER_HAL_INITIAL_USER_INFO_REQUEST_REPORTED__REQUEST_TYPE__COLD_BOOT), 604 eq(HAL_TIMEOUT_MS))); 605 verify(() -> CarStatsLog.write( 606 eq(CarStatsLog.CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED), 607 anyInt(), 608 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK), 609 eq(CarStatsLog 610 .CAR_USER_HAL_INITIAL_USER_INFO_RESPONSE_REPORTED__RESPONSE_ACTION__CREATE), 611 eq(UserHandle.USER_NULL), eq(newUserFlags), eq("")), timeout(CALLBACK_TIMEOUT)); 612 } 613 614 @Test testGetUserInfo_twoSuccessfulCalls()615 public void testGetUserInfo_twoSuccessfulCalls() throws Exception { 616 getUserInfoSuccessTest(1); 617 618 getUserInfoSuccessTest(2); 619 } 620 621 @Test testSwitchUser_noHalSupported()622 public void testSwitchUser_noHalSupported() { 623 // Cannot use mUserHalService because it's already set with supported properties 624 UserHalService myHalService = new UserHalService(mVehicleHal); 625 626 assertThrows(IllegalStateException.class, 627 () -> myHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), 628 HAL_TIMEOUT_MS, noOpCallback())); 629 } 630 631 @Test testSwitchUser_invalidTimeout()632 public void testSwitchUser_invalidTimeout() { 633 assertThrows(IllegalArgumentException.class, () -> mUserHalService 634 .switchUser(createUserSwitchRequest(mUser100, mUsersInfo), 0, noOpCallback())); 635 assertThrows(IllegalArgumentException.class, () -> mUserHalService 636 .switchUser(createUserSwitchRequest(mUser100, mUsersInfo), -1, noOpCallback())); 637 } 638 639 @Test testSwitchUser_noUsersInfo()640 public void testSwitchUser_noUsersInfo() { 641 assertThrows(IllegalArgumentException.class, () -> mUserHalService 642 .switchUser(createUserSwitchRequest(mUser100, null), HAL_TIMEOUT_MS, 643 noOpCallback())); 644 } 645 646 @Test testSwitchUser_noCallback()647 public void testSwitchUser_noCallback() { 648 assertThrows(NullPointerException.class, () -> mUserHalService 649 .switchUser(createUserSwitchRequest(mUser100, mUsersInfo), HAL_TIMEOUT_MS, null)); 650 } 651 652 @Test testSwitchUser_nullRequest()653 public void testSwitchUser_nullRequest() { 654 assertThrows(NullPointerException.class, () -> mUserHalService 655 .switchUser(null, HAL_TIMEOUT_MS, noOpCallback())); 656 } 657 658 @Test testSwitchUser_noTarget()659 public void testSwitchUser_noTarget() { 660 assertThrows(NullPointerException.class, () -> mUserHalService 661 .switchUser(createUserSwitchRequest(null, mUsersInfo), HAL_TIMEOUT_MS, 662 noOpCallback())); 663 } 664 665 @Test testSwitchUser_halSetTimedOut()666 public void testSwitchUser_halSetTimedOut() throws Exception { 667 replySetPropertyWithTimeoutException(SWITCH_USER); 668 669 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 670 CALLBACK_TIMEOUT); 671 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), 672 HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 673 callback); 674 675 callback.assertCalled(); 676 assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT); 677 assertThat(callback.response).isNull(); 678 679 // Make sure the pending request was removed 680 SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS); 681 callback.assertNotCalledAgain(); 682 } 683 684 @Test testSwitchUser_halDidNotReply()685 public void testSwitchUser_halDidNotReply() throws Exception { 686 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 687 CALLBACK_TIMEOUT); 688 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), 689 HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 690 callback); 691 692 callback.assertCalled(); 693 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 694 assertThat(callback.response).isNull(); 695 } 696 697 @Test testSwitchUser_halReplyWithWrongRequestId()698 public void testSwitchUser_halReplyWithWrongRequestId() throws Exception { 699 HalPropValue propResponse = createPropRequest(SWITCH_USER, 700 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE, 701 new int[]{SwitchUserStatus.SUCCESS}); 702 703 replySetPropertyWithOnChangeEvent(SWITCH_USER, propResponse, 704 /* rightRequestId= */ false); 705 706 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 707 CALLBACK_TIMEOUT); 708 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), 709 HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 710 callback); 711 712 callback.assertCalled(); 713 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 714 assertThat(callback.response).isNull(); 715 716 int switchRequestAndroid = CarStatsLog 717 .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID; 718 int statusUnspecified = 719 CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__UNSPECIFIED; 720 int statusWrongHalResponse = CarStatsLog 721 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE; 722 723 verify(() -> CarStatsLog.write( 724 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED), 725 anyInt(), 726 eq(switchRequestAndroid), 727 eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS))); 728 verify(() -> CarStatsLog.write( 729 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED), 730 anyInt(), 731 eq(statusWrongHalResponse), 732 eq(statusUnspecified)), timeout(CALLBACK_TIMEOUT)); 733 } 734 735 @Test testSwitchUser_halReturnedInvalidMessageType()736 public void testSwitchUser_halReturnedInvalidMessageType() throws Exception { 737 HalPropValue propResponse = createPropRequest(SWITCH_USER, 738 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.LEGACY_ANDROID_SWITCH, 739 new int[]{SwitchUserStatus.SUCCESS}); 740 741 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 742 SWITCH_USER, propResponse, /* rightRequestId= */ true); 743 744 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 745 CALLBACK_TIMEOUT); 746 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), HAL_TIMEOUT_MS, 747 callback); 748 749 callback.assertCalled(); 750 751 // Make sure the arguments were properly converted 752 assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH, 753 mUser100); 754 755 // Assert response 756 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 757 assertThat(callback.response).isNull(); 758 } 759 760 @Test testSwitchUser_success()761 public void testSwitchUser_success() throws Exception { 762 HalPropValue propResponse = createPropRequest(SWITCH_USER, 763 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE, 764 new int[]{SwitchUserStatus.SUCCESS}); 765 766 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 767 SWITCH_USER, propResponse, /* rightRequestId= */ true); 768 769 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 770 CALLBACK_TIMEOUT); 771 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), HAL_TIMEOUT_MS, 772 callback); 773 774 callback.assertCalled(); 775 776 // Make sure the arguments were properly converted 777 assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH, 778 mUser100); 779 780 // Assert response 781 assertCallbackStatus(callback, HalCallback.STATUS_OK); 782 SwitchUserResponse actualResponse = callback.response; 783 assertThat(actualResponse.status).isEqualTo(SwitchUserStatus.SUCCESS); 784 assertThat(actualResponse.messageType).isEqualTo(SwitchUserMessageType.VEHICLE_RESPONSE); 785 assertThat(actualResponse.errorMessage).isEmpty(); 786 787 int switchRequestAndroid = CarStatsLog 788 .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID; 789 int statusSuccess = CarStatsLog 790 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__SUCCESS; 791 792 verify(() -> CarStatsLog.write( 793 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED), 794 anyInt(), 795 eq(switchRequestAndroid), 796 eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_MS))); 797 verify(() -> CarStatsLog.write( 798 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED), 799 anyInt(), 800 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK), 801 eq(statusSuccess)), timeout(CALLBACK_TIMEOUT)); 802 } 803 804 @Test testSwitchUser_failure()805 public void testSwitchUser_failure() throws Exception { 806 HalPropValue propResponse = createPropRequest(SWITCH_USER, 807 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE, 808 new int[]{SwitchUserStatus.FAILURE}, "D'OH!"); 809 810 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 811 SWITCH_USER, propResponse, /* rightRequestId= */ true); 812 813 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 814 CALLBACK_TIMEOUT); 815 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), HAL_TIMEOUT_MS, 816 callback); 817 818 callback.assertCalled(); 819 820 // Make sure the arguments were properly converted 821 assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH, 822 mUser100); 823 824 // Assert response 825 assertCallbackStatus(callback, HalCallback.STATUS_OK); 826 SwitchUserResponse actualResponse = callback.response; 827 assertThat(actualResponse.status).isEqualTo(SwitchUserStatus.FAILURE); 828 assertThat(actualResponse.messageType).isEqualTo(SwitchUserMessageType.VEHICLE_RESPONSE); 829 assertThat(actualResponse.errorMessage).isEqualTo("D'OH!"); 830 831 int switchRequestAndroid = CarStatsLog 832 .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID; 833 int statusFailure = CarStatsLog 834 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__FAILURE; 835 836 verify(() -> CarStatsLog.write( 837 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED), 838 anyInt(), 839 eq(switchRequestAndroid), 840 eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_MS))); 841 verify(() -> CarStatsLog.write( 842 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED), 843 anyInt(), 844 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK), 845 eq(statusFailure)), timeout(CALLBACK_TIMEOUT)); 846 } 847 848 @Test testSwitchUser_secondCallFailWhilePending()849 public void testSwitchUser_secondCallFailWhilePending() throws Exception { 850 GenericHalCallback<SwitchUserResponse> callback1 = new GenericHalCallback<>( 851 CALLBACK_TIMEOUT); 852 GenericHalCallback<SwitchUserResponse> callback2 = new GenericHalCallback<>( 853 CALLBACK_TIMEOUT); 854 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), 855 HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 856 callback1); 857 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), HAL_TIMEOUT_MS, 858 callback2); 859 860 callback1.assertCalled(); 861 assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 862 assertThat(callback1.response).isNull(); 863 864 callback2.assertCalled(); 865 assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION); 866 assertThat(callback1.response).isNull(); 867 } 868 869 @Test testSwitchUser_halReturnedInvalidStatus()870 public void testSwitchUser_halReturnedInvalidStatus() throws Exception { 871 HalPropValue propResponse = createPropRequest(SWITCH_USER, 872 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE, 873 new int[]{/*status =*/ 110}); 874 875 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 876 SWITCH_USER, propResponse, /* rightRequestId= */ true); 877 878 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 879 CALLBACK_TIMEOUT); 880 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), HAL_TIMEOUT_MS, 881 callback); 882 883 callback.assertCalled(); 884 885 // Make sure the arguments were properly converted 886 assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH, 887 mUser100); 888 889 // Assert response 890 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 891 assertThat(callback.response).isNull(); 892 893 int switchRequestAndroid = CarStatsLog 894 .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID; 895 int statusFailure = CarStatsLog 896 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__FAILURE; 897 int statusWrongHalResponse = CarStatsLog 898 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE; 899 verify(() -> CarStatsLog.write( 900 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED), 901 anyInt(), 902 eq(switchRequestAndroid), 903 eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_MS))); 904 verify(() -> CarStatsLog.write( 905 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED), 906 anyInt(), 907 eq(statusWrongHalResponse), 908 eq(statusFailure)), timeout(CALLBACK_TIMEOUT)); 909 } 910 911 @Test testSwitchUser_halResponseAfterTimeout()912 public void testSwitchUser_halResponseAfterTimeout() throws Exception { 913 HalPropValue propResponse = createPropRequest(SWITCH_USER, 914 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE, 915 new int[]{SwitchUserStatus.SUCCESS}); 916 CountDownLatch latch = new CountDownLatch(1); 917 918 replySetPropertyWithOnChangeEvent(SWITCH_USER, propResponse, /* rightRequestId= */ true, 919 latch); 920 921 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 922 CALLBACK_TIMEOUT); 923 924 mUserHalService.switchUser(createUserSwitchRequest(mUser100, mUsersInfo), 925 HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, callback); 926 927 int switchRequestAndroid = CarStatsLog 928 .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID; 929 verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED), 930 anyInt(), 931 eq(switchRequestAndroid), 932 eq(0), eq(100), eq(100), eq(110), eq(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS))); 933 934 // The event has not been sent before the callback. 935 callback.assertCalled(); 936 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 937 assertThat(callback.response).isNull(); 938 939 // Now send the event after the request already timed-out. 940 latch.countDown(); 941 942 int statusUnspecified = 943 CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__UNSPECIFIED; 944 int statusWrongHalResponse = CarStatsLog 945 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE; 946 947 verify(() -> CarStatsLog.write( 948 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED), 949 anyInt(), 950 eq(statusWrongHalResponse), 951 eq(statusUnspecified)), timeout(CALLBACK_TIMEOUT)); 952 } 953 954 @Test testUserSwitch_OEMRequest_success()955 public void testUserSwitch_OEMRequest_success() throws Exception { 956 int requestId = -4; 957 int targetUserId = 11; 958 HalPropValue propResponse = createPropRequest(SWITCH_USER, requestId, 959 SwitchUserMessageType.VEHICLE_REQUEST, new int[]{targetUserId}); 960 961 mUserHalService.onHalEvents(Arrays.asList(propResponse)); 962 waitForHandler(); 963 964 verify(mCarUserService).switchAndroidUserFromHal(requestId, targetUserId); 965 966 int switchRequestOem = CarStatsLog 967 .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_OEM; 968 969 verify(() -> CarStatsLog.write( 970 eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED), 971 /* requestId= */ anyInt(), 972 eq(switchRequestOem), 973 /* current user id= */ eq(-1), 974 /* current user flag= */ eq(-1), 975 /* targetUserId= */ eq(11), 976 /* target user flag= */ eq(-1), 977 /* timeout_ms= */ eq(-1))); 978 } 979 980 @Test testUserSwitch_OEMRequest_failure_positiveRequestId()981 public void testUserSwitch_OEMRequest_failure_positiveRequestId() throws Exception { 982 int requestId = 4; 983 int targetUserId = 11; 984 HalPropValue propResponse = createPropRequest(SWITCH_USER, requestId, 985 SwitchUserMessageType.VEHICLE_REQUEST, new int[]{targetUserId}); 986 987 mUserHalService.onHalEvents(Arrays.asList(propResponse)); 988 waitForHandler(); 989 990 verify(mCarUserService, never()).switchAndroidUserFromHal(anyInt(), anyInt()); 991 } 992 993 @Test testPostSwitchResponse_noHalSupported()994 public void testPostSwitchResponse_noHalSupported() { 995 // Cannot use mUserHalService because it's already set with supported properties 996 UserHalService myHalService = new UserHalService(mVehicleHal); 997 998 assertThrows(IllegalStateException.class, 999 () -> myHalService.postSwitchResponse(UserHalHelper.emptySwitchUserRequest())); 1000 } 1001 1002 @Test testPostSwitchResponse_nullRequest()1003 public void testPostSwitchResponse_nullRequest() { 1004 assertThrows(NullPointerException.class, () -> mUserHalService.postSwitchResponse(null)); 1005 } 1006 1007 @Test testPostSwitchResponse_noUsersInfo()1008 public void testPostSwitchResponse_noUsersInfo() { 1009 SwitchUserRequest request = createUserSwitchRequest(mUser100, null); 1010 request.requestId = 42; 1011 assertThrows(IllegalArgumentException.class, 1012 () -> mUserHalService.postSwitchResponse(request)); 1013 } 1014 1015 @Test testPostSwitchResponse_HalCalledWithCorrectProp()1016 public void testPostSwitchResponse_HalCalledWithCorrectProp() { 1017 SwitchUserRequest request = createUserSwitchRequest(mUser100, mUsersInfo); 1018 request.requestId = 42; 1019 mUserHalService.postSwitchResponse(request); 1020 ArgumentCaptor<HalPropValue> propCaptor = 1021 ArgumentCaptor.forClass(HalPropValue.class); 1022 verify(mVehicleHal).set(propCaptor.capture()); 1023 HalPropValue prop = propCaptor.getValue(); 1024 assertHalSetSwitchUserRequest(prop, SwitchUserMessageType.ANDROID_POST_SWITCH, mUser100); 1025 } 1026 1027 @Test testLegacyUserSwitch_nullRequest()1028 public void testLegacyUserSwitch_nullRequest() { 1029 assertThrows(NullPointerException.class, () -> mUserHalService.legacyUserSwitch(null)); 1030 } 1031 1032 @Test testLegacyUserSwitch_noMessageType()1033 public void testLegacyUserSwitch_noMessageType() { 1034 SwitchUserRequest request = UserHalHelper.emptySwitchUserRequest(); 1035 1036 assertThrows(IllegalArgumentException.class, 1037 () -> mUserHalService.legacyUserSwitch(request)); 1038 } 1039 1040 @Test testLegacyUserSwitch_noTargetUserInfo()1041 public void testLegacyUserSwitch_noTargetUserInfo() { 1042 SwitchUserRequest request = UserHalHelper.emptySwitchUserRequest(); 1043 request.messageType = SwitchUserMessageType.ANDROID_SWITCH; 1044 1045 assertThrows(IllegalArgumentException.class, 1046 () -> mUserHalService.legacyUserSwitch(request)); 1047 } 1048 1049 @Test testRemoveUser_noHalSupported()1050 public void testRemoveUser_noHalSupported() { 1051 // Cannot use mUserHalService because it's already set with supported properties 1052 UserHalService myHalService = new UserHalService(mVehicleHal); 1053 1054 assertThrows(IllegalStateException.class, 1055 () -> myHalService.removeUser(UserHalHelper.emptyRemoveUserRequest())); 1056 } 1057 1058 @Test testRemoveUser_nullRequest()1059 public void testRemoveUser_nullRequest() { 1060 RemoveUserRequest request = null; 1061 1062 assertThrows(NullPointerException.class, 1063 () -> mUserHalService.removeUser(request)); 1064 } 1065 1066 @Test testRemoveUser_noRequestId()1067 public void testRemoveUser_noRequestId() { 1068 RemoveUserRequest request = UserHalHelper.emptyRemoveUserRequest(); 1069 1070 assertThrows(IllegalArgumentException.class, 1071 () -> mUserHalService.removeUser(request)); 1072 } 1073 1074 @Test testRemoveUser_noRemovedUserInfo()1075 public void testRemoveUser_noRemovedUserInfo() { 1076 RemoveUserRequest request = UserHalHelper.emptyRemoveUserRequest(); 1077 request.requestId = 1; 1078 1079 assertThrows(IllegalArgumentException.class, 1080 () -> mUserHalService.removeUser(request)); 1081 } 1082 1083 @Test testRemoveUser_noUsersInfo()1084 public void testRemoveUser_noUsersInfo() { 1085 RemoveUserRequest request = UserHalHelper.emptyRemoveUserRequest(); 1086 request.requestId = 1; 1087 request.removedUserInfo = mUser100; 1088 1089 assertThrows(IllegalArgumentException.class, 1090 () -> mUserHalService.removeUser(request)); 1091 } 1092 1093 @Test testRemoveUser_HalCalledWithCorrectProp()1094 public void testRemoveUser_HalCalledWithCorrectProp() { 1095 RemoveUserRequest request = UserHalHelper.emptyRemoveUserRequest(); 1096 request.removedUserInfo = mUser100; 1097 request.usersInfo = mUsersInfo; 1098 ArgumentCaptor<HalPropValue> propCaptor = 1099 ArgumentCaptor.forClass(HalPropValue.class); 1100 1101 mUserHalService.removeUser(request); 1102 1103 verify(mVehicleHal).set(propCaptor.capture()); 1104 assertHalSetRemoveUserRequest(propCaptor.getValue(), mUser100); 1105 } 1106 1107 @Test testLegacyUserSwitch_noHalSupported()1108 public void testLegacyUserSwitch_noHalSupported() { 1109 // Cannot use mUserHalService because it's already set with supported properties 1110 UserHalService myHalService = new UserHalService(mVehicleHal); 1111 1112 assertThrows(IllegalStateException.class, 1113 () -> myHalService.legacyUserSwitch(UserHalHelper.emptySwitchUserRequest())); 1114 } 1115 1116 @Test testLegacyUserSwitch_noUsersInfo()1117 public void testLegacyUserSwitch_noUsersInfo() { 1118 SwitchUserRequest request = UserHalHelper.emptySwitchUserRequest(); 1119 request.messageType = SwitchUserMessageType.ANDROID_SWITCH; 1120 request.targetUser = mUser100; 1121 1122 assertThrows(IllegalArgumentException.class, 1123 () -> mUserHalService.legacyUserSwitch(request)); 1124 } 1125 1126 @Test testLegacyUserSwitch_HalCalledWithCorrectProp()1127 public void testLegacyUserSwitch_HalCalledWithCorrectProp() { 1128 SwitchUserRequest request = UserHalHelper.emptySwitchUserRequest(); 1129 request.messageType = SwitchUserMessageType.LEGACY_ANDROID_SWITCH; 1130 request.targetUser = mUser100; 1131 request.usersInfo = mUsersInfo; 1132 1133 mUserHalService.legacyUserSwitch(request); 1134 ArgumentCaptor<HalPropValue> propCaptor = 1135 ArgumentCaptor.forClass(HalPropValue.class); 1136 verify(mVehicleHal).set(propCaptor.capture()); 1137 HalPropValue prop = propCaptor.getValue(); 1138 assertHalSetSwitchUserRequest(prop, SwitchUserMessageType.LEGACY_ANDROID_SWITCH, 1139 mUser100); 1140 } 1141 1142 @Test testCreateUser_noHalSupported()1143 public void testCreateUser_noHalSupported() { 1144 // Cannot use mUserHalService because it's already set with supported properties 1145 UserHalService myHalService = new UserHalService(mVehicleHal); 1146 1147 assertThrows(IllegalStateException.class, 1148 () -> myHalService.createUser(UserHalHelper.emptyCreateUserRequest(), 1149 HAL_TIMEOUT_MS, noOpCallback())); 1150 } 1151 1152 @Test testCreateUser_noRequest()1153 public void testCreateUser_noRequest() { 1154 assertThrows(NullPointerException.class, () -> mUserHalService 1155 .createUser(null, HAL_TIMEOUT_MS, noOpCallback())); 1156 } 1157 1158 @Test testCreateUser_invalidTimeout()1159 public void testCreateUser_invalidTimeout() { 1160 assertThrows(IllegalArgumentException.class, () -> mUserHalService 1161 .createUser(UserHalHelper.emptyCreateUserRequest(), 0, noOpCallback())); 1162 assertThrows(IllegalArgumentException.class, () -> mUserHalService 1163 .createUser(UserHalHelper.emptyCreateUserRequest(), -1, noOpCallback())); 1164 } 1165 1166 @Test testCreateUser_noCallback()1167 public void testCreateUser_noCallback() { 1168 CreateUserRequest request = UserHalHelper.emptyCreateUserRequest(); 1169 request.newUserInfo.userId = 10; 1170 request.usersInfo.existingUsers = new UserInfo[]{request.newUserInfo}; 1171 1172 assertThrows(NullPointerException.class, () -> mUserHalService 1173 .createUser(request, HAL_TIMEOUT_MS, null)); 1174 } 1175 1176 /** 1177 * Creates a valid {@link CreateUserRequest} for tests that doesn't check its contents. 1178 */ 1179 @NonNull newValidCreateUserRequest()1180 private CreateUserRequest newValidCreateUserRequest() { 1181 CreateUserRequest request = UserHalHelper.emptyCreateUserRequest(); 1182 request.newUserInfo = mUser100; 1183 request.usersInfo = mUsersInfo; 1184 return request; 1185 } 1186 1187 @Test testCreateUser_halSetTimedOut()1188 public void testCreateUser_halSetTimedOut() throws Exception { 1189 replySetPropertyWithTimeoutException(CREATE_USER); 1190 1191 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 1192 CALLBACK_TIMEOUT); 1193 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 1194 callback); 1195 1196 callback.assertCalled(); 1197 assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT); 1198 assertThat(callback.response).isNull(); 1199 1200 // Make sure the pending request was removed 1201 SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS); 1202 callback.assertNotCalledAgain(); 1203 } 1204 1205 @Test testCreateUser_halDidNotReply()1206 public void testCreateUser_halDidNotReply() throws Exception { 1207 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 1208 CALLBACK_TIMEOUT); 1209 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 1210 callback); 1211 1212 callback.assertCalled(); 1213 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 1214 assertThat(callback.response).isNull(); 1215 } 1216 1217 @Test testCreateUser_halReplyWithWrongRequestId()1218 public void testCreateUser_halReplyWithWrongRequestId() throws Exception { 1219 HalPropValue propResponse = createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER); 1220 1221 replySetPropertyWithOnChangeEvent(CREATE_USER, propResponse, 1222 /* rightRequestId= */ false); 1223 1224 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 1225 CALLBACK_TIMEOUT); 1226 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 1227 callback); 1228 1229 callback.assertCalled(); 1230 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 1231 assertThat(callback.response).isNull(); 1232 } 1233 1234 @Test testCreateUser_success()1235 public void testCreateUser_success() throws Exception { 1236 HalPropValue propResponse = createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER, 1237 new int[]{CreateUserStatus.SUCCESS}); 1238 1239 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 1240 CREATE_USER, propResponse, /* rightRequestId= */ true); 1241 1242 CreateUserRequest request = UserHalHelper.emptyCreateUserRequest(); 1243 request.newUserInfo = mUser100; 1244 request.usersInfo = mUsersInfo; 1245 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 1246 CALLBACK_TIMEOUT); 1247 mUserHalService.createUser(request, HAL_TIMEOUT_MS, callback); 1248 1249 callback.assertCalled(); 1250 1251 // Make sure the arguments were properly converted 1252 assertHalSetCreateUserRequest(reqCaptor.get(), request); 1253 1254 // Assert response 1255 assertCallbackStatus(callback, HalCallback.STATUS_OK); 1256 CreateUserResponse actualResponse = callback.response; 1257 assertThat(actualResponse.status).isEqualTo(CreateUserStatus.SUCCESS); 1258 assertThat(actualResponse.errorMessage).isEmpty(); 1259 1260 int createRequest = CarStatsLog 1261 .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__CREATE_REQUEST; 1262 int statusOk = CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK; 1263 int statusSuccess = CarStatsLog 1264 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__SUCCESS; 1265 verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED), 1266 anyInt(), eq(createRequest), eq(0), eq(100), eq(100), eq(110), 1267 eq(HAL_TIMEOUT_MS))); 1268 verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED), 1269 anyInt(), eq(statusOk), eq(statusSuccess)), timeout(CALLBACK_TIMEOUT)); 1270 } 1271 1272 @Test testCreateUser_failure()1273 public void testCreateUser_failure() throws Exception { 1274 HalPropValue propResponse = createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER, 1275 /* requestType= */ null, new int[]{CreateUserStatus.FAILURE}, "D'OH!"); 1276 1277 AtomicReference<HalPropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 1278 CREATE_USER, propResponse, /* rightRequestId= */ true); 1279 1280 CreateUserRequest request = UserHalHelper.emptyCreateUserRequest(); 1281 request.newUserInfo = mUser100; 1282 request.usersInfo = mUsersInfo; 1283 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 1284 CALLBACK_TIMEOUT); 1285 mUserHalService.createUser(request, HAL_TIMEOUT_MS, callback); 1286 1287 callback.assertCalled(); 1288 1289 // Make sure the arguments were properly converted 1290 assertHalSetCreateUserRequest(reqCaptor.get(), request); 1291 1292 // Assert response 1293 assertCallbackStatus(callback, HalCallback.STATUS_OK); 1294 CreateUserResponse actualResponse = callback.response; 1295 assertThat(actualResponse.status).isEqualTo(CreateUserStatus.FAILURE); 1296 assertThat(actualResponse.errorMessage).isEqualTo("D'OH!"); 1297 1298 int createRequest = CarStatsLog 1299 .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__CREATE_REQUEST; 1300 int statusOk = CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK; 1301 int statusFailure = CarStatsLog 1302 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__REQUEST_STATUS__FAILURE; 1303 verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED), 1304 anyInt(), eq(createRequest), eq(0), eq(100), eq(100), eq(110), 1305 eq(HAL_TIMEOUT_MS))); 1306 verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED), 1307 anyInt(), eq(statusOk), eq(statusFailure)), timeout(CALLBACK_TIMEOUT)); 1308 } 1309 1310 @Test testCreateUser_secondCallFailWhilePending()1311 public void testCreateUser_secondCallFailWhilePending() throws Exception { 1312 GenericHalCallback<CreateUserResponse> callback1 = new GenericHalCallback<>( 1313 CALLBACK_TIMEOUT); 1314 GenericHalCallback<CreateUserResponse> callback2 = new GenericHalCallback<>( 1315 CALLBACK_TIMEOUT); 1316 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 1317 callback1); 1318 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_MS, callback2); 1319 1320 callback1.assertCalled(); 1321 assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 1322 assertThat(callback1.response).isNull(); 1323 1324 callback2.assertCalled(); 1325 assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION); 1326 assertThat(callback1.response).isNull(); 1327 } 1328 1329 @Test testCreateUser_halReturnedInvalidStatus()1330 public void testCreateUser_halReturnedInvalidStatus() throws Exception { 1331 HalPropValue propResponse = createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER, 1332 new int[]{/*status =*/ -1}); 1333 1334 replySetPropertyWithOnChangeEvent(CREATE_USER, propResponse, /* rightRequestId= */ true); 1335 1336 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 1337 CALLBACK_TIMEOUT); 1338 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_MS, callback); 1339 1340 callback.assertCalled(); 1341 1342 // Assert response 1343 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 1344 assertThat(callback.response).isNull(); 1345 } 1346 1347 @Test testGetUserAssociation_noHalSupported()1348 public void testGetUserAssociation_noHalSupported() { 1349 // Cannot use mUserHalService because it's already set with supported properties 1350 UserHalService myHalService = new UserHalService(mVehicleHal); 1351 1352 assertThrows(IllegalStateException.class, 1353 () -> myHalService.getUserAssociation(new UserIdentificationGetRequest())); 1354 } 1355 1356 @Test testGetUserAssociation_nullRequest()1357 public void testGetUserAssociation_nullRequest() { 1358 assertThrows(NullPointerException.class, () -> mUserHalService.getUserAssociation(null)); 1359 } 1360 1361 @Test testGetUserAssociation_requestWithDuplicatedTypes()1362 public void testGetUserAssociation_requestWithDuplicatedTypes() { 1363 UserIdentificationGetRequest request = new UserIdentificationGetRequest(); 1364 request.numberAssociationTypes = 2; 1365 request.associationTypes = new int[]{KEY_FOB, KEY_FOB}; 1366 1367 assertThrows(IllegalArgumentException.class, 1368 () -> mUserHalService.getUserAssociation(request)); 1369 } 1370 1371 @Test testGetUserAssociation_invalidResponse()1372 public void testGetUserAssociation_invalidResponse() { 1373 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1374 /* areaId= */ 0, 1375 new int[]{ 1376 DEFAULT_REQUEST_ID, 1377 // 1 associations 1378 1, 1379 // type only, it's missing value 1380 KEY_FOB}); 1381 1382 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1383 propResponse); 1384 1385 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1386 } 1387 1388 @Test testGetUserAssociation_nullResponse()1389 public void testGetUserAssociation_nullResponse() { 1390 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest(null); 1391 1392 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1393 1394 verifyValidGetUserIdentificationRequestMade(); 1395 } 1396 1397 @Test testGetUserAssociation_ServiceExceptionFromHal()1398 public void testGetUserAssociation_ServiceExceptionFromHal() { 1399 UserIdentificationGetRequest request = 1400 replyToValidGetUserIdentificationRequestWithException( 1401 new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN)); 1402 1403 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1404 1405 verifyValidGetUserIdentificationRequestMade(); 1406 } 1407 1408 @Test testGetUserAssociation_wrongNumberOfAssociationsOnResponse()1409 public void testGetUserAssociation_wrongNumberOfAssociationsOnResponse() { 1410 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1411 /* areaId= */ 0, 1412 new int[]{ 1413 DEFAULT_REQUEST_ID, 1414 // 2 associations 1415 2, 1416 KEY_FOB, 1417 ASSOCIATED_CURRENT_USER, 1418 CUSTOM_1, 1419 ASSOCIATED_CURRENT_USER 1420 }); 1421 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1422 propResponse); 1423 1424 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1425 1426 verifyValidGetUserIdentificationRequestMade(); 1427 } 1428 1429 @Test testGetUserAssociation_typesOnResponseMismatchTypesOnRequest()1430 public void testGetUserAssociation_typesOnResponseMismatchTypesOnRequest() { 1431 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1432 /* areaId= */ 0, 1433 new int[]{ 1434 DEFAULT_REQUEST_ID, 1435 // 1 association 1436 1, 1437 CUSTOM_1, 1438 ASSOCIATED_CURRENT_USER 1439 }); 1440 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1441 propResponse); 1442 1443 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1444 1445 verifyValidGetUserIdentificationRequestMade(); 1446 } 1447 1448 @Test testGetUserAssociation_requestIdMismatch()1449 public void testGetUserAssociation_requestIdMismatch() { 1450 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1451 /* areaId= */ 0, 1452 new int[]{ 1453 DEFAULT_REQUEST_ID + 1, 1454 // 1 association 1455 1, 1456 KEY_FOB, 1457 ASSOCIATED_CURRENT_USER 1458 }); 1459 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1460 propResponse); 1461 1462 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1463 1464 verifyValidGetUserIdentificationRequestMade(); 1465 } 1466 1467 @Test testGetUserAssociation_ok()1468 public void testGetUserAssociation_ok() { 1469 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1470 /* areaId= */ 0, 1471 new int[]{ 1472 DEFAULT_REQUEST_ID, 1473 // 1 association 1474 1, 1475 KEY_FOB, 1476 ASSOCIATED_CURRENT_USER 1477 }); 1478 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1479 propResponse); 1480 1481 UserIdentificationResponse response = mUserHalService.getUserAssociation(request); 1482 1483 assertThat(response.requestId).isEqualTo(DEFAULT_REQUEST_ID); 1484 assertThat(response.numberAssociation).isEqualTo(1); 1485 assertThat(response.associations.length).isEqualTo(1); 1486 UserIdentificationAssociation actualAssociation = response.associations[0]; 1487 assertThat(actualAssociation.type).isEqualTo(KEY_FOB); 1488 assertThat(actualAssociation.value).isEqualTo(ASSOCIATED_CURRENT_USER); 1489 } 1490 1491 @Test testSetUserAssociation_noHalSupported()1492 public void testSetUserAssociation_noHalSupported() { 1493 // Cannot use mUserHalService because it's already set with supported properties 1494 UserHalService myHalService = new UserHalService(mVehicleHal); 1495 1496 assertThrows(IllegalStateException.class, 1497 () -> myHalService.setUserAssociation(HAL_TIMEOUT_MS, 1498 UserHalHelper.emptyUserIdentificationSetRequest(), noOpCallback())); 1499 } 1500 1501 @Test testSetUserAssociation_invalidTimeout()1502 public void testSetUserAssociation_invalidTimeout() { 1503 UserIdentificationSetRequest request = UserHalHelper.emptyUserIdentificationSetRequest(); 1504 assertThrows(IllegalArgumentException.class, () -> 1505 mUserHalService.setUserAssociation(0, request, noOpCallback())); 1506 assertThrows(IllegalArgumentException.class, () -> 1507 mUserHalService.setUserAssociation(-1, request, noOpCallback())); 1508 } 1509 1510 @Test testSetUserAssociation_nullRequest()1511 public void testSetUserAssociation_nullRequest() { 1512 assertThrows(NullPointerException.class, () -> 1513 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, null, noOpCallback())); 1514 } 1515 1516 @Test testSetUserAssociation_nullCallback()1517 public void testSetUserAssociation_nullCallback() { 1518 UserIdentificationSetRequest request = UserHalHelper.emptyUserIdentificationSetRequest(); 1519 assertThrows(NullPointerException.class, () -> 1520 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, null)); 1521 } 1522 1523 @Test testSetUserAssociation_requestWithDuplicatedTypes()1524 public void testSetUserAssociation_requestWithDuplicatedTypes() { 1525 UserIdentificationSetRequest request = UserHalHelper.emptyUserIdentificationSetRequest(); 1526 request.numberAssociations = 2; 1527 UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation(); 1528 association1.type = KEY_FOB; 1529 association1.value = ASSOCIATE_CURRENT_USER; 1530 request.associations = new UserIdentificationSetAssociation[]{association1, association1}; 1531 1532 assertThrows(IllegalArgumentException.class, () -> 1533 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, noOpCallback())); 1534 } 1535 1536 @Test testSetUserAssociation_halSetTimedOut()1537 public void testSetUserAssociation_halSetTimedOut() throws Exception { 1538 UserIdentificationSetRequest request = validUserIdentificationSetRequest(); 1539 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1540 CALLBACK_TIMEOUT); 1541 replySetPropertyWithTimeoutException(USER_IDENTIFICATION_ASSOCIATION); 1542 1543 mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback); 1544 1545 callback.assertCalled(); 1546 assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT); 1547 assertThat(callback.response).isNull(); 1548 1549 // Make sure the pending request was removed 1550 SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS); 1551 callback.assertNotCalledAgain(); 1552 } 1553 1554 @Test testSetUserAssociation_halDidNotReply()1555 public void testSetUserAssociation_halDidNotReply() throws Exception { 1556 UserIdentificationSetRequest request = validUserIdentificationSetRequest(); 1557 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1558 CALLBACK_TIMEOUT); 1559 1560 mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback); 1561 1562 callback.assertCalled(); 1563 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 1564 assertThat(callback.response).isNull(); 1565 } 1566 1567 @Test testSetUserAssociation_secondCallFailWhilePending()1568 public void testSetUserAssociation_secondCallFailWhilePending() throws Exception { 1569 UserIdentificationSetRequest request = validUserIdentificationSetRequest(); 1570 GenericHalCallback<UserIdentificationResponse> callback1 = new GenericHalCallback<>( 1571 CALLBACK_TIMEOUT); 1572 GenericHalCallback<UserIdentificationResponse> callback2 = new GenericHalCallback<>( 1573 CALLBACK_TIMEOUT); 1574 1575 mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback1); 1576 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback2); 1577 1578 callback1.assertCalled(); 1579 assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 1580 assertThat(callback1.response).isNull(); 1581 1582 callback2.assertCalled(); 1583 assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION); 1584 assertThat(callback1.response).isNull(); 1585 } 1586 1587 @Test testSetUserAssociation_responseWithWrongRequestId()1588 public void testSetUserAssociation_responseWithWrongRequestId() throws Exception { 1589 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1590 /* areaId= */ 0, new int[]{ 1591 DEFAULT_REQUEST_ID, 1592 // 1 association 1593 1, 1594 KEY_FOB, 1595 ASSOCIATED_CURRENT_USER 1596 }); 1597 1598 AtomicReference<HalPropValue> propRequest = replySetPropertyWithOnChangeEvent( 1599 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ false); 1600 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1601 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1602 CALLBACK_TIMEOUT); 1603 1604 mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback); 1605 1606 // Assert request 1607 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1608 // Assert response 1609 callback.assertCalled(); 1610 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 1611 assertThat(callback.response).isNull(); 1612 verify(() -> CarStatsLog.write( 1613 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED), 1614 anyInt(), 1615 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET), 1616 eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString())); 1617 } 1618 1619 @Test testSetUserAssociation_notEnoughValuesOnResponse()1620 public void testSetUserAssociation_notEnoughValuesOnResponse() throws Exception { 1621 // need at least 4: requestId, number associations, type1, value1 1622 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1623 /* areaId= */ 0, new int[]{1, 2, 3}); 1624 1625 AtomicReference<HalPropValue> propRequest = replySetPropertyWithOnChangeEvent( 1626 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true); 1627 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1628 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1629 CALLBACK_TIMEOUT); 1630 1631 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback); 1632 1633 // Assert request 1634 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1635 // Assert response 1636 callback.assertCalled(); 1637 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 1638 assertThat(callback.response).isNull(); 1639 1640 int wrongHalResponse = CarStatsLog 1641 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE; 1642 verify(() -> CarStatsLog.write( 1643 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED), 1644 anyInt(), 1645 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET), 1646 eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString())); 1647 verify(() -> CarStatsLog.write( 1648 eq(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED), 1649 anyInt(), eq(wrongHalResponse), eq(0), eq(""), eq("")), timeout(CALLBACK_TIMEOUT)); 1650 } 1651 1652 @Test testSetUserAssociation_wrongNumberOfAssociationsOnResponse()1653 public void testSetUserAssociation_wrongNumberOfAssociationsOnResponse() throws Exception { 1654 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1655 /* areaId= */ 0, new int[]{ 1656 DEFAULT_REQUEST_ID, 1657 // 2 associations; request is just 1 1658 2, 1659 KEY_FOB, 1660 ASSOCIATED_CURRENT_USER, 1661 CUSTOM_1, 1662 ASSOCIATED_CURRENT_USER 1663 }); 1664 1665 AtomicReference<HalPropValue> propRequest = replySetPropertyWithOnChangeEvent( 1666 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true); 1667 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1668 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1669 CALLBACK_TIMEOUT); 1670 1671 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback); 1672 1673 // Assert request 1674 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1675 // Assert response 1676 callback.assertCalled(); 1677 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 1678 assertThat(callback.response).isNull(); 1679 1680 int wrongHalResponse = CarStatsLog 1681 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE; 1682 verify(() -> CarStatsLog.write( 1683 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED), 1684 anyInt(), 1685 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET), 1686 eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString())); 1687 verify(() -> CarStatsLog.write( 1688 eq(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED), 1689 anyInt(), eq(wrongHalResponse), eq(2), anyString(), anyString()), 1690 timeout(CALLBACK_TIMEOUT)); 1691 } 1692 1693 @Test testSetUserAssociation_typeMismatchOnResponse()1694 public void testSetUserAssociation_typeMismatchOnResponse() throws Exception { 1695 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1696 /* areaId= */ 0, new int[]{ 1697 DEFAULT_REQUEST_ID, 1698 // 1 association 1699 1, 1700 // request is KEY_FOB 1701 CUSTOM_1, 1702 ASSOCIATED_CURRENT_USER 1703 }); 1704 1705 AtomicReference<HalPropValue> propRequest = replySetPropertyWithOnChangeEvent( 1706 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true); 1707 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1708 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1709 CALLBACK_TIMEOUT); 1710 1711 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback); 1712 1713 // Assert request 1714 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1715 // Assert response 1716 callback.assertCalled(); 1717 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 1718 assertThat(callback.response).isNull(); 1719 1720 int wrongHalResponse = CarStatsLog 1721 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__WRONG_HAL_RESPONSE; 1722 verify(() -> CarStatsLog.write( 1723 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED), 1724 anyInt(), 1725 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET), 1726 eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString())); 1727 verify(() -> CarStatsLog.write( 1728 eq(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED), 1729 anyInt(), eq(wrongHalResponse), eq(1), anyString(), anyString()), 1730 timeout(CALLBACK_TIMEOUT)); 1731 } 1732 1733 @Test testSetUserAssociation_ok()1734 public void testSetUserAssociation_ok() throws Exception { 1735 HalPropValue propResponse = mPropValueBuilder.build(USER_IDENTIFICATION_ASSOCIATION, 1736 /* areaId= */ 0, new int[]{ 1737 DEFAULT_REQUEST_ID, 1738 // 1 association 1739 1, 1740 KEY_FOB, 1741 ASSOCIATED_CURRENT_USER 1742 }); 1743 1744 AtomicReference<HalPropValue> propRequest = replySetPropertyWithOnChangeEvent( 1745 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true); 1746 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1747 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1748 CALLBACK_TIMEOUT); 1749 1750 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback); 1751 1752 // Assert request 1753 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1754 // Assert response 1755 callback.assertCalled(); 1756 assertCallbackStatus(callback, HalCallback.STATUS_OK); 1757 1758 UserIdentificationResponse actualResponse = callback.response; 1759 1760 assertThat(actualResponse.requestId).isEqualTo(DEFAULT_REQUEST_ID); 1761 assertThat(actualResponse.numberAssociation).isEqualTo(1); 1762 assertThat(actualResponse.associations.length).isEqualTo(1); 1763 UserIdentificationAssociation actualAssociation = actualResponse.associations[0]; 1764 assertThat(actualAssociation.type).isEqualTo(KEY_FOB); 1765 assertThat(actualAssociation.value).isEqualTo(ASSOCIATED_CURRENT_USER); 1766 1767 int statusOk = CarStatsLog 1768 .CAR_USER_HAL_MODIFY_USER_RESPONSE_REPORTED__CALLBACK_STATUS__OK; 1769 verify(() -> CarStatsLog.write( 1770 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED), 1771 anyInt(), 1772 eq(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET), 1773 eq(DEFAULT_USER_ID), eq(DEFAULT_USER_FLAGS), eq(1), anyString(), anyString())); 1774 verify(() -> CarStatsLog.write( 1775 eq(CarStatsLog.CAR_USER_HAL_SET_USER_ASSOCIATION_RESPONSE_REPORTED), 1776 anyInt(), eq(statusOk), eq(1), anyString(), anyString()), 1777 timeout(CALLBACK_TIMEOUT)); 1778 } 1779 1780 /** 1781 * Asserts the given {@link UsersInfo} is properly represented in the {@link HalPropValue}. 1782 * 1783 * @param value property containing the info 1784 * @param info info to be checked 1785 * @param initialIndex first index of the info values in the property's {@code int32Values} 1786 */ assertUsersInfo(HalPropValue value, UsersInfo info, int initialIndex)1787 private void assertUsersInfo(HalPropValue value, UsersInfo info, int initialIndex) { 1788 // TODO: consider using UserHalHelper to convert the property into a specific request, 1789 // and compare the request's UsersInfo. 1790 // But such method is not needed in production code yet. 1791 List<Integer> values = getIntValues(value); 1792 assertWithMessage("wrong values size").that(values) 1793 .hasSize(initialIndex + 3 + info.numberUsers * 2); 1794 1795 int i = initialIndex; 1796 assertWithMessage("currentUser.id mismatch at index %s", i).that(values.get(i)) 1797 .isEqualTo(info.currentUser.userId); 1798 i++; 1799 assertWithMessage("currentUser.flags mismatch at index %s", i).that(values.get(i)) 1800 .isEqualTo(info.currentUser.flags); 1801 i++; 1802 assertWithMessage("numberUsers mismatch at index %s", i).that(values.get(i)) 1803 .isEqualTo(info.numberUsers); 1804 i++; 1805 1806 for (int j = 0; j < info.numberUsers; j++) { 1807 int actualUserId = values.get(i++); 1808 int actualUserFlags = values.get(i++); 1809 UserInfo expectedUser = info.existingUsers[j]; 1810 assertWithMessage("wrong id for existing user#%s at index %s", j, i) 1811 .that(actualUserId).isEqualTo(expectedUser.userId); 1812 assertWithMessage("wrong flags for existing user#%s at index %s", j, i) 1813 .that(actualUserFlags).isEqualTo(expectedUser.flags); 1814 } 1815 } 1816 1817 /** 1818 * @see #replySetPropertyWithOnChangeEvent(int, HalPropValue, boolean, int) 1819 */ replySetPropertyWithOnChangeEvent(int prop, HalPropValue response, boolean rightRequestId)1820 private AtomicReference<HalPropValue> replySetPropertyWithOnChangeEvent(int prop, 1821 HalPropValue response, boolean rightRequestId) throws Exception { 1822 return replySetPropertyWithOnChangeEvent(prop, response, rightRequestId, 1823 /* countDownLatch= */ null); 1824 } 1825 1826 /** 1827 * Sets the VHAL mock to emulate a property change event upon a call to set a property. 1828 * 1829 * @param prop prop to be set 1830 * @param response response to be set on event 1831 * @param rightRequestId whether the response id should match the request 1832 * @param latch A {@link CountDownLatch} to control when to send the event. 1833 * @return A copy of the update property value. 1834 * 1835 * @return reference to the value passed to {@code set()}. 1836 */ replySetPropertyWithOnChangeEvent(int prop, HalPropValue response, boolean rightRequestId, CountDownLatch latch)1837 private AtomicReference<HalPropValue> replySetPropertyWithOnChangeEvent(int prop, 1838 HalPropValue response, boolean rightRequestId, CountDownLatch latch) 1839 throws Exception { 1840 AtomicReference<HalPropValue> ref = new AtomicReference<>(); 1841 doAnswer((inv) -> { 1842 HalPropValue request = inv.getArgument(0); 1843 ref.set(request); 1844 int requestId = request.getInt32Value(0); 1845 int responseId = rightRequestId ? requestId : requestId + 1000; 1846 1847 int[] intValues = new int[response.getInt32ValuesSize()]; 1848 for (int i = 0; i < response.getInt32ValuesSize(); i++) { 1849 if (i == 0) { 1850 intValues[i] = responseId; 1851 continue; 1852 } 1853 intValues[i] = response.getInt32Value(i); 1854 } 1855 HalPropValue responseCopy = mPropValueBuilder.build(response.getPropId(), 1856 response.getAreaId(), response.getTimestamp(), response.getStatus(), intValues, 1857 /*floatValues=*/new float[0], /*int64Values=*/new long[0], 1858 response.getStringValue(), /*byteValues=*/new byte[0]); 1859 1860 if (latch == null) { 1861 Log.d(TAG, "replySetPropertyWithOnChangeEvent(): resp=" + responseCopy + " for req=" 1862 + request); 1863 mUserHalService.onHalEvents(Arrays.asList(responseCopy)); 1864 return null; 1865 } 1866 1867 new Thread(() -> { 1868 JavaMockitoHelper.silentAwait(latch, CALLBACK_TIMEOUT); 1869 Log.d(TAG, "replySetPropertyWithOnChangeEvent(): resp=" + responseCopy + " for req=" 1870 + request); 1871 mUserHalService.onHalEvents(Arrays.asList(responseCopy)); 1872 }, "replySetpropertyWithOnChangeEventThread").start(); 1873 1874 return null; 1875 }).when(mVehicleHal).set(isProperty(prop)); 1876 return ref; 1877 } 1878 1879 /** 1880 * Sets the VHAL mock to emulate a property timeout exception upon a call to set a property. 1881 */ replySetPropertyWithTimeoutException(int prop)1882 private void replySetPropertyWithTimeoutException(int prop) throws Exception { 1883 doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN, 1884 "PropId: 0x" + Integer.toHexString(prop))).when(mVehicleHal) 1885 .set(isProperty(prop)); 1886 } 1887 1888 @NonNull createUserSwitchRequest(@onNull UserInfo targetUser, @NonNull UsersInfo usersInfo)1889 private SwitchUserRequest createUserSwitchRequest(@NonNull UserInfo targetUser, 1890 @NonNull UsersInfo usersInfo) { 1891 SwitchUserRequest request = UserHalHelper.emptySwitchUserRequest(); 1892 request.targetUser = targetUser; 1893 request.usersInfo = usersInfo; 1894 return request; 1895 } 1896 1897 /** 1898 * Creates and set expectations for a valid request. 1899 */ replyToValidGetUserIdentificationRequest( @onNull HalPropValue response)1900 private UserIdentificationGetRequest replyToValidGetUserIdentificationRequest( 1901 @NonNull HalPropValue response) { 1902 mockNextRequestId(DEFAULT_REQUEST_ID); 1903 1904 UserIdentificationGetRequest request = new UserIdentificationGetRequest(); 1905 request.userInfo = new UserInfo(); 1906 request.userInfo.userId = DEFAULT_USER_ID; 1907 request.userInfo.flags = DEFAULT_USER_FLAGS; 1908 request.numberAssociationTypes = 1; 1909 request.associationTypes = new int[]{KEY_FOB}; 1910 1911 when(mVehicleHal.get(isPropertyWithValues(USER_IDENTIFICATION_ASSOCIATION, 1912 DEFAULT_REQUEST_ID, DEFAULT_USER_ID, DEFAULT_USER_FLAGS, 1913 /* numberAssociations= */ 1, KEY_FOB))) 1914 .thenReturn(response); 1915 1916 return request; 1917 } 1918 replyToValidGetUserIdentificationRequestWithException( Exception e)1919 private UserIdentificationGetRequest replyToValidGetUserIdentificationRequestWithException( 1920 Exception e) { 1921 mockNextRequestId(DEFAULT_REQUEST_ID); 1922 1923 UserIdentificationGetRequest request = new UserIdentificationGetRequest(); 1924 request.userInfo = new UserInfo(); 1925 request.userInfo.userId = DEFAULT_USER_ID; 1926 request.userInfo.flags = DEFAULT_USER_FLAGS; 1927 request.numberAssociationTypes = 1; 1928 request.associationTypes = new int[]{KEY_FOB}; 1929 1930 when(mVehicleHal.get(isPropertyWithValues(USER_IDENTIFICATION_ASSOCIATION, 1931 DEFAULT_REQUEST_ID, DEFAULT_USER_ID, DEFAULT_USER_FLAGS, 1932 /* numberAssociations= */ 1, KEY_FOB))).thenThrow(e); 1933 1934 return request; 1935 } 1936 1937 /** 1938 * Creates and set expectations for a valid request. 1939 */ replyToValidSetUserIdentificationRequest()1940 private UserIdentificationSetRequest replyToValidSetUserIdentificationRequest() { 1941 mockNextRequestId(DEFAULT_REQUEST_ID); 1942 return validUserIdentificationSetRequest(); 1943 } 1944 1945 /** 1946 * Creates a valid request that can be used in test cases where its content is not asserted. 1947 */ validUserIdentificationSetRequest()1948 private UserIdentificationSetRequest validUserIdentificationSetRequest() { 1949 UserIdentificationSetRequest request = UserHalHelper.emptyUserIdentificationSetRequest(); 1950 request.userInfo.userId = DEFAULT_USER_ID; 1951 request.userInfo.flags = DEFAULT_USER_FLAGS; 1952 request.numberAssociations = 1; 1953 UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation(); 1954 association1.type = KEY_FOB; 1955 association1.value = ASSOCIATE_CURRENT_USER; 1956 request.associations = new UserIdentificationSetAssociation[]{association1}; 1957 return request; 1958 } 1959 1960 /** 1961 * Run empty runnable to make sure that all posted handlers are done. 1962 */ waitForHandler()1963 private void waitForHandler() { 1964 mHandler.runWithScissors(() -> { }, /* Default timeout */ CALLBACK_TIMEOUT); 1965 } 1966 mockNextRequestId(int requestId)1967 private void mockNextRequestId(int requestId) { 1968 doReturn(requestId).when(mUserHalService).getNextRequestId(); 1969 } 1970 mockUserHalEnabled(@ullable Boolean enabled)1971 private void mockUserHalEnabled(@Nullable Boolean enabled) { 1972 Optional<Boolean> value = enabled != null ? Optional.of(enabled) : Optional.empty(); 1973 doReturn(value).when(() -> CarSystemProperties.getUserHalEnabled()); 1974 } 1975 assertInitialUserInfoSetRequest(HalPropValue req, int requestType)1976 private void assertInitialUserInfoSetRequest(HalPropValue req, int requestType) { 1977 assertThat(req.getInt32Value(1)).isEqualTo(requestType); 1978 assertUsersInfo(req, mUsersInfo, 2); 1979 } 1980 assertHalSetSwitchUserRequest(HalPropValue req, int messageType, UserInfo targetUserInfo)1981 private void assertHalSetSwitchUserRequest(HalPropValue req, int messageType, 1982 UserInfo targetUserInfo) { 1983 assertThat(req.getPropId()).isEqualTo(SWITCH_USER); 1984 assertWithMessage("wrong request Id on %s", req).that(req.getInt32Value(0)) 1985 .isAtLeast(1); 1986 assertThat(req.getInt32Value(1)).isEqualTo(messageType); 1987 assertWithMessage("targetuser.id mismatch on %s", req).that(req.getInt32Value(2)) 1988 .isEqualTo(targetUserInfo.userId); 1989 assertWithMessage("targetuser.flags mismatch on %s", req).that(req.getInt32Value(3)) 1990 .isEqualTo(targetUserInfo.flags); 1991 assertUsersInfo(req, mUsersInfo, 4); 1992 } 1993 assertHalSetRemoveUserRequest(HalPropValue req, UserInfo userInfo)1994 private void assertHalSetRemoveUserRequest(HalPropValue req, UserInfo userInfo) { 1995 assertThat(req.getPropId()).isEqualTo(REMOVE_USER); 1996 assertWithMessage("wrong request Id on %s", req).that(req.getInt32Value(0)) 1997 .isAtLeast(1); 1998 assertWithMessage("user.id mismatch on %s", req).that(req.getInt32Value(1)) 1999 .isEqualTo(userInfo.userId); 2000 assertWithMessage("user.flags mismatch on %s", req).that(req.getInt32Value(2)) 2001 .isEqualTo(userInfo.flags); 2002 assertUsersInfo(req, mUsersInfo, 3); 2003 } 2004 assertHalSetCreateUserRequest(HalPropValue prop, CreateUserRequest request)2005 private void assertHalSetCreateUserRequest(HalPropValue prop, CreateUserRequest request) { 2006 assertThat(prop.getPropId()).isEqualTo(CREATE_USER); 2007 assertWithMessage("wrong request Id on %s", prop).that(prop.getInt32Value(0)) 2008 .isEqualTo(request.requestId); 2009 assertWithMessage("newUser.userId mismatch on %s", prop).that(prop.getInt32Value(1)) 2010 .isEqualTo(request.newUserInfo.userId); 2011 assertWithMessage("newUser.flags mismatch on %s", prop).that(prop.getInt32Value(2)) 2012 .isEqualTo(request.newUserInfo.flags); 2013 assertUsersInfo(prop, request.usersInfo, 3); 2014 } 2015 assertCallbackStatus(GenericHalCallback<?> callback, int expectedStatus)2016 private void assertCallbackStatus(GenericHalCallback<?> callback, int expectedStatus) { 2017 int actualStatus = callback.status; 2018 if (actualStatus == expectedStatus) return; 2019 2020 fail("Wrong callback status; expected " 2021 + UserHalHelper.halCallbackStatusToString(expectedStatus) + ", got " 2022 + UserHalHelper.halCallbackStatusToString(actualStatus)); 2023 } 2024 2025 /** 2026 * Verifies {@code hal.get()} was called with the values used on 2027 * {@link #replyToValidGetUserIdentificationRequest(HalPropValue)}. 2028 */ verifyValidGetUserIdentificationRequestMade()2029 private void verifyValidGetUserIdentificationRequestMade() { 2030 verify(mVehicleHal).get(isPropertyWithValues(USER_IDENTIFICATION_ASSOCIATION, 2031 DEFAULT_REQUEST_ID, DEFAULT_USER_ID, DEFAULT_USER_FLAGS, 2032 /* numberAssociations= */ 1, KEY_FOB)); 2033 } 2034 2035 /** 2036 * Verifies {@code hal.set()} was called with the values used on 2037 * {@link #replyToValidSetUserIdentificationRequest(HalPropValue)}. 2038 */ verifyValidSetUserIdentificationRequestMade(@onNull HalPropValue request)2039 private void verifyValidSetUserIdentificationRequestMade(@NonNull HalPropValue request) { 2040 assertThat(request.getPropId()).isEqualTo(USER_IDENTIFICATION_ASSOCIATION); 2041 2042 assertThat(getIntValues(request)).containsExactly(DEFAULT_REQUEST_ID, DEFAULT_USER_ID, 2043 DEFAULT_USER_FLAGS, 2044 /* numberAssociations= */ 1, KEY_FOB, ASSOCIATE_CURRENT_USER); 2045 } 2046 createPropRequest(int propId, int requestId)2047 private HalPropValue createPropRequest(int propId, int requestId) { 2048 return createPropRequest(propId, requestId, null, new int[0], new String()); 2049 } 2050 createPropRequest(int propId, int requestId, int[] intValues)2051 private HalPropValue createPropRequest(int propId, int requestId, int[] intValues) { 2052 return createPropRequest(propId, requestId, null, intValues, new String()); 2053 } 2054 createPropRequest(int propId, int requestId, int requestType)2055 private HalPropValue createPropRequest(int propId, int requestId, int requestType) { 2056 return createPropRequest(propId, requestId, requestType, new int[0], new String()); 2057 } 2058 createPropRequest(int propId, int requestId, int requestType, int[] intValues)2059 private HalPropValue createPropRequest(int propId, int requestId, int requestType, 2060 int[] intValues) { 2061 return createPropRequest(propId, requestId, requestType, intValues, new String()); 2062 } 2063 createPropRequest(int propId, int requestId, Integer requestType, int[] intValues, String stringValue)2064 private HalPropValue createPropRequest(int propId, int requestId, Integer requestType, 2065 int[] intValues, String stringValue) { 2066 int intLength = intValues.length + 1; 2067 if (requestType != null) { 2068 intLength += 1; 2069 } 2070 int[] values = new int[intLength]; 2071 values[0] = requestId; 2072 int start = 1; 2073 2074 if (requestType != null) { 2075 values[1] = requestType; 2076 start = 2; 2077 } 2078 for (int i = 0; i < intValues.length; i++) { 2079 values[i + start] = intValues[i]; 2080 } 2081 return mPropValueBuilder.build(propId, /* areaId= */ 0, 2082 SystemClock.elapsedRealtime(), /* status= */ 0, values, 2083 new float[0], new long[0], stringValue, new byte[0]); 2084 } 2085 noOpCallback()2086 private static <T> HalCallback<T> noOpCallback() { 2087 return (i, r) -> { }; 2088 } 2089 getIntValues(HalPropValue value)2090 private static List<Integer> getIntValues(HalPropValue value) { 2091 ArrayList<Integer> values = new ArrayList<Integer>(); 2092 for (int i = 0; i < value.getInt32ValuesSize(); i++) { 2093 values.add(value.getInt32Value(i)); 2094 } 2095 return values; 2096 } 2097 2098 private static final class GenericHalCallback<R> implements HalCallback<R> { 2099 2100 private final CountDownLatch mLatch = new CountDownLatch(1); 2101 private final int mTimeout; 2102 private final List<Pair<Integer, R>> mExtraCalls = new ArrayList<>(); 2103 2104 public int status; 2105 public R response; 2106 GenericHalCallback(int timeout)2107 GenericHalCallback(int timeout) { 2108 this.mTimeout = timeout; 2109 } 2110 2111 @Override onResponse(int status, R response)2112 public void onResponse(int status, R response) { 2113 Log.d(TAG, "onResponse(): status=" + status + ", response=" + response); 2114 if (mLatch.getCount() == 0) { 2115 Log.e(TAG, "Already responded"); 2116 mExtraCalls.add(new Pair<>(status, response)); 2117 return; 2118 } 2119 this.status = status; 2120 this.response = response; 2121 mLatch.countDown(); 2122 } 2123 2124 /** 2125 * Asserts that the callback was called, or fail if it timed out. 2126 */ assertCalled()2127 public void assertCalled() throws InterruptedException { 2128 Log.d(TAG, "assertCalled(): waiting " + mTimeout + "ms"); 2129 if (!mLatch.await(mTimeout, TimeUnit.MILLISECONDS)) { 2130 throw new AssertionError("callback not called in " + mTimeout + "ms"); 2131 } 2132 } 2133 2134 /** 2135 * Asserts that the callback was not called more than once. 2136 */ assertNotCalledAgain()2137 public void assertNotCalledAgain() { 2138 if (mExtraCalls.isEmpty()) return; 2139 throw new AssertionError("Called " + mExtraCalls.size() + " times more than expected: " 2140 + mExtraCalls); 2141 } 2142 } 2143 } 2144