1 /* 2 * Copyright (C) 2019 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 17 package com.android.car.hal; 18 19 import static android.car.Car.PERMISSION_VENDOR_EXTENSION; 20 import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET; 21 import static android.car.VehiclePropertyIds.PERF_VEHICLE_SPEED; 22 import static android.car.hardware.property.VehicleHalStatusCode.STATUS_INTERNAL_ERROR; 23 import static android.car.hardware.property.VehicleHalStatusCode.STATUS_NOT_AVAILABLE; 24 import static android.car.hardware.property.VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE; 25 import static android.car.hardware.property.VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO; 26 import static android.car.hardware.property.VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE; 27 import static android.hardware.automotive.vehicle.VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION; 28 29 import static com.android.car.internal.property.CarPropertyErrorCodes.STATUS_OK; 30 31 import static com.google.common.truth.Truth.assertThat; 32 import static com.google.common.truth.Truth.assertWithMessage; 33 34 import static org.junit.Assert.assertThrows; 35 import static org.mockito.ArgumentMatchers.anyList; 36 import static org.mockito.Mockito.any; 37 import static org.mockito.Mockito.anyInt; 38 import static org.mockito.Mockito.clearInvocations; 39 import static org.mockito.Mockito.doAnswer; 40 import static org.mockito.Mockito.doNothing; 41 import static org.mockito.Mockito.doReturn; 42 import static org.mockito.Mockito.doThrow; 43 import static org.mockito.Mockito.eq; 44 import static org.mockito.Mockito.mock; 45 import static org.mockito.Mockito.never; 46 import static org.mockito.Mockito.reset; 47 import static org.mockito.Mockito.timeout; 48 import static org.mockito.Mockito.times; 49 import static org.mockito.Mockito.verify; 50 import static org.mockito.Mockito.when; 51 52 import android.car.VehiclePropertyIds; 53 import android.car.hardware.CarPropertyConfig; 54 import android.car.hardware.CarPropertyValue; 55 import android.car.hardware.property.CarPropertyManager; 56 import android.hardware.automotive.vehicle.VehiclePropError; 57 import android.hardware.automotive.vehicle.VehicleProperty; 58 import android.hardware.automotive.vehicle.VehiclePropertyChangeMode; 59 import android.hardware.automotive.vehicle.VehiclePropertyStatus; 60 import android.hardware.automotive.vehicle.VehicleVendorPermission; 61 import android.os.IBinder; 62 import android.os.RemoteException; 63 import android.os.ServiceSpecificException; 64 import android.util.ArraySet; 65 66 import androidx.test.runner.AndroidJUnit4; 67 68 import com.android.car.VehicleStub.AsyncGetSetRequest; 69 import com.android.car.VehicleStub.GetVehicleStubAsyncResult; 70 import com.android.car.VehicleStub.SetVehicleStubAsyncResult; 71 import com.android.car.VehicleStub.VehicleStubCallbackInterface; 72 import com.android.car.hal.VehicleHal.HalSubscribeOptions; 73 import com.android.car.hal.property.PropertyHalServiceConfigs; 74 import com.android.car.hal.test.AidlVehiclePropValueBuilder; 75 import com.android.car.internal.property.AsyncPropertyServiceRequest; 76 import com.android.car.internal.property.CarPropertyErrorCodes; 77 import com.android.car.internal.property.CarSubscription; 78 import com.android.car.internal.property.GetSetValueResult; 79 import com.android.car.internal.property.GetSetValueResultList; 80 import com.android.car.internal.property.IAsyncPropertyResultCallback; 81 import com.android.internal.annotations.VisibleForTesting; 82 83 import org.junit.After; 84 import org.junit.Before; 85 import org.junit.Rule; 86 import org.junit.Test; 87 import org.junit.runner.RunWith; 88 import org.mockito.ArgumentCaptor; 89 import org.mockito.Captor; 90 import org.mockito.Mock; 91 import org.mockito.invocation.InvocationOnMock; 92 import org.mockito.junit.MockitoJUnit; 93 import org.mockito.junit.MockitoRule; 94 import org.mockito.stubbing.Answer; 95 96 import java.util.ArrayList; 97 import java.util.HashMap; 98 import java.util.List; 99 import java.util.Map; 100 import java.util.Set; 101 102 @RunWith(AndroidJUnit4.class) 103 public class PropertyHalServiceTest { 104 @Rule 105 public MockitoRule mMockitoRule = MockitoJUnit.rule(); 106 107 @Mock 108 private VehicleHal mVehicleHal; 109 110 @Mock 111 private IAsyncPropertyResultCallback mGetAsyncPropertyResultCallback; 112 @Mock 113 private IAsyncPropertyResultCallback mSetAsyncPropertyResultCallback; 114 @Mock 115 private IBinder mGetAsyncPropertyResultBinder; 116 @Mock 117 private IBinder mSetAsyncPropertyResultBinder; 118 @Mock 119 private PropertyHalService.PropertyHalListener mPropertyHalListener; 120 @Captor 121 private ArgumentCaptor<GetSetValueResultList> mAsyncResultCaptor; 122 @Captor 123 private ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor; 124 @Captor 125 private ArgumentCaptor<List> mListArgumentCaptor; 126 @Mock 127 private CarPropertyConfig mMockCarPropertyConfig1; 128 @Mock 129 private CarPropertyConfig mMockCarPropertyConfig2; 130 131 private PropertyHalService mPropertyHalService; 132 private static final int REQUEST_ID_1 = 1; 133 private static final int REQUEST_ID_2 = 2; 134 private static final int REQUEST_ID_3 = 3; 135 private static final int REQUEST_ID_4 = 4; 136 private static final int REQUEST_ID_5 = 5; 137 private static final int RECEIVED_REQUEST_ID_1 = 0; 138 private static final int RECEIVED_REQUEST_ID_2 = 1; 139 private static final int RECEIVED_REQUEST_ID_3 = 2; 140 private static final int INT32_PROP = VehiclePropertyIds.INFO_FUEL_DOOR_LOCATION; 141 private static final int PROPERTY_VALUE = 123; 142 private static final int VENDOR_ERROR_CODE = 1234; 143 private static final int SYSTEM_ERROR_CODE = 4321; 144 private static final int VENDOR_PROPERTY_1 = 0x21e01111; 145 private static final int VENDOR_PROPERTY_2 = 0x21e01112; 146 private static final int VENDOR_PROPERTY_3 = 0x21e01113; 147 private static final float SAMPLE_RATE_HZ = 17.0f; 148 private static final AsyncPropertyServiceRequest GET_PROPERTY_SERVICE_REQUEST_1 = 149 new AsyncPropertyServiceRequest(REQUEST_ID_1, HVAC_TEMPERATURE_SET, /* areaId= */ 0); 150 private static final AsyncPropertyServiceRequest GET_PROPERTY_SERVICE_REQUEST_2 = 151 new AsyncPropertyServiceRequest(REQUEST_ID_2, HVAC_TEMPERATURE_SET, /* areaId= */ 0); 152 private static final AsyncPropertyServiceRequest GET_PROPERTY_SERVICE_REQUEST_STATIC_1 = 153 new AsyncPropertyServiceRequest(REQUEST_ID_1, INT32_PROP, /* areaId= */ 0); 154 private static final AsyncPropertyServiceRequest SET_HVAC_REQUEST_ID_1 = 155 new AsyncPropertyServiceRequest(REQUEST_ID_1, HVAC_TEMPERATURE_SET, /* areaId= */ 0, 156 new CarPropertyValue(HVAC_TEMPERATURE_SET, /* areaId= */ 0, SAMPLE_RATE_HZ)); 157 private static final AsyncPropertyServiceRequest SET_SPEED_REQUEST_ID_2 = 158 new AsyncPropertyServiceRequest(REQUEST_ID_2, PERF_VEHICLE_SPEED, /* areaId= */ 0, 159 new CarPropertyValue(PERF_VEHICLE_SPEED, /* areaId= */ 0, SAMPLE_RATE_HZ)); 160 private static final AsyncPropertyServiceRequest SET_SPEED_REQUEST_ID_3 = 161 new AsyncPropertyServiceRequest(REQUEST_ID_3, PERF_VEHICLE_SPEED, /* areaId= */ 0, 162 new CarPropertyValue(PERF_VEHICLE_SPEED, /* areaId= */ 0, SAMPLE_RATE_HZ)); 163 private static final AsyncPropertyServiceRequest SET_VEHICLE_SPEED_AREA_ID_1_REQUEST = 164 new AsyncPropertyServiceRequest(REQUEST_ID_4, PERF_VEHICLE_SPEED, /* areaId= */ 1, 165 new CarPropertyValue(PERF_VEHICLE_SPEED, /* areaId= */ 1, SAMPLE_RATE_HZ)); 166 private static final AsyncPropertyServiceRequest SET_VEHICLE_SPEED_AREA_ID_2_REQUEST = 167 new AsyncPropertyServiceRequest(REQUEST_ID_5, PERF_VEHICLE_SPEED, /* areaId= */ 2, 168 new CarPropertyValue(PERF_VEHICLE_SPEED, /* areaId= */ 2, SAMPLE_RATE_HZ)); 169 170 private static final long TEST_UPDATE_TIMESTAMP_NANOS = 1234; 171 private final HalPropValueBuilder mPropValueBuilder = new HalPropValueBuilder( 172 /* isAidl= */ true); 173 private final HalPropValue mPropValue = mPropValueBuilder.build( 174 HVAC_TEMPERATURE_SET, /* areaId= */ 0, TEST_UPDATE_TIMESTAMP_NANOS, /* status= */ 0, 175 SAMPLE_RATE_HZ); 176 private final HalPropValue mNonTargetPropValue = mPropValueBuilder.build( 177 HVAC_TEMPERATURE_SET, /* areaId= */ 0, TEST_UPDATE_TIMESTAMP_NANOS, /* status= */ 0, 178 16.0f); 179 private final HalPropValue mPropValue2 = mPropValueBuilder.build( 180 PERF_VEHICLE_SPEED, /* areaId= */ 0, TEST_UPDATE_TIMESTAMP_NANOS, /* status= */ 0, 181 SAMPLE_RATE_HZ); 182 private final HalPropValue mPropValue3 = mPropValueBuilder.build( 183 INT32_PROP, /* areaId= */ 0, TEST_UPDATE_TIMESTAMP_NANOS, /* status= */ 0, 184 3); 185 copyRequest(AsyncPropertyServiceRequest request)186 private AsyncPropertyServiceRequest copyRequest(AsyncPropertyServiceRequest request) { 187 return new AsyncPropertyServiceRequest(request.getRequestId(), request.getPropertyId(), 188 request.getAreaId(), request.getCarPropertyValue()); 189 } 190 191 @Before setUp()192 public void setUp() { 193 when(mVehicleHal.getHalPropValueBuilder()).thenReturn(mPropValueBuilder); 194 mPropertyHalService = new PropertyHalService(mVehicleHal); 195 mPropertyHalService.setPropertyHalServiceConfigs(PropertyHalServiceConfigs.newConfigs()); 196 mPropertyHalService.init(); 197 198 HalPropConfig mockPropConfig1 = mock(HalPropConfig.class); 199 when(mockPropConfig1.getPropId()).thenReturn(VehicleProperty.HVAC_TEMPERATURE_SET); 200 when(mockPropConfig1.getChangeMode()).thenReturn(VehiclePropertyChangeMode.ON_CHANGE); 201 when(mockPropConfig1.toCarPropertyConfig(eq(VehicleProperty.HVAC_TEMPERATURE_SET), any())) 202 .thenReturn(mMockCarPropertyConfig1); 203 when(mMockCarPropertyConfig1.getChangeMode()) 204 .thenReturn(VehiclePropertyChangeMode.ON_CHANGE); 205 when(mMockCarPropertyConfig1.getAreaIds()).thenReturn(new int[]{0}); 206 207 HalPropConfig mockPropConfig2 = mock(HalPropConfig.class); 208 when(mockPropConfig2.getPropId()).thenReturn(VehicleProperty.PERF_VEHICLE_SPEED); 209 when(mockPropConfig2.getChangeMode()).thenReturn(VehiclePropertyChangeMode.CONTINUOUS); 210 when(mockPropConfig2.getMinSampleRate()).thenReturn(20.0f); 211 when(mockPropConfig2.getMaxSampleRate()).thenReturn(100.0f); 212 when(mockPropConfig2.toCarPropertyConfig(eq(VehicleProperty.PERF_VEHICLE_SPEED), any())) 213 .thenReturn(mMockCarPropertyConfig2); 214 when(mMockCarPropertyConfig2.getChangeMode()) 215 .thenReturn(VehiclePropertyChangeMode.CONTINUOUS); 216 when(mMockCarPropertyConfig2.getMinSampleRate()).thenReturn(20.0f); 217 when(mMockCarPropertyConfig2.getMaxSampleRate()).thenReturn(100.0f); 218 when(mMockCarPropertyConfig2.getAreaIds()).thenReturn(new int[]{0}); 219 220 HalPropConfig mockPropConfig3 = mock(HalPropConfig.class); 221 when(mockPropConfig3.getChangeMode()).thenReturn(VehiclePropertyChangeMode.STATIC); 222 when(mockPropConfig3.getPropId()).thenReturn(INT32_PROP); 223 224 mPropertyHalService.takeProperties(List.of(mockPropConfig1, mockPropConfig2, 225 mockPropConfig3)); 226 mPropertyHalService.getPropertyList(); 227 } 228 229 @After tearDown()230 public void tearDown() { 231 mPropertyHalService.release(); 232 mPropertyHalService = null; 233 } 234 verifyNoPendingRequest()235 private void verifyNoPendingRequest() { 236 assertWithMessage("No pending async requests after test finish") 237 .that(mPropertyHalService.countPendingAsyncRequests()).isEqualTo(0); 238 assertWithMessage("No pending async set request waiting for update after test finish") 239 .that(mPropertyHalService.countHalPropIdToWaitForUpdateRequests()).isEqualTo(0); 240 } 241 deliverResult(InvocationOnMock invocation, Integer expectedServiceRequestId, int errorCode, HalPropValue propValue, boolean get)242 private Object deliverResult(InvocationOnMock invocation, Integer expectedServiceRequestId, 243 int errorCode, HalPropValue propValue, boolean get) { 244 CarPropertyErrorCodes carPropertyErrorCodes = 245 new CarPropertyErrorCodes( 246 errorCode, 247 /* vendorErrorCode= */ 0, 248 /* systemErrorCode= */ 0); 249 return deliverResult( 250 invocation, expectedServiceRequestId, carPropertyErrorCodes, propValue, get); 251 } 252 deliverResult(InvocationOnMock invocation, Integer expectedServiceRequestId, CarPropertyErrorCodes carPropertyErrorCodes, HalPropValue propValue, boolean get)253 private Object deliverResult(InvocationOnMock invocation, Integer expectedServiceRequestId, 254 CarPropertyErrorCodes carPropertyErrorCodes, HalPropValue propValue, boolean get) { 255 Object[] args = invocation.getArguments(); 256 List getVehicleHalRequests = (List) args[0]; 257 Map<VehicleStubCallbackInterface, List<GetVehicleStubAsyncResult>> callbackToGetResults = 258 new HashMap<>(); 259 Map<VehicleStubCallbackInterface, List<SetVehicleStubAsyncResult>> callbackToSetResults = 260 new HashMap<>(); 261 for (int i = 0; i < getVehicleHalRequests.size(); i++) { 262 AsyncGetSetRequest getVehicleHalRequest = (AsyncGetSetRequest) 263 getVehicleHalRequests.get(i); 264 VehicleStubCallbackInterface callback = (VehicleStubCallbackInterface) args[1]; 265 if (callbackToGetResults.get(callback) == null) { 266 callbackToGetResults.put(callback, new ArrayList<>()); 267 } 268 if (callbackToSetResults.get(callback) == null) { 269 callbackToSetResults.put(callback, new ArrayList<>()); 270 } 271 272 int serviceRequestId = getVehicleHalRequest.getServiceRequestId(); 273 if (expectedServiceRequestId != null) { 274 assertThat(serviceRequestId).isEqualTo(expectedServiceRequestId); 275 } 276 277 if (get) { 278 if (propValue != null) { 279 callbackToGetResults.get(callback).add(new GetVehicleStubAsyncResult( 280 serviceRequestId, propValue)); 281 } else { 282 callbackToGetResults.get(callback).add(new GetVehicleStubAsyncResult( 283 serviceRequestId, carPropertyErrorCodes)); 284 } 285 } else { 286 callbackToSetResults.get(callback).add(new SetVehicleStubAsyncResult( 287 serviceRequestId, carPropertyErrorCodes)); 288 } 289 } 290 291 for (VehicleStubCallbackInterface callback : callbackToGetResults.keySet()) { 292 callback.onGetAsyncResults(callbackToGetResults.get(callback)); 293 } 294 for (VehicleStubCallbackInterface callback : callbackToSetResults.keySet()) { 295 callback.onSetAsyncResults(callbackToSetResults.get(callback)); 296 } 297 298 return null; 299 } 300 deliverOkayGetResult(InvocationOnMock invocation)301 private Object deliverOkayGetResult(InvocationOnMock invocation) { 302 return deliverOkayGetResult(invocation, mPropValue); 303 } 304 deliverOkayGetResult(InvocationOnMock invocation, HalPropValue propValue)305 private Object deliverOkayGetResult(InvocationOnMock invocation, HalPropValue propValue) { 306 return deliverResult(invocation, /* expectedServiceRequestId= */ null, 307 STATUS_OK, propValue, true); 308 } 309 deliverOkayGetResult(InvocationOnMock invocation, Integer expectedServiceRequestId)310 private Object deliverOkayGetResult(InvocationOnMock invocation, 311 Integer expectedServiceRequestId) { 312 return deliverResult(invocation, expectedServiceRequestId, STATUS_OK, 313 mPropValue, true); 314 } 315 deliverOkaySetResult(InvocationOnMock invocation)316 private Object deliverOkaySetResult(InvocationOnMock invocation) { 317 return deliverOkaySetResult(invocation, /* expectedServiceRequestId= */ null); 318 } 319 deliverOkaySetResult(InvocationOnMock invocation, Integer expectedServiceRequestId)320 private Object deliverOkaySetResult(InvocationOnMock invocation, 321 Integer expectedServiceRequestId) { 322 return deliverResult(invocation, expectedServiceRequestId, STATUS_OK, 323 null, false); 324 } 325 deliverTryAgainGetResult(InvocationOnMock invocation)326 private Object deliverTryAgainGetResult(InvocationOnMock invocation) { 327 return deliverTryAgainGetResult(invocation, /* expectedServiceRequestId= */ null); 328 } 329 deliverTryAgainGetResult(InvocationOnMock invocation, Integer expectedServiceRequestId)330 private Object deliverTryAgainGetResult(InvocationOnMock invocation, 331 Integer expectedServiceRequestId) { 332 return deliverResult(invocation, expectedServiceRequestId, 333 CarPropertyErrorCodes.STATUS_TRY_AGAIN, null, true); 334 } 335 deliverTryAgainSetResult(InvocationOnMock invocation)336 private Object deliverTryAgainSetResult(InvocationOnMock invocation) { 337 return deliverTryAgainSetResult(invocation, /* expectedServiceRequestId= */ null); 338 } 339 deliverTryAgainSetResult(InvocationOnMock invocation, Integer expectedServiceRequestId)340 private Object deliverTryAgainSetResult(InvocationOnMock invocation, 341 Integer expectedServiceRequestId) { 342 return deliverResult(invocation, expectedServiceRequestId, 343 CarPropertyErrorCodes.STATUS_TRY_AGAIN, null, false); 344 } 345 deliverErrorGetResult(InvocationOnMock invocation, int errorCode)346 private Object deliverErrorGetResult(InvocationOnMock invocation, int errorCode) { 347 return deliverErrorGetResult(invocation, /* expectedServiceRequestId= */ null, errorCode); 348 } 349 deliverErrorGetResult(InvocationOnMock invocation, Integer expectedServiceRequestId, int errorCode)350 private Object deliverErrorGetResult(InvocationOnMock invocation, 351 Integer expectedServiceRequestId, int errorCode) { 352 return deliverResult(invocation, expectedServiceRequestId, errorCode, null, true); 353 } 354 deliverErrorSetResult(InvocationOnMock invocation, int errorCode)355 private Object deliverErrorSetResult(InvocationOnMock invocation, int errorCode) { 356 return deliverErrorSetResult(invocation, /* expectedServiceRequestId= */ null, errorCode); 357 } 358 deliverErrorSetResult(InvocationOnMock invocation, Integer expectedServiceRequestId, int errorCode)359 private Object deliverErrorSetResult(InvocationOnMock invocation, 360 Integer expectedServiceRequestId, int errorCode) { 361 return deliverResult(invocation, expectedServiceRequestId, errorCode, null, false); 362 } 363 364 @Test testGetCarPropertyValuesAsync()365 public void testGetCarPropertyValuesAsync() { 366 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 367 368 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 369 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 370 /* asyncRequestStartTime= */ 0); 371 372 ArgumentCaptor<List<AsyncGetSetRequest>> captor = 373 ArgumentCaptor.forClass(List.class); 374 verify(mVehicleHal).getAsync(captor.capture(), 375 any(VehicleStubCallbackInterface.class)); 376 AsyncGetSetRequest gotRequest = captor.getValue().get(0); 377 assertThat(gotRequest.getServiceRequestId()).isEqualTo(RECEIVED_REQUEST_ID_1); 378 assertThat(gotRequest.getHalPropValue().getPropId()).isEqualTo(HVAC_TEMPERATURE_SET); 379 assertThat(gotRequest.getTimeoutUptimeMs()).isGreaterThan(1000); 380 381 mPropertyHalService.cancelRequests(new int[]{REQUEST_ID_1}); 382 verify(mVehicleHal, timeout(1000)).cancelRequests(List.of(0)); 383 384 verifyNoPendingRequest(); 385 } 386 387 @Test testGetCarPropertyValuesAsync_multipleRequests()388 public void testGetCarPropertyValuesAsync_multipleRequests() { 389 List<AsyncPropertyServiceRequest> getPropertyServiceRequests = new ArrayList<>(); 390 getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_1); 391 getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_2); 392 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 393 394 mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests, 395 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 396 /* asyncRequestStartTime= */ 0); 397 398 ArgumentCaptor<List<AsyncGetSetRequest>> captor = 399 ArgumentCaptor.forClass(List.class); 400 verify(mVehicleHal).getAsync(captor.capture(), 401 any(VehicleStubCallbackInterface.class)); 402 AsyncGetSetRequest gotRequest0 = captor.getValue().get(0); 403 assertThat(gotRequest0.getServiceRequestId()).isEqualTo(RECEIVED_REQUEST_ID_1); 404 assertThat(gotRequest0.getHalPropValue().getPropId()).isEqualTo( 405 HVAC_TEMPERATURE_SET); 406 assertThat(gotRequest0.getHalPropValue().getAreaId()).isEqualTo(0); 407 assertThat(gotRequest0.getTimeoutUptimeMs()).isGreaterThan(1000); 408 AsyncGetSetRequest gotRequest1 = captor.getValue().get(1); 409 assertThat(gotRequest1.getServiceRequestId()).isEqualTo(RECEIVED_REQUEST_ID_2); 410 assertThat(gotRequest1.getHalPropValue().getPropId()).isEqualTo( 411 HVAC_TEMPERATURE_SET); 412 assertThat(gotRequest1.getHalPropValue().getAreaId()).isEqualTo(0); 413 assertThat(gotRequest1.getTimeoutUptimeMs()).isGreaterThan(1000); 414 415 mPropertyHalService.cancelRequests(new int[]{REQUEST_ID_1, REQUEST_ID_2}); 416 417 verifyNoPendingRequest(); 418 } 419 420 @Test testGetCarPropertyValuesAsync_staticCacheMultipleRequests()421 public void testGetCarPropertyValuesAsync_staticCacheMultipleRequests() throws Exception { 422 doAnswer((invocation) -> { 423 return deliverOkayGetResult(invocation, mPropValue3); 424 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 425 426 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 427 428 mPropertyHalService.getCarPropertyValuesAsync( 429 List.of(GET_PROPERTY_SERVICE_REQUEST_STATIC_1), mGetAsyncPropertyResultCallback, 430 /* timeoutInMs= */ 1000, /* asyncRequestStartTime= */ 0); 431 432 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 433 mAsyncResultCaptor.capture()); 434 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 435 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 436 assertThat(result.getCarPropertyValue().getValue()).isEqualTo(3); 437 assertThat(result.getCarPropertyValue().getAreaId()).isEqualTo(0); 438 reset(mVehicleHal); 439 reset(mGetAsyncPropertyResultCallback); 440 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 441 442 mPropertyHalService.getCarPropertyValuesAsync( 443 List.of(GET_PROPERTY_SERVICE_REQUEST_STATIC_1), mGetAsyncPropertyResultCallback, 444 /* timeoutInMs= */ 1000, /* asyncRequestStartTime= */ 0); 445 verify(mVehicleHal, never()).getAsync(any(), any()); 446 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 447 mAsyncResultCaptor.capture()); 448 GetSetValueResult cachedResult = mAsyncResultCaptor.getValue().getList().get(0); 449 assertThat(cachedResult.getRequestId()).isEqualTo(REQUEST_ID_1); 450 assertThat(cachedResult.getCarPropertyValue().getValue()).isEqualTo(3); 451 assertThat(cachedResult.getCarPropertyValue().getAreaId()).isEqualTo(0); 452 } 453 454 @Test testGetCarPropertyValuesAsync_linkToDeath()455 public void testGetCarPropertyValuesAsync_linkToDeath() throws RemoteException { 456 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 457 List<AsyncPropertyServiceRequest> getPropertyServiceRequests = mock(List.class); 458 mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests, 459 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 460 /* asyncRequestStartTime= */ 0); 461 verify(mGetAsyncPropertyResultBinder).linkToDeath(any(IBinder.DeathRecipient.class), 462 anyInt()); 463 464 mPropertyHalService.cancelRequests(new int[]{REQUEST_ID_1}); 465 466 verifyNoPendingRequest(); 467 } 468 469 @Test testGetCarPropertyValuesAsync_binderDiedBeforeLinkToDeath()470 public void testGetCarPropertyValuesAsync_binderDiedBeforeLinkToDeath() throws RemoteException { 471 IBinder mockBinder = mock(IBinder.class); 472 when(mGetAsyncPropertyResultCallback.asBinder()).thenReturn(mockBinder); 473 doThrow(new RemoteException()).when(mockBinder).linkToDeath(any(), anyInt()); 474 List<AsyncPropertyServiceRequest> getPropertyServiceRequests = mock(List.class); 475 476 assertThrows(IllegalStateException.class, () -> { 477 mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests, 478 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 479 /* asyncRequestStartTime= */ 0); 480 }); 481 482 verifyNoPendingRequest(); 483 } 484 485 @Test testGetCarPropertyValuesAsync_unlinkToDeath_onBinderDied()486 public void testGetCarPropertyValuesAsync_unlinkToDeath_onBinderDied() throws RemoteException { 487 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 488 List<AsyncPropertyServiceRequest> getPropertyServiceRequests = mock(List.class); 489 mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests, 490 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 491 /* asyncRequestStartTime= */ 0); 492 493 ArgumentCaptor<IBinder.DeathRecipient> recipientCaptor = ArgumentCaptor.forClass( 494 IBinder.DeathRecipient.class); 495 verify(mGetAsyncPropertyResultBinder).linkToDeath(recipientCaptor.capture(), eq(0)); 496 497 recipientCaptor.getValue().binderDied(); 498 499 verify(mGetAsyncPropertyResultBinder).unlinkToDeath(recipientCaptor.getValue(), 0); 500 501 verifyNoPendingRequest(); 502 } 503 504 @Test testGetCarPropertyValuesAsync_normalResult()505 public void testGetCarPropertyValuesAsync_normalResult() throws RemoteException { 506 doAnswer((invocation) -> { 507 return deliverOkayGetResult(invocation, RECEIVED_REQUEST_ID_1); 508 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 509 510 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 511 512 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 513 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 514 /* asyncRequestStartTime= */ 0); 515 516 517 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 518 mAsyncResultCaptor.capture()); 519 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 520 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 521 assertThat(result.getCarPropertyValue().getValue()).isEqualTo(SAMPLE_RATE_HZ); 522 assertThat(result.getCarPropertyValue().getAreaId()).isEqualTo(0); 523 524 verifyNoPendingRequest(); 525 } 526 527 @Test testGetCarPropertyValuesAsync_retryTwiceAndSucceed()528 public void testGetCarPropertyValuesAsync_retryTwiceAndSucceed() throws RemoteException { 529 doAnswer(new Answer() { 530 private int mCount = 0; 531 532 public Object answer(InvocationOnMock invocation) { 533 Object[] args = invocation.getArguments(); 534 List<AsyncGetSetRequest> getVehicleHalRequests = (List<AsyncGetSetRequest>) args[0]; 535 assertThat(getVehicleHalRequests.size()).isEqualTo(1); 536 537 switch (mCount++) { 538 case 0: 539 return deliverTryAgainGetResult(invocation, RECEIVED_REQUEST_ID_1); 540 case 1: 541 return deliverTryAgainGetResult(invocation, RECEIVED_REQUEST_ID_2); 542 case 2: 543 return deliverOkayGetResult(invocation, RECEIVED_REQUEST_ID_3); 544 default: 545 throw new IllegalStateException("Only expect 3 calls"); 546 } 547 } 548 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 549 550 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 551 552 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 553 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 554 /* asyncRequestStartTime= */ 0); 555 556 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 557 mAsyncResultCaptor.capture()); 558 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 559 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 560 assertThat(result.getCarPropertyValue().getValue()).isEqualTo(SAMPLE_RATE_HZ); 561 assertThat(result.getCarPropertyValue().getAreaId()).isEqualTo(0); 562 563 verifyNoPendingRequest(); 564 } 565 566 @Test testGetCarPropertyValuesAsync_retryAndTimeout()567 public void testGetCarPropertyValuesAsync_retryAndTimeout() throws RemoteException { 568 doAnswer((invocation) -> { 569 // For every request, we return retry result. 570 return deliverTryAgainGetResult(invocation); 571 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 572 573 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 574 575 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 576 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 10, 577 /* asyncRequestStartTime= */ 0); 578 579 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 580 mAsyncResultCaptor.capture()); 581 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 582 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 583 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()).isEqualTo( 584 CarPropertyManager.STATUS_ERROR_TIMEOUT); 585 586 verifyNoPendingRequest(); 587 } 588 589 @Test testGetCarPropertyValuesAsync_noResultTimeout()590 public void testGetCarPropertyValuesAsync_noResultTimeout() throws RemoteException { 591 doNothing().when(mVehicleHal).getAsync(anyList(), 592 any(VehicleStubCallbackInterface.class)); 593 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 594 595 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 596 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 10, 597 /* asyncRequestStartTime= */ 0); 598 599 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 600 mAsyncResultCaptor.capture()); 601 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 602 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 603 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()).isEqualTo( 604 CarPropertyManager.STATUS_ERROR_TIMEOUT); 605 606 verifyNoPendingRequest(); 607 } 608 609 @Test testGetCarPropertyValuesAsync_timeoutFromVehicleStub()610 public void testGetCarPropertyValuesAsync_timeoutFromVehicleStub() throws RemoteException { 611 doAnswer((invocation) -> { 612 Object[] args = invocation.getArguments(); 613 List getVehicleHalRequests = (List) args[0]; 614 AsyncGetSetRequest getVehicleHalRequest = 615 (AsyncGetSetRequest) getVehicleHalRequests.get(0); 616 VehicleStubCallbackInterface getVehicleStubAsyncCallback = 617 (VehicleStubCallbackInterface) args[1]; 618 // Simulate the request has already timed-out. 619 getVehicleStubAsyncCallback.onRequestsTimeout(List.of( 620 getVehicleHalRequest.getServiceRequestId())); 621 return null; 622 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 623 624 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 625 626 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 627 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 628 /* asyncRequestStartTime= */ 0); 629 630 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 631 mAsyncResultCaptor.capture()); 632 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 633 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 634 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()).isEqualTo( 635 CarPropertyManager.STATUS_ERROR_TIMEOUT); 636 637 verifyNoPendingRequest(); 638 } 639 640 @Test testGetCarPropertyValuesAsync_errorResult()641 public void testGetCarPropertyValuesAsync_errorResult() throws RemoteException { 642 doAnswer((invocation) -> { 643 return deliverErrorGetResult(invocation, RECEIVED_REQUEST_ID_1, 644 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 645 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 646 647 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 648 649 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 650 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 651 /* asyncRequestStartTime= */ 0); 652 653 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 654 mAsyncResultCaptor.capture()); 655 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 656 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 657 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()).isEqualTo( 658 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 659 assertThat(result.getCarPropertyValue()).isEqualTo(null); 660 661 verifyNoPendingRequest(); 662 } 663 664 @Test testGetCarPropertyValuesAsync_errorResultVendorErrorCode()665 public void testGetCarPropertyValuesAsync_errorResultVendorErrorCode() throws RemoteException { 666 doAnswer((invocation) -> { 667 CarPropertyErrorCodes errorCodes = new CarPropertyErrorCodes( 668 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR, 669 VENDOR_ERROR_CODE, 670 SYSTEM_ERROR_CODE); 671 return deliverResult(invocation, RECEIVED_REQUEST_ID_1, errorCodes, 672 /* propValue= */ null, /* get= */ true); 673 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 674 675 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 676 677 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 678 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 679 /* asyncRequestStartTime= */ 0); 680 681 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 682 mAsyncResultCaptor.capture()); 683 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 684 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 685 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()).isEqualTo( 686 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 687 assertThat(result.getCarPropertyErrorCodes().getVendorErrorCode()) 688 .isEqualTo(VENDOR_ERROR_CODE); 689 assertThat(result.getCarPropertyErrorCodes().getSystemErrorCode()).isEqualTo( 690 SYSTEM_ERROR_CODE); 691 assertThat(result.getCarPropertyValue()).isEqualTo(null); 692 693 verifyNoPendingRequest(); 694 } 695 696 @Test testGetCarPropertyValuesAsync_propStatusUnavailable()697 public void testGetCarPropertyValuesAsync_propStatusUnavailable() throws RemoteException { 698 doAnswer((invocation) -> { 699 HalPropValue propValue = mPropValueBuilder.build( 700 HVAC_TEMPERATURE_SET, /* areaId= */ 0, TEST_UPDATE_TIMESTAMP_NANOS, 701 VehiclePropertyStatus.UNAVAILABLE, SAMPLE_RATE_HZ); 702 return deliverOkayGetResult(invocation, propValue); 703 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 704 705 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 706 707 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 708 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 709 /* asyncRequestStartTime= */ 0); 710 711 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 712 mAsyncResultCaptor.capture()); 713 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 714 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 715 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()).isEqualTo( 716 CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE); 717 assertThat(result.getCarPropertyErrorCodes().getVendorErrorCode()).isEqualTo(0); 718 assertThat(result.getCarPropertyErrorCodes().getSystemErrorCode()).isEqualTo(0); 719 assertThat(result.getCarPropertyValue()).isEqualTo(null); 720 721 verifyNoPendingRequest(); 722 } 723 724 @Test testGetCarPropertyValuesAsync_propStatusError()725 public void testGetCarPropertyValuesAsync_propStatusError() throws RemoteException { 726 doAnswer((invocation) -> { 727 HalPropValue propValue = mPropValueBuilder.build( 728 HVAC_TEMPERATURE_SET, /* areaId= */ 0, TEST_UPDATE_TIMESTAMP_NANOS, 729 VehiclePropertyStatus.ERROR, SAMPLE_RATE_HZ); 730 return deliverOkayGetResult(invocation, propValue); 731 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 732 733 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 734 735 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 736 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 737 /* asyncRequestStartTime= */ 0); 738 739 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 740 mAsyncResultCaptor.capture()); 741 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 742 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 743 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()).isEqualTo( 744 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 745 assertThat(result.getCarPropertyErrorCodes().getVendorErrorCode()).isEqualTo(0); 746 assertThat(result.getCarPropertyErrorCodes().getSystemErrorCode()).isEqualTo(0); 747 assertThat(result.getCarPropertyValue()).isEqualTo(null); 748 749 verifyNoPendingRequest(); 750 } 751 752 @Test testGetCarPropertyValuesAsync_multipleResultsSameCall()753 public void testGetCarPropertyValuesAsync_multipleResultsSameCall() throws RemoteException { 754 doAnswer((invocation) -> { 755 Object[] args = invocation.getArguments(); 756 List<AsyncGetSetRequest> getVehicleHalRequests = (List) args[0]; 757 VehicleStubCallbackInterface getVehicleStubAsyncCallback = 758 (VehicleStubCallbackInterface) args[1]; 759 760 assertThat(getVehicleHalRequests.size()).isEqualTo(2); 761 assertThat(getVehicleHalRequests.get(0).getServiceRequestId()).isEqualTo( 762 RECEIVED_REQUEST_ID_1); 763 assertThat(getVehicleHalRequests.get(0).getHalPropValue().getPropId()).isEqualTo( 764 HVAC_TEMPERATURE_SET); 765 assertThat(getVehicleHalRequests.get(1).getServiceRequestId()).isEqualTo( 766 RECEIVED_REQUEST_ID_2); 767 assertThat(getVehicleHalRequests.get(1).getHalPropValue().getPropId()).isEqualTo( 768 HVAC_TEMPERATURE_SET); 769 770 List<GetVehicleStubAsyncResult> getVehicleStubAsyncResults = 771 new ArrayList<>(); 772 getVehicleStubAsyncResults.add( 773 new GetVehicleStubAsyncResult(RECEIVED_REQUEST_ID_1, mPropValue)); 774 getVehicleStubAsyncResults.add( 775 new GetVehicleStubAsyncResult(RECEIVED_REQUEST_ID_2, mPropValue)); 776 getVehicleStubAsyncCallback.onGetAsyncResults(getVehicleStubAsyncResults); 777 return null; 778 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 779 780 List<AsyncPropertyServiceRequest> getPropertyServiceRequests = new ArrayList<>(); 781 getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_1); 782 getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_2); 783 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 784 785 mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests, 786 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 787 /* asyncRequestStartTime= */ 0); 788 789 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 790 mAsyncResultCaptor.capture()); 791 GetSetValueResult result1 = mAsyncResultCaptor.getValue().getList().get(0); 792 GetSetValueResult result2 = mAsyncResultCaptor.getValue().getList().get(1); 793 assertThat(result1.getRequestId()).isEqualTo(REQUEST_ID_1); 794 assertThat(result1.getCarPropertyValue().getValue()).isEqualTo(SAMPLE_RATE_HZ); 795 assertThat(result2.getRequestId()).isEqualTo(REQUEST_ID_2); 796 assertThat(result2.getCarPropertyValue().getValue()).isEqualTo(SAMPLE_RATE_HZ); 797 798 verifyNoPendingRequest(); 799 } 800 801 @Test testGetCarPropertyValuesAsync_multipleResultsDifferentCalls()802 public void testGetCarPropertyValuesAsync_multipleResultsDifferentCalls() 803 throws RemoteException { 804 doAnswer((invocation) -> { 805 Object[] args = invocation.getArguments(); 806 List<AsyncGetSetRequest> getVehicleHalRequests = (List) args[0]; 807 VehicleStubCallbackInterface getVehicleStubAsyncCallback = 808 (VehicleStubCallbackInterface) args[1]; 809 810 assertThat(getVehicleHalRequests.size()).isEqualTo(2); 811 assertThat(getVehicleHalRequests.get(0).getServiceRequestId()).isEqualTo( 812 RECEIVED_REQUEST_ID_1); 813 assertThat(getVehicleHalRequests.get(0).getHalPropValue().getPropId()).isEqualTo( 814 HVAC_TEMPERATURE_SET); 815 assertThat(getVehicleHalRequests.get(1).getServiceRequestId()).isEqualTo( 816 RECEIVED_REQUEST_ID_2); 817 assertThat(getVehicleHalRequests.get(1).getHalPropValue().getPropId()).isEqualTo( 818 HVAC_TEMPERATURE_SET); 819 820 getVehicleStubAsyncCallback.onGetAsyncResults( 821 List.of(new GetVehicleStubAsyncResult(RECEIVED_REQUEST_ID_1, 822 mPropValue))); 823 getVehicleStubAsyncCallback.onGetAsyncResults( 824 List.of(new GetVehicleStubAsyncResult(RECEIVED_REQUEST_ID_2, 825 mPropValue))); 826 return null; 827 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 828 829 List<AsyncPropertyServiceRequest> getPropertyServiceRequests = new ArrayList<>(); 830 getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_1); 831 getPropertyServiceRequests.add(GET_PROPERTY_SERVICE_REQUEST_2); 832 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 833 834 mPropertyHalService.getCarPropertyValuesAsync(getPropertyServiceRequests, 835 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 836 /* asyncRequestStartTime= */ 0); 837 838 verify(mGetAsyncPropertyResultCallback, timeout(1000).times(2)) 839 .onGetValueResults(mAsyncResultCaptor.capture()); 840 List<GetSetValueResultList> getValuesResults = mAsyncResultCaptor.getAllValues(); 841 assertThat(getValuesResults.get(0).getList().get(0).getRequestId()).isEqualTo(REQUEST_ID_1); 842 assertThat(getValuesResults.get(0).getList().get(0).getCarPropertyValue().getValue()) 843 .isEqualTo(SAMPLE_RATE_HZ); 844 assertThat(getValuesResults.get(1).getList().get(0).getRequestId()).isEqualTo(REQUEST_ID_2); 845 assertThat(getValuesResults.get(1).getList().get(0).getCarPropertyValue().getValue()) 846 .isEqualTo(SAMPLE_RATE_HZ); 847 848 verifyNoPendingRequest(); 849 } 850 851 @Test testSetCarPropertyValuesAsync()852 public void testSetCarPropertyValuesAsync() { 853 Set<Integer> vhalCancelledRequestIds = new ArraySet<>(); 854 doAnswer((invocation) -> { 855 List<Integer> ids = (List<Integer>) invocation.getArgument(0); 856 for (int i = 0; i < ids.size(); i++) { 857 vhalCancelledRequestIds.add(ids.get(i)); 858 } 859 return null; 860 }).when(mVehicleHal).cancelRequests(any()); 861 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 862 863 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 864 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 865 /* asyncRequestStartTime= */ 0); 866 867 ArgumentCaptor<List<AsyncGetSetRequest>> captor = 868 ArgumentCaptor.forClass(List.class); 869 verify(mVehicleHal).setAsync(captor.capture(), any(VehicleStubCallbackInterface.class)); 870 AsyncGetSetRequest gotRequest = captor.getValue().get(0); 871 assertThat(gotRequest.getServiceRequestId()).isEqualTo(RECEIVED_REQUEST_ID_1); 872 assertThat(gotRequest.getHalPropValue().getPropId()).isEqualTo(HVAC_TEMPERATURE_SET); 873 assertThat(gotRequest.getHalPropValue().getFloatValue(0)).isEqualTo(SAMPLE_RATE_HZ); 874 assertThat(gotRequest.getTimeoutUptimeMs()).isGreaterThan(1000); 875 876 mPropertyHalService.cancelRequests(new int[]{REQUEST_ID_1}); 877 878 // Because we cancel the onging async set property request, the ongoing get initial value 879 // request should be cancelled as well. 880 verify(mVehicleHal, timeout(1000).times(2)).cancelRequests(any()); 881 assertThat(vhalCancelledRequestIds).containsExactlyElementsIn(new Integer[]{0, 1}); 882 883 verifyNoPendingRequest(); 884 } 885 886 @Test testSetCarPropertyValuesAsync_configNotFound()887 public void testSetCarPropertyValuesAsync_configNotFound() { 888 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 889 AsyncPropertyServiceRequest request = new AsyncPropertyServiceRequest( 890 REQUEST_ID_1, /* propertyId= */ 1, /* areaId= */ 0, 891 new CarPropertyValue(/* propertyId= */ 1, /* areaId= */ 0, SAMPLE_RATE_HZ)); 892 893 assertThrows(IllegalArgumentException.class, () -> { 894 mPropertyHalService.setCarPropertyValuesAsync(List.of(request), 895 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 896 /* asyncRequestStartTime= */ 0); 897 }); 898 899 verifyNoPendingRequest(); 900 } 901 902 @Test testSetCarPropertyValuesAsync_linkToDeath()903 public void testSetCarPropertyValuesAsync_linkToDeath() throws RemoteException { 904 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 905 List<AsyncPropertyServiceRequest> setPropertyServiceRequests = mock(List.class); 906 907 mPropertyHalService.setCarPropertyValuesAsync(setPropertyServiceRequests, 908 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 909 /* asyncRequestStartTime= */ 0); 910 911 verify(mSetAsyncPropertyResultBinder).linkToDeath(any(IBinder.DeathRecipient.class), 912 anyInt()); 913 914 verifyNoPendingRequest(); 915 } 916 917 // Test the case where we don't wait for property update event. The success callback should be 918 // immediately called when the set request succeeded. 919 @Test testSetCarPropertyValuesAsync_noWaitForPropertyUpdate()920 public void testSetCarPropertyValuesAsync_noWaitForPropertyUpdate() 921 throws Exception { 922 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 923 924 doAnswer((invocation) -> { 925 setInvocationWrap.add(invocation); 926 return null; 927 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 928 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 929 930 AsyncPropertyServiceRequest request = copyRequest(SET_HVAC_REQUEST_ID_1); 931 request.setWaitForPropertyUpdate(false); 932 933 mPropertyHalService.setCarPropertyValuesAsync(List.of(request), 934 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 935 /* asyncRequestStartTime= */ 0); 936 937 // Must not subscribe to the property for update events. 938 verify(mVehicleHal, never()).subscribeProperty(any(), anyList()); 939 // Must not send get initial value request. 940 verify(mVehicleHal, never()).getAsync(any(), any()); 941 assertThat(setInvocationWrap).hasSize(1); 942 943 // Returns the set value result. 944 deliverOkaySetResult(setInvocationWrap.get(0)); 945 946 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 947 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 948 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 949 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 950 .isEqualTo(STATUS_OK); 951 // This should be the time when the request is successfully sent. 952 assertThat(result.getUpdateTimestampNanos()).isGreaterThan(0); 953 954 verifyNoPendingRequest(); 955 } 956 957 @Test testSetCarPropertyValuesAsync_noWaitForPropertyUpdateWithMultipleAreaRequests()958 public void testSetCarPropertyValuesAsync_noWaitForPropertyUpdateWithMultipleAreaRequests() 959 throws Exception { 960 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 961 962 doAnswer((invocation) -> { 963 setInvocationWrap.add(invocation); 964 return null; 965 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 966 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 967 968 AsyncPropertyServiceRequest request1 = copyRequest(SET_VEHICLE_SPEED_AREA_ID_1_REQUEST); 969 AsyncPropertyServiceRequest request2 = copyRequest(SET_VEHICLE_SPEED_AREA_ID_2_REQUEST); 970 request1.setWaitForPropertyUpdate(false); 971 request2.setWaitForPropertyUpdate(false); 972 973 mPropertyHalService.setCarPropertyValuesAsync(List.of(request1, request2), 974 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 975 /* asyncRequestStartTime= */ 0); 976 977 // Must not subscribe to the property for update events. 978 verify(mVehicleHal, never()).subscribeProperty(any(), anyList()); 979 verify(mVehicleHal, never()).subscribeProperty(any(), anyList()); 980 // Must not send get initial value request. 981 verify(mVehicleHal, never()).getAsync(any(), any()); 982 assertThat(setInvocationWrap).hasSize(1); 983 984 // Returns the set value result. 985 deliverOkaySetResult(setInvocationWrap.get(0)); 986 987 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 988 GetSetValueResult result1 = mAsyncResultCaptor.getValue().getList().get(0); 989 assertThat(result1.getRequestId()).isEqualTo(REQUEST_ID_4); 990 assertThat(result1.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 991 .isEqualTo(STATUS_OK); 992 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 993 GetSetValueResult result2 = mAsyncResultCaptor.getValue().getList().get(1); 994 assertThat(result2.getRequestId()).isEqualTo(REQUEST_ID_5); 995 assertThat(result2.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 996 .isEqualTo(STATUS_OK); 997 998 // This should be the time when the request is successfully sent. 999 assertThat(result1.getUpdateTimestampNanos()).isGreaterThan(0); 1000 assertThat(result2.getUpdateTimestampNanos()).isGreaterThan(0); 1001 1002 verifyNoPendingRequest(); 1003 } 1004 1005 @Test testSetCarPropertyValuesAsync_mixWaitNoWaitForPropertyUpdate()1006 public void testSetCarPropertyValuesAsync_mixWaitNoWaitForPropertyUpdate() throws Exception { 1007 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1008 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1009 List<HalServiceBase> serviceWrap = new ArrayList<>(); 1010 1011 doAnswer((invocation) -> { 1012 setInvocationWrap.add(invocation); 1013 return null; 1014 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1015 doAnswer((invocation) -> { 1016 getInvocationWrap.add(invocation); 1017 return null; 1018 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1019 doAnswer((invocation) -> { 1020 serviceWrap.add(invocation.getArgument(0)); 1021 return null; 1022 }).when(mVehicleHal).subscribeProperty(any(), anyList()); 1023 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1024 1025 AsyncPropertyServiceRequest request1 = copyRequest(SET_HVAC_REQUEST_ID_1); 1026 AsyncPropertyServiceRequest request2 = copyRequest(SET_SPEED_REQUEST_ID_2); 1027 request2.setWaitForPropertyUpdate(false); 1028 1029 mPropertyHalService.setCarPropertyValuesAsync(List.of(request1, request2), 1030 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1031 /* asyncRequestStartTime= */ 0); 1032 1033 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1034 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 1035 assertThat(setInvocationWrap).hasSize(1); 1036 assertThat(getInvocationWrap).hasSize(1); 1037 1038 // Returns the get initial value result, assume we failed to get initial values. 1039 deliverErrorGetResult(getInvocationWrap.get(0), 1040 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 1041 1042 verify(mSetAsyncPropertyResultCallback, never()).onSetValueResults(any()); 1043 1044 // Returns the set value result. 1045 deliverOkaySetResult(setInvocationWrap.get(0)); 1046 1047 // We should receive the success callback for request 2 since the set request is already 1048 // sent. 1049 verify(mSetAsyncPropertyResultCallback).onSetValueResults( 1050 mAsyncResultCaptor.capture()); 1051 1052 // Deliver updated value for request 1. Request 2 don't need an updated value. 1053 assertThat(serviceWrap).hasSize(1); 1054 serviceWrap.get(0).onHalEvents(List.of(mPropValue)); 1055 1056 // Get init value result must not be passed to the client. 1057 verify(mSetAsyncPropertyResultCallback, never()).onGetValueResults(any()); 1058 // We should receive the success callback for request 1. 1059 verify(mSetAsyncPropertyResultCallback, times(2)).onSetValueResults( 1060 mAsyncResultCaptor.capture()); 1061 for (GetSetValueResultList results: mAsyncResultCaptor.getAllValues()) { 1062 GetSetValueResult result = results.getList().get(0); 1063 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 1064 .isEqualTo(STATUS_OK); 1065 if (result.getRequestId() == REQUEST_ID_1) { 1066 assertThat(result.getUpdateTimestampNanos()).isEqualTo( 1067 TEST_UPDATE_TIMESTAMP_NANOS); 1068 } else { 1069 assertThat(result.getUpdateTimestampNanos()).isNotEqualTo( 1070 TEST_UPDATE_TIMESTAMP_NANOS); 1071 // This should be elapsedRealTimeNano when the set is done. 1072 assertThat(result.getUpdateTimestampNanos()).isGreaterThan(0); 1073 } 1074 } 1075 // After the result comes, we must unsubscribe the property. 1076 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 1077 1078 verifyNoPendingRequest(); 1079 } 1080 1081 // Test the case where we get the result for the init value before we get the result for 1082 // async set. The init value is the same as the target value. 1083 @Test testSetCarPropertyValuesAsync_initValueSameAsTargetValue_beforeSetResult()1084 public void testSetCarPropertyValuesAsync_initValueSameAsTargetValue_beforeSetResult() 1085 throws Exception { 1086 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1087 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1088 1089 doAnswer((invocation) -> { 1090 setInvocationWrap.add(invocation); 1091 return null; 1092 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1093 doAnswer((invocation) -> { 1094 getInvocationWrap.add(invocation); 1095 return null; 1096 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1097 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1098 1099 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 1100 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1101 /* asyncRequestStartTime= */ 0); 1102 1103 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1104 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 1105 assertThat(setInvocationWrap).hasSize(1); 1106 assertThat(getInvocationWrap).hasSize(1); 1107 1108 // Returns the get initial value result. 1109 deliverOkayGetResult(getInvocationWrap.get(0)); 1110 1111 verify(mSetAsyncPropertyResultCallback, never()).onSetValueResults(any()); 1112 1113 // Returns the set value result. 1114 deliverOkaySetResult(setInvocationWrap.get(0)); 1115 1116 // Get init value result must not be passed to the client. 1117 verify(mSetAsyncPropertyResultCallback, never()).onGetValueResults(any()); 1118 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 1119 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 1120 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 1121 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 1122 .isEqualTo(STATUS_OK); 1123 assertThat(result.getUpdateTimestampNanos()).isEqualTo(TEST_UPDATE_TIMESTAMP_NANOS); 1124 // After the result comes, we must unsubscribe the property. 1125 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 1126 1127 verifyNoPendingRequest(); 1128 } 1129 1130 // Test the case where we get the result for the init value after we get the result for 1131 // async set. The init value is the same as the target value. 1132 @Test testSetCarPropertyValuesAsync_initValueSameAsTargetValue_afterSetResult()1133 public void testSetCarPropertyValuesAsync_initValueSameAsTargetValue_afterSetResult() 1134 throws Exception { 1135 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1136 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1137 1138 doAnswer((invocation) -> { 1139 setInvocationWrap.add(invocation); 1140 return null; 1141 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1142 doAnswer((invocation) -> { 1143 getInvocationWrap.add(invocation); 1144 return null; 1145 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1146 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1147 1148 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 1149 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1150 /* asyncRequestStartTime= */ 0); 1151 1152 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1153 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 1154 assertThat(setInvocationWrap).hasSize(1); 1155 assertThat(getInvocationWrap).hasSize(1); 1156 1157 // Returns the set value result. 1158 deliverOkaySetResult(setInvocationWrap.get(0)); 1159 1160 verify(mSetAsyncPropertyResultCallback, never()).onSetValueResults(any()); 1161 1162 // Returns the get initial value result. 1163 deliverOkayGetResult(getInvocationWrap.get(0)); 1164 1165 // Get init value result must not be passed to the client. 1166 verify(mSetAsyncPropertyResultCallback, never()).onGetValueResults(any()); 1167 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 1168 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 1169 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 1170 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 1171 .isEqualTo(STATUS_OK); 1172 assertThat(result.getUpdateTimestampNanos()).isEqualTo(TEST_UPDATE_TIMESTAMP_NANOS); 1173 // After the result comes, we must unsubscribe the property. 1174 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 1175 1176 verifyNoPendingRequest(); 1177 } 1178 1179 // Test the case where the get initial value and set value request retried once. 1180 // The init value is the same as the target value. 1181 @Test testSetCarPropertyValuesAsync_initValueSameAsTargetValue_retry()1182 public void testSetCarPropertyValuesAsync_initValueSameAsTargetValue_retry() 1183 throws Exception { 1184 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1185 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1186 1187 doAnswer((invocation) -> { 1188 setInvocationWrap.add(invocation); 1189 return null; 1190 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1191 doAnswer((invocation) -> { 1192 getInvocationWrap.add(invocation); 1193 return null; 1194 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1195 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1196 1197 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 1198 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1199 /* asyncRequestStartTime= */ 0); 1200 1201 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1202 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 1203 assertThat(setInvocationWrap).hasSize(1); 1204 assertThat(getInvocationWrap).hasSize(1); 1205 1206 // Retry get initial value request. 1207 deliverTryAgainGetResult(getInvocationWrap.get(0)); 1208 // Retry set initial value request. 1209 deliverTryAgainSetResult(setInvocationWrap.get(0)); 1210 1211 // Wait until the retry happens. 1212 verify(mVehicleHal, timeout(1000).times(2)).getAsync(any(), any()); 1213 verify(mVehicleHal, timeout(1000).times(2)).setAsync(any(), any()); 1214 1215 // Returns the set value result. 1216 deliverOkaySetResult(setInvocationWrap.get(1)); 1217 // Returns the get initial value result. 1218 deliverOkayGetResult(getInvocationWrap.get(1)); 1219 1220 verify(mSetAsyncPropertyResultCallback, never()).onGetValueResults(any()); 1221 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 1222 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 1223 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 1224 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 1225 .isEqualTo(STATUS_OK); 1226 assertThat(result.getUpdateTimestampNanos()).isEqualTo(TEST_UPDATE_TIMESTAMP_NANOS); 1227 // After the result comes, we must unsubscribe the property. 1228 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 1229 1230 verifyNoPendingRequest(); 1231 } 1232 1233 // Test the case where the get initial value returns a different value than target value. 1234 @Test testSetCarPropertyValuesAsync_initValueDiffTargetValue_timeout()1235 public void testSetCarPropertyValuesAsync_initValueDiffTargetValue_timeout() 1236 throws Exception { 1237 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1238 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1239 1240 doAnswer((invocation) -> { 1241 setInvocationWrap.add(invocation); 1242 return null; 1243 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1244 doAnswer((invocation) -> { 1245 getInvocationWrap.add(invocation); 1246 return null; 1247 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1248 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1249 1250 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 1251 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 100, 1252 /* asyncRequestStartTime= */ 0); 1253 1254 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1255 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 1256 assertThat(setInvocationWrap).hasSize(1); 1257 assertThat(getInvocationWrap).hasSize(1); 1258 1259 // Returns the get initial value result. 1260 deliverOkayGetResult(getInvocationWrap.get(0), mPropValueBuilder.build( 1261 HVAC_TEMPERATURE_SET, /* areaId= */ 0, 16.0f)); 1262 // Returns the set value result. 1263 deliverOkaySetResult(setInvocationWrap.get(0)); 1264 1265 // Get init value result must not be passed to the client. 1266 verify(mSetAsyncPropertyResultCallback, never()).onGetValueResults(any()); 1267 // Eventually the request should time out. 1268 verify(mSetAsyncPropertyResultCallback, timeout(1000)).onSetValueResults( 1269 mAsyncResultCaptor.capture()); 1270 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 1271 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 1272 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()).isEqualTo( 1273 CarPropertyManager.STATUS_ERROR_TIMEOUT); 1274 1275 verifyNoPendingRequest(); 1276 } 1277 1278 // Test the case where we get set value error result after we get the initial value result. 1279 @Test testSetCarPropertyValuesAsync_errorSetResultAfterTargetInitValueResult()1280 public void testSetCarPropertyValuesAsync_errorSetResultAfterTargetInitValueResult() 1281 throws Exception { 1282 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1283 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1284 1285 doAnswer((invocation) -> { 1286 setInvocationWrap.add(invocation); 1287 return null; 1288 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1289 doAnswer((invocation) -> { 1290 getInvocationWrap.add(invocation); 1291 return null; 1292 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1293 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1294 1295 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 1296 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1297 /* asyncRequestStartTime= */ 0); 1298 1299 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1300 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 1301 assertThat(setInvocationWrap).hasSize(1); 1302 assertThat(getInvocationWrap).hasSize(1); 1303 1304 // Returns the get initial value result. 1305 deliverOkayGetResult(getInvocationWrap.get(0)); 1306 // Returns the set value result. 1307 deliverErrorSetResult(setInvocationWrap.get(0), 1308 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 1309 1310 // Get init value result must not be passed to the client. 1311 verify(mSetAsyncPropertyResultCallback, never()).onGetValueResults(any()); 1312 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 1313 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 1314 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 1315 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 1316 .isEqualTo(CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 1317 // After the result comes, we must unsubscribe the property. 1318 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 1319 1320 verifyNoPendingRequest(); 1321 } 1322 1323 // Test the callback is only invoked once even though the same result is returned multiple 1324 // times. 1325 @Test testSetCarPropertyValuesAsync_callbackOnlyCalledOncePerRequest()1326 public void testSetCarPropertyValuesAsync_callbackOnlyCalledOncePerRequest() 1327 throws Exception { 1328 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1329 1330 doAnswer((invocation) -> { 1331 setInvocationWrap.add(invocation); 1332 return null; 1333 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1334 doAnswer((invocation) -> { 1335 return null; 1336 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1337 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1338 1339 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 1340 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1341 /* asyncRequestStartTime= */ 0); 1342 1343 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1344 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 1345 deliverErrorSetResult(setInvocationWrap.get(0), 1346 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 1347 1348 // The same result is returned again. 1349 deliverErrorSetResult(setInvocationWrap.get(0), 1350 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 1351 1352 // We must only call callback once. 1353 verify(mSetAsyncPropertyResultCallback, times(1)).onSetValueResults(any()); 1354 // After the result comes, we must unsubscribe the property. 1355 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 1356 1357 verifyNoPendingRequest(); 1358 } 1359 1360 // Test the case where the get init value request has error result. The result must be ignored. 1361 @Test testSetCarPropertyValuesAsync_errorInitValueResult_timeout()1362 public void testSetCarPropertyValuesAsync_errorInitValueResult_timeout() 1363 throws Exception { 1364 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1365 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1366 1367 doAnswer((invocation) -> { 1368 setInvocationWrap.add(invocation); 1369 return null; 1370 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1371 doAnswer((invocation) -> { 1372 getInvocationWrap.add(invocation); 1373 return null; 1374 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1375 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1376 1377 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 1378 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 100, 1379 /* asyncRequestStartTime= */ 0); 1380 1381 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1382 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 1383 assertThat(setInvocationWrap).hasSize(1); 1384 assertThat(getInvocationWrap).hasSize(1); 1385 1386 // Returns the get initial value result, assume we failed to get initial values. 1387 deliverErrorGetResult(getInvocationWrap.get(0), 1388 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 1389 // Returns the set value result. 1390 deliverOkaySetResult(setInvocationWrap.get(0)); 1391 1392 // Get init value result must not be passed to the client. 1393 verify(mSetAsyncPropertyResultCallback, never()).onGetValueResults(any()); 1394 // Eventually the request should time out. 1395 verify(mSetAsyncPropertyResultCallback, timeout(1000)).onSetValueResults( 1396 mAsyncResultCaptor.capture()); 1397 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 1398 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 1399 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()).isEqualTo( 1400 CarPropertyManager.STATUS_ERROR_TIMEOUT); 1401 1402 verifyNoPendingRequest(); 1403 } 1404 1405 @Test testSetCarPropertyValuesAsync_propertyUpdatedThroughEvent()1406 public void testSetCarPropertyValuesAsync_propertyUpdatedThroughEvent() 1407 throws Exception { 1408 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1409 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1410 List<HalServiceBase> serviceWrap = new ArrayList<>(); 1411 1412 doAnswer((invocation) -> { 1413 setInvocationWrap.add(invocation); 1414 return null; 1415 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1416 doAnswer((invocation) -> { 1417 getInvocationWrap.add(invocation); 1418 return null; 1419 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1420 doAnswer((invocation) -> { 1421 serviceWrap.add(invocation.getArgument(0)); 1422 return null; 1423 }).when(mVehicleHal).subscribeProperty(any(), anyList()); 1424 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1425 1426 float testSampleRate = 20.0f; 1427 AsyncPropertyServiceRequest request2 = copyRequest(SET_SPEED_REQUEST_ID_2); 1428 request2.setUpdateRateHz(testSampleRate); 1429 1430 mPropertyHalService.setCarPropertyValuesAsync(List.of( 1431 SET_HVAC_REQUEST_ID_1, request2), 1432 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1433 /* asyncRequestStartTime= */ 0); 1434 1435 assertThat(setInvocationWrap).hasSize(1); 1436 assertThat(getInvocationWrap).hasSize(1); 1437 1438 // Returns the get initial value result. 1439 deliverErrorGetResult(getInvocationWrap.get(0), 1440 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 1441 // Returns the set value result. 1442 deliverOkaySetResult(setInvocationWrap.get(0)); 1443 1444 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1445 assertThat(mListArgumentCaptor.getValue()).containsExactly( 1446 hvacHalSubscribeOption(), speedHalSubscribeOption(testSampleRate)); 1447 1448 // Notify the property is updated to the target value. 1449 assertThat(serviceWrap).hasSize(1); 1450 serviceWrap.get(0).onHalEvents(List.of(mPropValue)); 1451 serviceWrap.get(0).onHalEvents(List.of(mPropValue2)); 1452 1453 verify(mSetAsyncPropertyResultCallback, times(2)).onSetValueResults( 1454 mAsyncResultCaptor.capture()); 1455 for (GetSetValueResultList results : mAsyncResultCaptor.getAllValues()) { 1456 GetSetValueResult result = results.getList().get(0); 1457 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 1458 .isEqualTo(STATUS_OK); 1459 assertThat(result.getUpdateTimestampNanos()).isEqualTo(TEST_UPDATE_TIMESTAMP_NANOS); 1460 } 1461 // After the result comes, we must unsubscribe the property. 1462 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 1463 verify(mVehicleHal).unsubscribeProperty(any(), eq(PERF_VEHICLE_SPEED)); 1464 1465 verifyNoPendingRequest(); 1466 } 1467 1468 @Test testSetCarPropertyValuesAsync_propertyUpdatedThroughEvent_ignoreNonTargetEvent()1469 public void testSetCarPropertyValuesAsync_propertyUpdatedThroughEvent_ignoreNonTargetEvent() 1470 throws Exception { 1471 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1472 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1473 List<HalServiceBase> serviceWrap = new ArrayList<>(); 1474 1475 doAnswer((invocation) -> { 1476 setInvocationWrap.add(invocation); 1477 return null; 1478 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1479 doAnswer((invocation) -> { 1480 getInvocationWrap.add(invocation); 1481 return null; 1482 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1483 // Because HVAC_TEMPERATURE_SET is ON_CHANGE property, the sample rate is 0. 1484 doAnswer((invocation) -> { 1485 serviceWrap.add(invocation.getArgument(0)); 1486 return null; 1487 }).when(mVehicleHal).subscribeProperty(any(), anyList()); 1488 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1489 1490 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 1491 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1492 /* asyncRequestStartTime= */ 0); 1493 1494 assertThat(setInvocationWrap).hasSize(1); 1495 assertThat(getInvocationWrap).hasSize(1); 1496 1497 // Returns the get initial value result. This is not the target value. 1498 deliverOkayGetResult(getInvocationWrap.get(0), mPropValueBuilder.build( 1499 HVAC_TEMPERATURE_SET, /* areaId= */ 0, 16.0f)); 1500 // Returns the set value result. 1501 deliverOkaySetResult(setInvocationWrap.get(0)); 1502 1503 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1504 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 1505 1506 // Generate a property update event with non-target value. 1507 serviceWrap.get(0).onHalEvents(List.of(mNonTargetPropValue)); 1508 1509 verify(mSetAsyncPropertyResultCallback, never()).onSetValueResults(any()); 1510 1511 // Notify the property is updated to the target value. 1512 serviceWrap.get(0).onHalEvents(List.of(mPropValue)); 1513 1514 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 1515 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 1516 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 1517 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 1518 .isEqualTo(STATUS_OK); 1519 assertThat(result.getUpdateTimestampNanos()).isEqualTo(TEST_UPDATE_TIMESTAMP_NANOS); 1520 // After the result comes, we must unsubscribe the property. 1521 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 1522 1523 verifyNoPendingRequest(); 1524 } 1525 1526 @Test testSetCarPropertyValuesAsync_updateSubscriptionRate()1527 public void testSetCarPropertyValuesAsync_updateSubscriptionRate() 1528 throws Exception { 1529 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1530 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1531 1532 doAnswer((invocation) -> { 1533 setInvocationWrap.add(invocation); 1534 return null; 1535 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1536 doAnswer((invocation) -> { 1537 getInvocationWrap.add(invocation); 1538 return null; 1539 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1540 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1541 1542 AsyncPropertyServiceRequest request = copyRequest(SET_SPEED_REQUEST_ID_2); 1543 request.setUpdateRateHz(20.0f); 1544 mPropertyHalService.setCarPropertyValuesAsync(List.of(request), 1545 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1546 /* asyncRequestStartTime= */ 0); 1547 1548 assertThat(setInvocationWrap).hasSize(1); 1549 assertThat(getInvocationWrap).hasSize(1); 1550 1551 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1552 assertThat(mListArgumentCaptor.getValue()).containsExactly(speedHalSubscribeOption(20f)); 1553 clearInvocations(mVehicleHal); 1554 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1555 1556 mPropertyHalService.subscribeProperty(List.of(createCarSubscriptionOption( 1557 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 1558 /* enableVur= */ true))); 1559 1560 // Subscription rate has to be updated according to client subscription. 1561 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1562 assertThat(mListArgumentCaptor.getValue()).containsExactly(speedHalSubscribeOption(40f)); 1563 clearInvocations(mVehicleHal); 1564 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1565 1566 // After client unsubscribe, revert back to the internal subscription rate. 1567 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED); 1568 1569 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1570 assertThat(mListArgumentCaptor.getValue()).containsExactly(speedHalSubscribeOption(20f)); 1571 clearInvocations(mVehicleHal); 1572 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1573 1574 // New client subscription must overwrite the internal rate. 1575 mPropertyHalService.subscribeProperty(List.of(createCarSubscriptionOption( 1576 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 50.0f, 1577 /* enableVur= */ true))); 1578 1579 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1580 assertThat(mListArgumentCaptor.getValue()).containsExactly(speedHalSubscribeOption(50f)); 1581 clearInvocations(mVehicleHal); 1582 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1583 1584 // Finish the async set request. 1585 deliverOkaySetResult(setInvocationWrap.get(0)); 1586 deliverOkayGetResult(getInvocationWrap.get(0), mPropValue2); 1587 1588 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 1589 assertThat( 1590 mAsyncResultCaptor.getValue().getList().get(0) 1591 .getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 1592 .isEqualTo(STATUS_OK); 1593 1594 // After the internal subscription is finished, the client subscription must be kept, 1595 // which causes no update to update rate. 1596 verify(mVehicleHal, never()).subscribeProperty(any(), any()); 1597 1598 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED); 1599 1600 // After both client and internal unsubscription, the property must be unsubscribed. 1601 verify(mVehicleHal).unsubscribeProperty(any(), eq(PERF_VEHICLE_SPEED)); 1602 1603 verifyNoPendingRequest(); 1604 } 1605 1606 @Test testMultipleSetCarPropertyValuesAsync_updateSubscriptionRateWithDifferentAreaIds()1607 public void testMultipleSetCarPropertyValuesAsync_updateSubscriptionRateWithDifferentAreaIds() 1608 throws Exception { 1609 when(mMockCarPropertyConfig2.getAreaIds()).thenReturn(new int[]{0, 1, 2}); 1610 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1611 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1612 1613 doAnswer((invocation) -> { 1614 setInvocationWrap.add(invocation); 1615 return null; 1616 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1617 doAnswer((invocation) -> { 1618 getInvocationWrap.add(invocation); 1619 return null; 1620 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1621 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1622 1623 AsyncPropertyServiceRequest request1 = copyRequest(SET_VEHICLE_SPEED_AREA_ID_1_REQUEST); 1624 request1.setUpdateRateHz(20.0f); 1625 AsyncPropertyServiceRequest request2 = copyRequest(SET_VEHICLE_SPEED_AREA_ID_2_REQUEST); 1626 request2.setUpdateRateHz(21.0f); 1627 mPropertyHalService.setCarPropertyValuesAsync(List.of(request1, request2), 1628 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1629 /* asyncRequestStartTime= */ 0); 1630 1631 assertThat(setInvocationWrap).hasSize(1); 1632 assertThat(getInvocationWrap).hasSize(1); 1633 1634 1635 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1636 assertThat(mListArgumentCaptor.getValue()).containsExactly( 1637 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, 20f, 1638 /* enableVariableUpdateRate= */ true), 1639 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{2}, 21f, 1640 /* enableVariableUpdateRate= */ true)); 1641 clearInvocations(mVehicleHal); 1642 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1643 1644 1645 List<CarSubscription> carSubscriptions = new ArrayList<>(); 1646 carSubscriptions.add(createCarSubscriptionOption(PERF_VEHICLE_SPEED, new int[] {1}, 1647 /* updateRateHz= */ 40.0f, /* enableVur= */ true)); 1648 mPropertyHalService.subscribeProperty(carSubscriptions); 1649 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1650 assertThat(mListArgumentCaptor.getValue()).containsExactly( 1651 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, 40f, 1652 /* enableVariableUpdateRate= */ true)); 1653 clearInvocations(mVehicleHal); 1654 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1655 1656 carSubscriptions = new ArrayList<>(); 1657 carSubscriptions.add(createCarSubscriptionOption(PERF_VEHICLE_SPEED, new int[] {2}, 1658 /* updateRateHz= */ 41.0f, /* enableVur= */ true)); 1659 mPropertyHalService.subscribeProperty(carSubscriptions); 1660 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1661 assertThat(mListArgumentCaptor.getValue()).containsExactly( 1662 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{2}, 41f, 1663 /* enableVariableUpdateRate= */ true)); 1664 clearInvocations(mVehicleHal); 1665 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1666 1667 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED); 1668 1669 // After client unsubscribe, revert back to the internal subscription rate 1670 1671 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1672 assertThat(mListArgumentCaptor.getValue()).containsExactly( 1673 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, 20f, 1674 /* enableVariableUpdateRate= */ true), 1675 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{2}, 21f, 1676 /* enableVariableUpdateRate= */ true)); 1677 clearInvocations(mVehicleHal); 1678 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1679 1680 1681 carSubscriptions = new ArrayList<>(); 1682 carSubscriptions.add(createCarSubscriptionOption(PERF_VEHICLE_SPEED, new int[] {1}, 1683 /* updateRateHz= */ 30.0f, /* enableVur= */ true)); 1684 mPropertyHalService.subscribeProperty(carSubscriptions); 1685 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1686 assertThat(mListArgumentCaptor.getValue()).containsExactly( 1687 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, 30f, 1688 /* enableVariableUpdateRate= */ true)); 1689 clearInvocations(mVehicleHal); 1690 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1691 1692 carSubscriptions = new ArrayList<>(); 1693 carSubscriptions.add(createCarSubscriptionOption(PERF_VEHICLE_SPEED, new int[] {2}, 1694 /* updateRateHz= */ 31.0f, /* enableVur= */ true)); 1695 mPropertyHalService.subscribeProperty(carSubscriptions); 1696 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1697 assertThat(mListArgumentCaptor.getValue()).containsExactly( 1698 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{2}, 31f, 1699 /* enableVariableUpdateRate= */ true)); 1700 clearInvocations(mVehicleHal); 1701 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1702 1703 deliverOkaySetResult(setInvocationWrap.get(0)); 1704 deliverOkayGetResult(getInvocationWrap.get(0), mPropValue2); 1705 1706 // After the internal subscription is finished, the client subscription must be kept. 1707 // The internal subscription rate is lower than the client rate, so no rate change. 1708 verify(mVehicleHal, never()).subscribeProperty(any(), any()); 1709 1710 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 1711 assertThat(mAsyncResultCaptor.getValue().getList().get(0).getCarPropertyErrorCodes() 1712 .getCarPropertyManagerErrorCode()).isEqualTo(STATUS_OK); 1713 assertThat(mAsyncResultCaptor.getValue().getList().get(1).getCarPropertyErrorCodes() 1714 .getCarPropertyManagerErrorCode()).isEqualTo(STATUS_OK); 1715 1716 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED); 1717 1718 // After both client and internal unsubscription, the property must be unsubscribed. 1719 verify(mVehicleHal).unsubscribeProperty(any(), eq(PERF_VEHICLE_SPEED)); 1720 1721 verifyNoPendingRequest(); 1722 } 1723 1724 @Test testMultipleSetCarPropertyValuesAsync_overlappingSetAsync()1725 public void testMultipleSetCarPropertyValuesAsync_overlappingSetAsync() 1726 throws Exception { 1727 when(mMockCarPropertyConfig2.getAreaIds()).thenReturn(new int[]{0, 1, 2}); 1728 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1729 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1730 1731 doAnswer((invocation) -> { 1732 setInvocationWrap.add(invocation); 1733 return null; 1734 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1735 doAnswer((invocation) -> { 1736 getInvocationWrap.add(invocation); 1737 return null; 1738 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1739 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1740 1741 AsyncPropertyServiceRequest request1 = copyRequest(SET_VEHICLE_SPEED_AREA_ID_1_REQUEST); 1742 request1.setUpdateRateHz(20.0f); 1743 AsyncPropertyServiceRequest request2 = copyRequest(SET_VEHICLE_SPEED_AREA_ID_2_REQUEST); 1744 request2.setUpdateRateHz(21.0f); 1745 mPropertyHalService.setCarPropertyValuesAsync(List.of(request1), 1746 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1747 /* asyncRequestStartTime= */ 0); 1748 mPropertyHalService.setCarPropertyValuesAsync(List.of(request2), 1749 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1750 /* asyncRequestStartTime= */ 0); 1751 1752 assertThat(setInvocationWrap).hasSize(2); 1753 assertThat(getInvocationWrap).hasSize(2); 1754 1755 verify(mVehicleHal, times(2)).subscribeProperty(any(), mListArgumentCaptor.capture()); 1756 assertThat(mListArgumentCaptor.getAllValues().get(0)).containsExactly( 1757 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, 20f, 1758 /* enableVariableUpdateRate= */ true)); 1759 assertThat(mListArgumentCaptor.getAllValues().get(1)).containsExactly( 1760 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{2}, 21f, 1761 /* enableVariableUpdateRate= */ true)); 1762 clearInvocations(mVehicleHal); 1763 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1764 1765 List<CarSubscription> carSubscriptions = new ArrayList<>(); 1766 carSubscriptions.add(createCarSubscriptionOption(PERF_VEHICLE_SPEED, new int[] {1}, 1767 /* updateRateHz= */ 40.0f, /* enableVur= */ true)); 1768 carSubscriptions.add(createCarSubscriptionOption(PERF_VEHICLE_SPEED, new int[] {2}, 1769 /* updateRateHz= */ 41.0f, /* enableVur= */ true)); 1770 mPropertyHalService.subscribeProperty(carSubscriptions); 1771 1772 // Subscription rate has to be updated according to client subscription. 1773 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1774 assertThat(mListArgumentCaptor.getValue()).containsExactly( 1775 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, 40f, 1776 /* enableVariableUpdateRate= */ true), 1777 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{2}, 41f, 1778 /* enableVariableUpdateRate= */ true)); 1779 clearInvocations(mVehicleHal); 1780 1781 deliverOkaySetResult(setInvocationWrap.get(0)); 1782 deliverOkayGetResult(getInvocationWrap.get(0), mPropValue2); 1783 1784 // Unsubscribing to internal rate 20.0f and 21.0f does not change the current client rate 1785 // 40 and 41. 1786 verify(mVehicleHal, never()).subscribeProperty(any(), any()); 1787 1788 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1789 1790 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED); 1791 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1792 assertThat(mListArgumentCaptor.getValue()).containsExactly(new HalSubscribeOptions( 1793 PERF_VEHICLE_SPEED, new int[]{2}, 21f, /* enableVariableUpdateRate= */ true)); 1794 clearInvocations(mVehicleHal); 1795 1796 deliverOkaySetResult(setInvocationWrap.get(1)); 1797 deliverOkayGetResult(getInvocationWrap.get(1), mPropValue2); 1798 1799 // Subscription rate has to be updated according to client subscription. 1800 verify(mVehicleHal).unsubscribeProperty(any(), eq(PERF_VEHICLE_SPEED)); 1801 1802 verifyNoPendingRequest(); 1803 } 1804 1805 @Test testSetCarPropertyValuesAsync_withSubscriptionFromDifferentAreaIds()1806 public void testSetCarPropertyValuesAsync_withSubscriptionFromDifferentAreaIds() 1807 throws Exception { 1808 when(mMockCarPropertyConfig2.getAreaIds()).thenReturn(new int[]{0, 1}); 1809 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1810 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1811 1812 doAnswer((invocation) -> { 1813 setInvocationWrap.add(invocation); 1814 return null; 1815 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1816 doAnswer((invocation) -> { 1817 getInvocationWrap.add(invocation); 1818 return null; 1819 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1820 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1821 1822 AsyncPropertyServiceRequest request = copyRequest(SET_VEHICLE_SPEED_AREA_ID_1_REQUEST); 1823 request.setUpdateRateHz(20.0f); 1824 mPropertyHalService.setCarPropertyValuesAsync(List.of(request), 1825 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1826 /* asyncRequestStartTime= */ 0); 1827 1828 assertThat(setInvocationWrap).hasSize(1); 1829 assertThat(getInvocationWrap).hasSize(1); 1830 1831 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1832 assertThat(mListArgumentCaptor.getAllValues().get(0)).containsExactly( 1833 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, 20f, 1834 /* enableVariableUpdateRate= */ true)); 1835 clearInvocations(mVehicleHal); 1836 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1837 1838 mPropertyHalService.subscribeProperty(List.of(createCarSubscriptionOption( 1839 PERF_VEHICLE_SPEED, new int[]{0, 1}, /* updateRateHz= */ 40.0f, 1840 /* enableVur= */ true))); 1841 1842 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1843 assertThat(mListArgumentCaptor.getAllValues().get(0)).containsExactly( 1844 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{0, 1}, 40f, 1845 /* enableVariableUpdateRate= */ true)); 1846 clearInvocations(mVehicleHal); 1847 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1848 1849 // After client unsubscribe, revert back to the internal subscription rate. 1850 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED); 1851 1852 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1853 assertThat(mListArgumentCaptor.getAllValues().get(0)).containsExactly( 1854 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, 20f, 1855 /* enableVariableUpdateRate= */ true)); 1856 clearInvocations(mVehicleHal); 1857 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1858 1859 // New client subscription must overwrite the internal rate. 1860 List<CarSubscription> carSubscriptions = new ArrayList<>(); 1861 carSubscriptions.add(createCarSubscriptionOption(PERF_VEHICLE_SPEED, new int[] {1}, 1862 /* updateRateHz= */ 50.0f, /* enableVur= */ true)); 1863 mPropertyHalService.subscribeProperty(carSubscriptions); 1864 1865 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1866 assertThat(mListArgumentCaptor.getAllValues().get(0)).containsExactly( 1867 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, 50f, 1868 /* enableVariableUpdateRate= */ true)); 1869 clearInvocations(mVehicleHal); 1870 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1871 clearInvocations(mVehicleHal); 1872 1873 // Finish the async set request. 1874 deliverOkaySetResult(setInvocationWrap.get(0)); 1875 deliverOkayGetResult(getInvocationWrap.get(0), mPropValue2); 1876 1877 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 1878 assertThat(mAsyncResultCaptor.getValue().getList().get(0).getCarPropertyErrorCodes() 1879 .getCarPropertyManagerErrorCode()).isEqualTo(STATUS_OK); 1880 1881 // After the internal subscription is finished, the client is still subscribed at 50hz 1882 // and no update rate change is required. 1883 verify(mVehicleHal, never()).subscribeProperty(any(), any()); 1884 1885 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED); 1886 1887 // After both client and internal unsubscription, the property must be unsubscribed. 1888 verify(mVehicleHal).unsubscribeProperty(any(), eq(PERF_VEHICLE_SPEED)); 1889 1890 verifyNoPendingRequest(); 1891 } 1892 1893 @Test testSetCarPropertyValuesAsync_defaultSubscriptionRate()1894 public void testSetCarPropertyValuesAsync_defaultSubscriptionRate() 1895 throws Exception { 1896 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1897 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1898 1899 doAnswer((invocation) -> { 1900 setInvocationWrap.add(invocation); 1901 return null; 1902 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1903 doAnswer((invocation) -> { 1904 getInvocationWrap.add(invocation); 1905 return null; 1906 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1907 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1908 1909 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_SPEED_REQUEST_ID_2), 1910 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 10, 1911 /* asyncRequestStartTime= */ 0); 1912 1913 assertThat(setInvocationWrap).hasSize(1); 1914 assertThat(getInvocationWrap).hasSize(1); 1915 1916 // Default sample rate is set to max sample rate. 1917 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1918 assertThat(mListArgumentCaptor.getValue()).containsExactly(speedHalSubscribeOption(100f)); 1919 1920 // Finish the async set request. 1921 deliverOkaySetResult(setInvocationWrap.get(0)); 1922 deliverOkayGetResult(getInvocationWrap.get(0), mPropValue2); 1923 } 1924 1925 @Test testSetCarPropertyValuesAsync_defaultSubscriptionRateDifferentAreaIds()1926 public void testSetCarPropertyValuesAsync_defaultSubscriptionRateDifferentAreaIds() { 1927 when(mMockCarPropertyConfig2.getAreaIds()).thenReturn(new int[]{0, 1}); 1928 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1929 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1930 1931 doAnswer((invocation) -> { 1932 setInvocationWrap.add(invocation); 1933 return null; 1934 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1935 doAnswer((invocation) -> { 1936 getInvocationWrap.add(invocation); 1937 return null; 1938 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1939 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1940 1941 mPropertyHalService.setCarPropertyValuesAsync( 1942 List.of(SET_VEHICLE_SPEED_AREA_ID_1_REQUEST, SET_HVAC_REQUEST_ID_1), 1943 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 10, 1944 /* asyncRequestStartTime= */ 0); 1945 1946 assertThat(setInvocationWrap).hasSize(1); 1947 assertThat(getInvocationWrap).hasSize(1); 1948 1949 // Default sample rate is set to max sample rate. 1950 float maxSampleRate = 100.0f; 1951 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1952 assertThat(mListArgumentCaptor.getValue()).containsExactly( 1953 hvacHalSubscribeOption(), 1954 new HalSubscribeOptions(PERF_VEHICLE_SPEED, new int[]{1}, maxSampleRate, 1955 /* enableVariableUpdateRate= */ true)); 1956 1957 // Finish the async set request. 1958 deliverOkaySetResult(setInvocationWrap.get(0)); 1959 deliverOkayGetResult(getInvocationWrap.get(0), mPropValue2); 1960 } 1961 1962 @Test testSetCarPropertyValuesAsync_setUpdateRateHz()1963 public void testSetCarPropertyValuesAsync_setUpdateRateHz() 1964 throws Exception { 1965 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 1966 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 1967 1968 doAnswer((invocation) -> { 1969 setInvocationWrap.add(invocation); 1970 return null; 1971 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1972 doAnswer((invocation) -> { 1973 getInvocationWrap.add(invocation); 1974 return null; 1975 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 1976 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 1977 1978 mPropertyHalService.subscribeProperty(List.of(createCarSubscriptionOption( 1979 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 22.0f, 1980 /* enableVur= */ true))); 1981 1982 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1983 assertThat(mListArgumentCaptor.getAllValues().get(0)).containsExactly( 1984 speedHalSubscribeOption(22.0f)); 1985 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 1986 clearInvocations(mVehicleHal); 1987 1988 AsyncPropertyServiceRequest request1 = copyRequest(SET_SPEED_REQUEST_ID_2); 1989 request1.setUpdateRateHz(23.1f); 1990 AsyncPropertyServiceRequest request2 = copyRequest(SET_SPEED_REQUEST_ID_3); 1991 request2.setUpdateRateHz(23.2f); 1992 mPropertyHalService.setCarPropertyValuesAsync(List.of(request1, request2), 1993 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 1994 /* asyncRequestStartTime= */ 0); 1995 1996 assertThat(setInvocationWrap).hasSize(1); 1997 assertThat(getInvocationWrap).hasSize(1); 1998 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 1999 assertThat(mListArgumentCaptor.getAllValues().get(0)).containsExactly( 2000 speedHalSubscribeOption(23.2f)); 2001 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 2002 clearInvocations(mVehicleHal); 2003 2004 // Finish the async set request. 2005 deliverOkaySetResult(setInvocationWrap.get(0)); 2006 deliverOkayGetResult(getInvocationWrap.get(0), mPropValue2); 2007 2008 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 2009 // Both request must succeed. 2010 assertThat(mAsyncResultCaptor.getValue().getList()).hasSize(2); 2011 assertThat(mAsyncResultCaptor.getValue().getList().get(0).getCarPropertyErrorCodes() 2012 .getCarPropertyManagerErrorCode()).isEqualTo(STATUS_OK); 2013 assertThat(mAsyncResultCaptor.getValue().getList().get(1).getCarPropertyErrorCodes() 2014 .getCarPropertyManagerErrorCode()).isEqualTo(STATUS_OK); 2015 2016 // After internal subscription complete, the client subscription rate must be kept. 2017 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 2018 assertThat(mListArgumentCaptor.getValue()).containsExactly(speedHalSubscribeOption(22.0f)); 2019 2020 verifyNoPendingRequest(); 2021 } 2022 2023 @Test testSetCarPropertyValuesAsync_cancelledBeforePropertyUpdateEvent()2024 public void testSetCarPropertyValuesAsync_cancelledBeforePropertyUpdateEvent() 2025 throws Exception { 2026 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 2027 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 2028 List<HalServiceBase> serviceWrap = new ArrayList<>(); 2029 2030 doAnswer((invocation) -> { 2031 setInvocationWrap.add(invocation); 2032 return null; 2033 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2034 doAnswer((invocation) -> { 2035 getInvocationWrap.add(invocation); 2036 return null; 2037 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2038 // Because HVAC_TEMPERATURE_SET is ON_CHANGE property, the sample rate is 0. 2039 doAnswer((invocation) -> { 2040 serviceWrap.add(invocation.getArgument(0)); 2041 return null; 2042 }).when(mVehicleHal).subscribeProperty(any(), anyList()); 2043 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2044 2045 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 2046 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2047 /* asyncRequestStartTime= */ 0); 2048 2049 assertThat(setInvocationWrap).hasSize(1); 2050 assertThat(getInvocationWrap).hasSize(1); 2051 2052 // Returns the set value result. 2053 deliverOkaySetResult(setInvocationWrap.get(0)); 2054 2055 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 2056 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 2057 2058 // Cancel the ongoing request. 2059 mPropertyHalService.cancelRequests(new int[]{REQUEST_ID_1}); 2060 2061 // Notify the property is updated to the target value after the request is cancelled. 2062 serviceWrap.get(0).onHalEvents(List.of(mPropValue)); 2063 2064 verify(mSetAsyncPropertyResultCallback, never()).onSetValueResults(any()); 2065 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 2066 2067 verifyNoPendingRequest(); 2068 } 2069 2070 @Test testSetCarPropertyValuesAsync_timeoutBeforePropertyUpdateEvent()2071 public void testSetCarPropertyValuesAsync_timeoutBeforePropertyUpdateEvent() 2072 throws Exception { 2073 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 2074 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 2075 List<HalServiceBase> serviceWrap = new ArrayList<>(); 2076 2077 doAnswer((invocation) -> { 2078 setInvocationWrap.add(invocation); 2079 return null; 2080 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2081 doAnswer((invocation) -> { 2082 getInvocationWrap.add(invocation); 2083 return null; 2084 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2085 // Because HVAC_TEMPERATURE_SET is ON_CHANGE property, the sample rate is 0. 2086 doAnswer((invocation) -> { 2087 serviceWrap.add(invocation.getArgument(0)); 2088 return null; 2089 }).when(mVehicleHal).subscribeProperty(any(), anyList()); 2090 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2091 2092 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 2093 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2094 /* asyncRequestStartTime= */ 0); 2095 2096 assertThat(setInvocationWrap).hasSize(1); 2097 assertThat(getInvocationWrap).hasSize(1); 2098 2099 // Returns the set value result. 2100 deliverOkaySetResult(setInvocationWrap.get(0)); 2101 2102 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 2103 assertThat(mListArgumentCaptor.getValue()).containsExactly(hvacHalSubscribeOption()); 2104 2105 List<AsyncGetSetRequest> setAsyncRequests = setInvocationWrap.get(0).getArgument(0); 2106 VehicleStubCallbackInterface callback = setInvocationWrap.get(0).getArgument(1); 2107 callback.onRequestsTimeout( 2108 List.of(setAsyncRequests.get(0).getServiceRequestId())); 2109 2110 // Notify the property is updated to the target value after the request is cancelled. 2111 serviceWrap.get(0).onHalEvents(List.of(mPropValue)); 2112 2113 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 2114 assertThat(mAsyncResultCaptor.getValue().getList()).hasSize(1); 2115 assertThat( 2116 mAsyncResultCaptor.getValue().getList().get(0).getCarPropertyErrorCodes() 2117 .getCarPropertyManagerErrorCode()) 2118 .isEqualTo(CarPropertyManager.STATUS_ERROR_TIMEOUT); 2119 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 2120 2121 verifyNoPendingRequest(); 2122 } 2123 2124 // If we receive errors for the [propId, areaId] we are setting via onPropertySetError, we must 2125 // fail the pending request. 2126 @Test testSetCarPropertyValuesAsync_onPropertySetError()2127 public void testSetCarPropertyValuesAsync_onPropertySetError() throws RemoteException { 2128 when(mMockCarPropertyConfig1.getAreaIds()).thenReturn(new int[]{1}); 2129 List<HalServiceBase> serviceWrap = new ArrayList<>(); 2130 AsyncPropertyServiceRequest setPropertyRequest = 2131 new AsyncPropertyServiceRequest(1, HVAC_TEMPERATURE_SET, /* areaId= */ 1); 2132 2133 doNothing().when(mVehicleHal).setAsync(anyList(), 2134 any(VehicleStubCallbackInterface.class)); 2135 doNothing().when(mVehicleHal).getAsync(anyList(), 2136 any(VehicleStubCallbackInterface.class)); 2137 doAnswer((invocation) -> { 2138 serviceWrap.add(invocation.getArgument(0)); 2139 return null; 2140 }).when(mVehicleHal).subscribeProperty(any(), anyList()); 2141 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2142 2143 mPropertyHalService.setCarPropertyValuesAsync(List.of(setPropertyRequest), 2144 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2145 /* asyncRequestStartTime= */ 0); 2146 2147 ArrayList<VehiclePropError> vehiclePropErrors = new ArrayList<>(); 2148 VehiclePropError error1 = new VehiclePropError(); 2149 error1.propId = HVAC_TEMPERATURE_SET; 2150 error1.areaId = 1; 2151 error1.errorCode = STATUS_NOT_AVAILABLE | (0x1234 << 16); 2152 // Error 2 has the wrong area ID and must be ignored. 2153 VehiclePropError error2 = new VehiclePropError(); 2154 error2.propId = HVAC_TEMPERATURE_SET; 2155 error2.areaId = 2; 2156 error2.errorCode = STATUS_INTERNAL_ERROR; 2157 vehiclePropErrors.add(error1); 2158 vehiclePropErrors.add(error2); 2159 assertThat(serviceWrap).hasSize(1); 2160 serviceWrap.get(0).onPropertySetError(vehiclePropErrors); 2161 2162 verify(mSetAsyncPropertyResultCallback).onSetValueResults(mAsyncResultCaptor.capture()); 2163 assertThat(mAsyncResultCaptor.getValue().getList()).hasSize(1); 2164 assertThat( 2165 mAsyncResultCaptor.getValue().getList().get(0).getCarPropertyErrorCodes() 2166 .getCarPropertyManagerErrorCode()) 2167 .isEqualTo(CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE); 2168 assertThat( 2169 mAsyncResultCaptor.getValue().getList().get(0).getCarPropertyErrorCodes() 2170 .getVendorErrorCode()) 2171 .isEqualTo(0x1234); 2172 assertThat(mAsyncResultCaptor.getValue().getList().get(0).getCarPropertyErrorCodes() 2173 .getSystemErrorCode()) 2174 .isEqualTo(STATUS_NOT_AVAILABLE); 2175 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 2176 2177 verifyNoPendingRequest(); 2178 } 2179 2180 @Test testOnSetAsyncResults_RetryAndTimeout()2181 public void testOnSetAsyncResults_RetryAndTimeout() throws RemoteException { 2182 doAnswer((invocation) -> { 2183 // For every request, we return retry result. 2184 return deliverTryAgainSetResult(invocation); 2185 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2186 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2187 2188 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 2189 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 10, 2190 /* asyncRequestStartTime= */ 0); 2191 2192 verify(mSetAsyncPropertyResultCallback, timeout(1000)).onSetValueResults( 2193 mAsyncResultCaptor.capture()); 2194 assertThat(mAsyncResultCaptor.getValue().getList().get(0).getRequestId()) 2195 .isEqualTo(REQUEST_ID_1); 2196 assertThat( 2197 mAsyncResultCaptor.getValue().getList().get(0).getCarPropertyErrorCodes() 2198 .getCarPropertyManagerErrorCode()) 2199 .isEqualTo(CarPropertyManager.STATUS_ERROR_TIMEOUT); 2200 2201 verifyNoPendingRequest(); 2202 } 2203 2204 @Test testOnSetAsyncResults_TimeoutFromVehicleStub()2205 public void testOnSetAsyncResults_TimeoutFromVehicleStub() throws RemoteException { 2206 doAnswer((invocation) -> { 2207 Object[] args = invocation.getArguments(); 2208 List requests = (List) args[0]; 2209 AsyncGetSetRequest request = (AsyncGetSetRequest) requests.get(0); 2210 VehicleStubCallbackInterface callback = (VehicleStubCallbackInterface) args[1]; 2211 // Simulate the request has already timed-out. 2212 callback.onRequestsTimeout(List.of(request.getServiceRequestId())); 2213 return null; 2214 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2215 2216 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2217 2218 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 2219 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2220 /* asyncRequestStartTime= */ 0); 2221 2222 verify(mSetAsyncPropertyResultCallback, timeout(1000)).onSetValueResults( 2223 mAsyncResultCaptor.capture()); 2224 assertThat(mAsyncResultCaptor.getValue().getList().get(0).getRequestId()) 2225 .isEqualTo(REQUEST_ID_1); 2226 assertThat(mAsyncResultCaptor.getValue().getList().get(0).getCarPropertyErrorCodes() 2227 .getCarPropertyManagerErrorCode()) 2228 .isEqualTo(CarPropertyManager.STATUS_ERROR_TIMEOUT); 2229 2230 verifyNoPendingRequest(); 2231 } 2232 2233 @Test testOnSetAsyncResults_errorResult()2234 public void testOnSetAsyncResults_errorResult() throws RemoteException { 2235 doAnswer((invocation) -> { 2236 return deliverErrorSetResult(invocation, RECEIVED_REQUEST_ID_1, 2237 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 2238 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2239 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2240 2241 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 2242 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2243 /* asyncRequestStartTime= */ 0); 2244 2245 verify(mSetAsyncPropertyResultCallback, timeout(1000)).onSetValueResults( 2246 mAsyncResultCaptor.capture()); 2247 GetSetValueResult result = mAsyncResultCaptor.getValue().getList().get(0); 2248 assertThat(result.getRequestId()).isEqualTo(REQUEST_ID_1); 2249 assertThat(result.getCarPropertyErrorCodes().getCarPropertyManagerErrorCode()) 2250 .isEqualTo(CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR); 2251 assertThat(result.getCarPropertyValue()).isEqualTo(null); 2252 2253 verifyNoPendingRequest(); 2254 } 2255 2256 @Test setProperty_handlesHalAndMgrPropIdMismatch()2257 public void setProperty_handlesHalAndMgrPropIdMismatch() { 2258 HalPropConfig mockPropConfig = mock(HalPropConfig.class); 2259 CarPropertyValue mockCarPropertyValue = mock(CarPropertyValue.class); 2260 when(mockCarPropertyValue.getPropertyId()).thenReturn( 2261 VehiclePropertyIds.VEHICLE_SPEED_DISPLAY_UNITS); 2262 when(mockCarPropertyValue.getAreaId()).thenReturn(0); 2263 when(mockCarPropertyValue.getValue()).thenReturn(1.0f); 2264 when(mockPropConfig.getPropId()).thenReturn(VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS); 2265 mPropertyHalService.takeProperties(List.of(mockPropConfig)); 2266 2267 mPropertyHalService.setProperty(mockCarPropertyValue); 2268 2269 HalPropValue value = mPropValueBuilder.build( 2270 VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS, /* areaId= */ 0, /* value= */ 1.0f); 2271 verify(mVehicleHal).set(value); 2272 2273 verifyNoPendingRequest(); 2274 } 2275 2276 @Test testCancelRequests_getCarPropertyValuesAsync()2277 public void testCancelRequests_getCarPropertyValuesAsync() throws Exception { 2278 doReturn(mGetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 2279 List<InvocationOnMock> invocationWrap = new ArrayList<>(); 2280 doAnswer((invocation) -> { 2281 invocationWrap.add(invocation); 2282 return null; 2283 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2284 2285 mPropertyHalService.getCarPropertyValuesAsync(List.of( 2286 GET_PROPERTY_SERVICE_REQUEST_1, GET_PROPERTY_SERVICE_REQUEST_2), 2287 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2288 /* asyncRequestStartTime= */ 0); 2289 2290 assertThat(invocationWrap).hasSize(1); 2291 2292 // Cancel the first request. 2293 mPropertyHalService.cancelRequests(new int[]{REQUEST_ID_1}); 2294 2295 verify(mVehicleHal).cancelRequests(List.of(0)); 2296 2297 // Deliver the results. 2298 deliverOkayGetResult(invocationWrap.get(0)); 2299 2300 // We should only get the result for request 2. 2301 verify(mGetAsyncPropertyResultCallback, timeout(1000)).onGetValueResults( 2302 mAsyncResultCaptor.capture()); 2303 assertThat(mAsyncResultCaptor.getValue().getList().get(0).getRequestId()) 2304 .isEqualTo(REQUEST_ID_2); 2305 2306 verifyNoPendingRequest(); 2307 } 2308 2309 @Test testCancelRequests_setCarPropertyValuesAsync()2310 public void testCancelRequests_setCarPropertyValuesAsync() throws Exception { 2311 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2312 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 2313 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 2314 2315 doAnswer((invocation) -> { 2316 setInvocationWrap.add(invocation); 2317 return null; 2318 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2319 doAnswer((invocation) -> { 2320 getInvocationWrap.add(invocation); 2321 return null; 2322 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2323 2324 mPropertyHalService.setCarPropertyValuesAsync(List.of( 2325 SET_HVAC_REQUEST_ID_1, SET_SPEED_REQUEST_ID_2), 2326 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2327 /* asyncRequestStartTime= */ 0); 2328 2329 assertThat(setInvocationWrap).hasSize(1); 2330 assertThat(getInvocationWrap).hasSize(1); 2331 2332 // Cancel the first request. 2333 mPropertyHalService.cancelRequests(new int[]{REQUEST_ID_1}); 2334 2335 // Note that because both the async set and the get init value request has the same manager 2336 // request ID, so they will all be cancelled. 2337 verify(mVehicleHal, timeout(1000).times(2)).cancelRequests(any()); 2338 2339 // Returns the set value result. 2340 deliverOkaySetResult(setInvocationWrap.get(0)); 2341 // Returns the get initial value result. 2342 deliverOkayGetResult(getInvocationWrap.get(0)); 2343 2344 // We should only get the result for request 2. 2345 verify(mSetAsyncPropertyResultCallback, timeout(1000)).onSetValueResults( 2346 mAsyncResultCaptor.capture()); 2347 assertThat(mAsyncResultCaptor.getValue().getList().get(0).getRequestId()) 2348 .isEqualTo(REQUEST_ID_2); 2349 2350 verifyNoPendingRequest(); 2351 } 2352 2353 @Test testCancelRequests_noPendingRequests()2354 public void testCancelRequests_noPendingRequests() { 2355 mPropertyHalService.cancelRequests(new int[]{0}); 2356 2357 verify(mVehicleHal, never()).cancelRequests(any()); 2358 2359 verifyNoPendingRequest(); 2360 } 2361 2362 // Test that when the client binder died, all pending async requests must be cleared. 2363 @Test testOnBinderDied()2364 public void testOnBinderDied() throws Exception { 2365 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2366 // We return the same binder object for both set and get here. 2367 doReturn(mSetAsyncPropertyResultBinder).when(mGetAsyncPropertyResultCallback).asBinder(); 2368 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 2369 List<InvocationOnMock> getInvocationWrap = new ArrayList<>(); 2370 2371 doAnswer((invocation) -> { 2372 setInvocationWrap.add(invocation); 2373 return null; 2374 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2375 doAnswer((invocation) -> { 2376 getInvocationWrap.add(invocation); 2377 return null; 2378 }).when(mVehicleHal).getAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2379 2380 mPropertyHalService.getCarPropertyValuesAsync(List.of(GET_PROPERTY_SERVICE_REQUEST_1), 2381 mGetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2382 /* asyncRequestStartTime= */ 0); 2383 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_SPEED_REQUEST_ID_2), 2384 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2385 /* asyncRequestStartTime= */ 0); 2386 2387 verify(mSetAsyncPropertyResultBinder).linkToDeath(mDeathRecipientCaptor.capture(), 2388 anyInt()); 2389 2390 assertThat(setInvocationWrap).hasSize(1); 2391 // One is for async get, one is for initial value. 2392 assertThat(getInvocationWrap).hasSize(2); 2393 2394 // Simulate client binder died. 2395 mDeathRecipientCaptor.getValue().binderDied(); 2396 2397 verify(mSetAsyncPropertyResultBinder).unlinkToDeath(any(), anyInt()); 2398 2399 // All async pending requests must be cleared. 2400 verifyNoPendingRequest(); 2401 } 2402 2403 @Test testGetPropertySync()2404 public void testGetPropertySync() throws Exception { 2405 HalPropValue value = mPropValueBuilder.build(INT32_PROP, /* areaId= */ 0, PROPERTY_VALUE); 2406 when(mVehicleHal.get(INT32_PROP, /* areaId= */ 0)).thenReturn(value); 2407 2408 CarPropertyValue carPropValue = mPropertyHalService.getProperty( 2409 INT32_PROP, /* areaId= */ 0); 2410 2411 assertThat(carPropValue.getValue()).isEqualTo(PROPERTY_VALUE); 2412 } 2413 2414 @Test testGetPropertySyncWithCache()2415 public void testGetPropertySyncWithCache() throws Exception { 2416 HalPropValue value = mPropValueBuilder.build(INT32_PROP, /* areaId= */ 0, PROPERTY_VALUE); 2417 when(mVehicleHal.get(INT32_PROP, /* areaId= */ 0)).thenReturn(value); 2418 mPropertyHalService.getProperty(INT32_PROP, /* areaId= */ 0); 2419 reset(mVehicleHal); 2420 2421 CarPropertyValue carPropValue = mPropertyHalService.getProperty( 2422 INT32_PROP, /* areaId= */ 0); 2423 2424 assertWithMessage("CarPropertyValue cached value").that(carPropValue.getValue()) 2425 .isEqualTo(PROPERTY_VALUE); 2426 verify(mVehicleHal, never()).get(anyInt(), anyInt()); 2427 } 2428 2429 @Test testGetPropertySyncErrorPropStatus()2430 public void testGetPropertySyncErrorPropStatus() throws Exception { 2431 HalPropValue value = mPropValueBuilder.build( 2432 AidlVehiclePropValueBuilder.newBuilder(INT32_PROP) 2433 .setStatus(VehiclePropertyStatus.ERROR).addIntValues(0).build()); 2434 when(mVehicleHal.get(INT32_PROP, /* areaId= */ 0)).thenReturn(value); 2435 2436 assertThat(mPropertyHalService.getProperty(INT32_PROP, /*areaId=*/0)).isEqualTo( 2437 new CarPropertyValue<>(INT32_PROP, /*areaId=*/0, 2438 CarPropertyValue.STATUS_ERROR, /*timestampNanos=*/0, Integer.valueOf(0))); 2439 } 2440 2441 @Test testGetPropertySyncUnavailablePropStatus()2442 public void testGetPropertySyncUnavailablePropStatus() throws Exception { 2443 HalPropValue value = mPropValueBuilder.build( 2444 AidlVehiclePropValueBuilder.newBuilder(INT32_PROP) 2445 .setStatus(VehiclePropertyStatus.UNAVAILABLE).addIntValues(0).build()); 2446 when(mVehicleHal.get(INT32_PROP, /* areaId= */ 0)).thenReturn(value); 2447 2448 assertThat(mPropertyHalService.getProperty(INT32_PROP, /*areaId=*/0)).isEqualTo( 2449 new CarPropertyValue<>(INT32_PROP, /*areaId=*/0, 2450 CarPropertyValue.STATUS_UNAVAILABLE, /*timestampNanos=*/0, 2451 Integer.valueOf(0))); 2452 } 2453 2454 @Test testGetPropertySyncInvalidProp()2455 public void testGetPropertySyncInvalidProp() throws Exception { 2456 // This property has no valid int array element. 2457 HalPropValue value = mPropValueBuilder.build( 2458 AidlVehiclePropValueBuilder.newBuilder(INT32_PROP).build()); 2459 when(mVehicleHal.get(INT32_PROP, /* areaId= */ 0)).thenReturn(value); 2460 2461 assertThat(mPropertyHalService.getProperty(INT32_PROP, /*areaId=*/0)).isEqualTo( 2462 new CarPropertyValue<>(INT32_PROP, /*areaId=*/0, 2463 CarPropertyValue.STATUS_ERROR, /*timestampNanos=*/0, Integer.valueOf(0))); 2464 } 2465 2466 @Test testOnPropertySetError()2467 public void testOnPropertySetError() throws Exception { 2468 ArrayList<VehiclePropError> vehiclePropErrors = new ArrayList<>(); 2469 VehiclePropError error1 = new VehiclePropError(); 2470 error1.propId = HVAC_TEMPERATURE_SET; 2471 error1.areaId = 1; 2472 error1.errorCode = STATUS_NOT_AVAILABLE | (0x1234 << 16); 2473 VehiclePropError error2 = new VehiclePropError(); 2474 error2.propId = PERF_VEHICLE_SPEED; 2475 error2.areaId = 0; 2476 error2.errorCode = STATUS_INTERNAL_ERROR; 2477 vehiclePropErrors.add(error1); 2478 vehiclePropErrors.add(error2); 2479 2480 mPropertyHalService.setPropertyHalListener(mPropertyHalListener); 2481 mPropertyHalService.onPropertySetError(vehiclePropErrors); 2482 2483 verify(mPropertyHalListener).onPropertySetError(HVAC_TEMPERATURE_SET, 1, 2484 CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE); 2485 verify(mPropertyHalListener).onPropertySetError(PERF_VEHICLE_SPEED, 0, 2486 CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN); 2487 } 2488 2489 @Test testNoCustomizeVendorPermission()2490 public void testNoCustomizeVendorPermission() throws Exception { 2491 HalPropConfig vendor1Config = mock(HalPropConfig.class); 2492 when(vendor1Config.getPropId()).thenReturn(VENDOR_PROPERTY_1); 2493 when(mVehicleHal.getPropConfig(SUPPORT_CUSTOMIZE_VENDOR_PERMISSION)).thenReturn(null); 2494 2495 mPropertyHalService.takeProperties(List.of(vendor1Config)); 2496 2497 // By default we require PERMISSION_VENDOR_EXTENSION for getting/setting vendor props. 2498 assertThat(mPropertyHalService.getReadPermission(VENDOR_PROPERTY_1)) 2499 .isEqualTo(PERMISSION_VENDOR_EXTENSION); 2500 assertThat(mPropertyHalService.getWritePermission(VENDOR_PROPERTY_1)) 2501 .isEqualTo(PERMISSION_VENDOR_EXTENSION); 2502 } 2503 2504 @Test testCustomizeVendorPermission()2505 public void testCustomizeVendorPermission() throws Exception { 2506 HalPropConfig mockVendorPermConfig = mock(HalPropConfig.class); 2507 // Use the same test config we used in PropertyHalServiceTest. 2508 when(mockVendorPermConfig.getConfigArray()).thenReturn(new int[]{ 2509 VENDOR_PROPERTY_1, 2510 VehicleVendorPermission.PERMISSION_DEFAULT, 2511 VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE, 2512 VENDOR_PROPERTY_2, 2513 VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_ENGINE, 2514 VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_ENGINE, 2515 VENDOR_PROPERTY_3, 2516 VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_INFO, 2517 VehicleVendorPermission.PERMISSION_DEFAULT 2518 }); 2519 when(mVehicleHal.getPropConfig(SUPPORT_CUSTOMIZE_VENDOR_PERMISSION)).thenReturn( 2520 mockVendorPermConfig); 2521 HalPropConfig vendor1Config = mock(HalPropConfig.class); 2522 when(vendor1Config.getPropId()).thenReturn(VENDOR_PROPERTY_1); 2523 HalPropConfig vendor2Config = mock(HalPropConfig.class); 2524 when(vendor2Config.getPropId()).thenReturn(VENDOR_PROPERTY_2); 2525 HalPropConfig vendor3Config = mock(HalPropConfig.class); 2526 when(vendor3Config.getPropId()).thenReturn(VENDOR_PROPERTY_3); 2527 2528 mPropertyHalService.takeProperties(List.of(vendor1Config, vendor2Config, 2529 vendor3Config)); 2530 2531 assertThat(mPropertyHalService.getReadPermission(VENDOR_PROPERTY_1)) 2532 .isEqualTo(PERMISSION_VENDOR_EXTENSION); 2533 assertThat(mPropertyHalService.getWritePermission(VENDOR_PROPERTY_1)).isNull(); 2534 assertThat(mPropertyHalService.getReadPermission(VENDOR_PROPERTY_2)) 2535 .isEqualTo(PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE); 2536 assertThat(mPropertyHalService.getWritePermission(VENDOR_PROPERTY_2)) 2537 .isEqualTo(PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE); 2538 assertThat(mPropertyHalService.getReadPermission(VENDOR_PROPERTY_3)) 2539 .isEqualTo(PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO); 2540 assertThat(mPropertyHalService.getWritePermission(VENDOR_PROPERTY_3)) 2541 .isEqualTo(PERMISSION_VENDOR_EXTENSION); 2542 } 2543 2544 @Test testHalSubscribeOptions_equals()2545 public void testHalSubscribeOptions_equals() { 2546 HalSubscribeOptions options1 = new HalSubscribeOptions(/* halPropId= */ 5, 2547 /* areaIds= */ new int[]{0, 3}, /* updateRateHz= */ 53f); 2548 HalSubscribeOptions options2 = new HalSubscribeOptions(/* halPropId= */ 5, 2549 /* areaIds= */ new int[]{0, 3}, /* updateRateHz= */ 53f); 2550 2551 assertWithMessage("Equal hal subscribe options") 2552 .that(options1.equals(options2)).isTrue(); 2553 } 2554 2555 @Test testHalSubscribeOptions_notEquals()2556 public void testHalSubscribeOptions_notEquals() { 2557 HalSubscribeOptions options1 = new HalSubscribeOptions(/* halPropId= */ 5, 2558 /* areaIds= */ new int[]{0, 3}, /* updateRateHz= */ 55f, 2559 /* enableVariableUpdateRate= */ true); 2560 HalSubscribeOptions options2 = new HalSubscribeOptions(/* halPropId= */ 5, 2561 /* areaIds= */ new int[]{0, 3}, /* updateRateHz= */ 53f, 2562 /* enableVariableUpdateRate= */ true); 2563 2564 assertWithMessage("Non-equal hal subscribe options") 2565 .that(options1.equals(options2)).isFalse(); 2566 } 2567 2568 @Test testHalSubscribeOptions_hashcode()2569 public void testHalSubscribeOptions_hashcode() { 2570 HalSubscribeOptions options1 = new HalSubscribeOptions(/* halPropId= */ 5, 2571 /* areaIds= */ new int[]{0, 3}, /* updateRateHz= */ 53f, 2572 /* enableVariableUpdateRate= */ true); 2573 HalSubscribeOptions options2 = new HalSubscribeOptions(/* halPropId= */ 5, 2574 /* areaIds= */ new int[]{0, 3}, /* updateRateHz= */ 53f, 2575 /* enableVariableUpdateRate= */ true); 2576 2577 assertWithMessage("Hashcode hal subscribe options") 2578 .that(options1.hashCode()).isEqualTo(options2.hashCode()); 2579 } 2580 2581 /** 2582 * This test is for verifying when we need to update sample rate for multiple properties, both 2583 * subscribeProperty and unsubscribeProperty may happen. 2584 */ 2585 @Test testOnHalEvnts_unsubscribeAndUpdateSampleRates()2586 public void testOnHalEvnts_unsubscribeAndUpdateSampleRates() 2587 throws Exception { 2588 List<InvocationOnMock> setInvocationWrap = new ArrayList<>(); 2589 List<HalServiceBase> serviceWrap = new ArrayList<>(); 2590 2591 doAnswer((invocation) -> { 2592 setInvocationWrap.add(invocation); 2593 return null; 2594 }).when(mVehicleHal).setAsync(anyList(), any(VehicleStubCallbackInterface.class)); 2595 doAnswer((invocation) -> { 2596 serviceWrap.add(invocation.getArgument(0)); 2597 return null; 2598 }).when(mVehicleHal).subscribeProperty(any(), anyList()); 2599 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2600 2601 // Subscribe to speed at 40hz. 2602 mPropertyHalService.subscribeProperty(List.of( 2603 createCarSubscriptionOption( 2604 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 2605 /* enableVur= */ true))); 2606 // Issues set async request, which should cause speed to be subscribed at 100hz. 2607 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_HVAC_REQUEST_ID_1), 2608 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2609 /* asyncRequestStartTime= */ 0); 2610 // Issues set async request, which should cause hvac to be subscribed at 0hz. 2611 mPropertyHalService.setCarPropertyValuesAsync(List.of(SET_SPEED_REQUEST_ID_2), 2612 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2613 /* asyncRequestStartTime= */ 0); 2614 2615 // Returns the set value result. 2616 deliverOkaySetResult(setInvocationWrap.get(0)); 2617 deliverOkaySetResult(setInvocationWrap.get(1)); 2618 2619 verify(mVehicleHal, times(3)).subscribeProperty(any(), mListArgumentCaptor.capture()); 2620 // This is caused by subscribeProperty. 2621 assertThat(mListArgumentCaptor.getAllValues().get(0)).containsExactly( 2622 speedHalSubscribeOption(40.0f)); 2623 // This is caused by setCarPropertyValuesAsync. 2624 assertThat(mListArgumentCaptor.getAllValues().get(1)).containsExactly( 2625 hvacHalSubscribeOption()); 2626 // This is caused by setCarPropertyValuesAsync. 2627 assertThat(mListArgumentCaptor.getAllValues().get(2)).containsExactly( 2628 speedHalSubscribeOption(100.0f)); 2629 2630 clearInvocations(mVehicleHal); 2631 2632 // Send change value events for set requests. 2633 serviceWrap.get(0).onHalEvents(List.of(mPropValue, mPropValue2)); 2634 2635 // We no longer need to subscribe to temp. 2636 verify(mVehicleHal).unsubscribeProperty(any(), eq(HVAC_TEMPERATURE_SET)); 2637 // Speed should be subscribed at 40hz. 2638 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 2639 assertThat(mListArgumentCaptor.getAllValues().get(3)).containsExactly( 2640 speedHalSubscribeOption(40.0f)); 2641 2642 verifyNoPendingRequest(); 2643 } 2644 2645 @Test testSubscribeProperty_exceptionFromVhal()2646 public void testSubscribeProperty_exceptionFromVhal() throws Exception { 2647 doThrow(new ServiceSpecificException(0)).when(mVehicleHal).subscribeProperty( 2648 any(), anyList()); 2649 2650 assertThrows(ServiceSpecificException.class, () -> 2651 mPropertyHalService.subscribeProperty(List.of( 2652 createCarSubscriptionOption( 2653 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 2654 /* enableVur= */ true)))); 2655 } 2656 2657 /** 2658 * Tests that if we receive exception from underlying layer, client must be able to retry the 2659 * operation and causes a retry to VHAL. If the error goes away in VHAL, the retry must succeed. 2660 */ 2661 @Test testSubscribeProperty_exceptionFromVhal_retryFixed()2662 public void testSubscribeProperty_exceptionFromVhal_retryFixed() throws Exception { 2663 doThrow(new ServiceSpecificException(0)).when(mVehicleHal).subscribeProperty( 2664 any(), anyList()); 2665 2666 assertThrows(ServiceSpecificException.class, () -> 2667 mPropertyHalService.subscribeProperty(List.of( 2668 createCarSubscriptionOption( 2669 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 2670 /* enableVur= */ true)))); 2671 2672 clearInvocations(mVehicleHal); 2673 // Simulate the error has been fixed. 2674 doNothing().when(mVehicleHal).subscribeProperty(any(), anyList()); 2675 2676 // Retry the operation. 2677 mPropertyHalService.subscribeProperty(List.of( 2678 createCarSubscriptionOption( 2679 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 2680 /* enableVur= */ true))); 2681 2682 // The retry request must go to VehicleHal. 2683 verify(mVehicleHal).subscribeProperty(any(), anyList()); 2684 2685 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED); 2686 2687 verify(mVehicleHal).unsubscribeProperty(any(), eq(PERF_VEHICLE_SPEED)); 2688 2689 verifyNoPendingRequest(); 2690 } 2691 2692 @Test testSubscribeProperty_enableVur()2693 public void testSubscribeProperty_enableVur() throws Exception { 2694 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 2695 2696 mPropertyHalService.subscribeProperty(List.of(createCarSubscriptionOption( 2697 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 2698 /* enableVur= */ true))); 2699 2700 // Subscription rate has to be updated according to client subscription. 2701 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 2702 assertThat(mListArgumentCaptor.getValue()).containsExactly(speedHalSubscribeOption(40f)); 2703 } 2704 2705 @Test testSubscribeProperty_disablesVur()2706 public void testSubscribeProperty_disablesVur() throws Exception { 2707 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 2708 2709 mPropertyHalService.subscribeProperty(List.of(createCarSubscriptionOption( 2710 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 2711 /* enableVur= */ false))); 2712 2713 // Subscription rate has to be updated according to client subscription. 2714 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 2715 assertThat(mListArgumentCaptor.getValue()).containsExactly(new HalSubscribeOptions( 2716 PERF_VEHICLE_SPEED, new int[]{0}, 40.0f, /* enableVariableUpdateRate= */ false)); 2717 } 2718 2719 @Test testSubscribeProperty_withResolution()2720 public void testSubscribeProperty_withResolution() throws Exception { 2721 mListArgumentCaptor = ArgumentCaptor.forClass(List.class); 2722 2723 mPropertyHalService.subscribeProperty(List.of(createCarSubscriptionOption( 2724 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 2725 /* enableVur= */ false, /* resolution */ 1.0f))); 2726 2727 // Subscription rate has to be updated according to client subscription. 2728 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 2729 assertThat(mListArgumentCaptor.getValue()).containsExactly(new HalSubscribeOptions( 2730 PERF_VEHICLE_SPEED, new int[]{0}, 40.0f, /* enableVariableUpdateRate= */ false, 2731 /* resolution */ 1.0f)); 2732 } 2733 2734 @Test testSubscribeProperty_setAsync_clientDisablesVur()2735 public void testSubscribeProperty_setAsync_clientDisablesVur() throws Exception { 2736 doReturn(mSetAsyncPropertyResultBinder).when(mSetAsyncPropertyResultCallback).asBinder(); 2737 AsyncPropertyServiceRequest request = copyRequest(SET_SPEED_REQUEST_ID_2); 2738 request.setUpdateRateHz(20.0f); 2739 2740 mPropertyHalService.setCarPropertyValuesAsync(List.of(request), 2741 mSetAsyncPropertyResultCallback, /* timeoutInMs= */ 1000, 2742 /* asyncRequestStartTime= */ 0); 2743 2744 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 2745 assertThat(mListArgumentCaptor.getValue()).containsExactly(speedHalSubscribeOption(20f)); 2746 clearInvocations(mVehicleHal); 2747 2748 // Client disables Vur. 2749 mPropertyHalService.subscribeProperty(List.of(createCarSubscriptionOption( 2750 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 10.0f, 2751 /* enableVur= */ false))); 2752 2753 // Vur must be turned off. 2754 verify(mVehicleHal).subscribeProperty(any(), mListArgumentCaptor.capture()); 2755 assertThat(mListArgumentCaptor.getValue()).containsExactly(new HalSubscribeOptions( 2756 PERF_VEHICLE_SPEED, new int[]{0}, 20.0f, /* enableVariableUpdateRate= */ false)); 2757 2758 mPropertyHalService.cancelRequests(new int[]{REQUEST_ID_2}); 2759 } 2760 2761 @Test testUnubscribeProperty_exceptionFromVhal()2762 public void testUnubscribeProperty_exceptionFromVhal() throws Exception { 2763 mPropertyHalService.subscribeProperty(List.of( 2764 createCarSubscriptionOption( 2765 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 2766 /* enableVur= */ true))); 2767 doThrow(new ServiceSpecificException(0)).when(mVehicleHal).unsubscribeProperty( 2768 any(), anyInt()); 2769 2770 assertThrows(ServiceSpecificException.class, () -> 2771 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED)); 2772 } 2773 2774 /** 2775 * Tests that if we receive exception from underlying layer, client must be able to retry the 2776 * operation and causes a retry to VHAL. If the error goes away in VHAL, the retry must succeed. 2777 */ 2778 @Test tesUnsubscribeProperty_exceptionFromVhal_retryFixed()2779 public void tesUnsubscribeProperty_exceptionFromVhal_retryFixed() throws Exception { 2780 mPropertyHalService.subscribeProperty(List.of( 2781 createCarSubscriptionOption( 2782 PERF_VEHICLE_SPEED, new int[]{0}, /* updateRateHz= */ 40.0f, 2783 /* enableVur= */ true))); 2784 doThrow(new ServiceSpecificException(0)).when(mVehicleHal).unsubscribeProperty( 2785 any(), anyInt()); 2786 2787 assertThrows(ServiceSpecificException.class, () -> 2788 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED)); 2789 2790 // Simulate the error has been fixed. 2791 clearInvocations(mVehicleHal); 2792 doNothing().when(mVehicleHal).unsubscribeProperty(any(), anyInt()); 2793 2794 mPropertyHalService.unsubscribeProperty(PERF_VEHICLE_SPEED); 2795 2796 // The retry request must go to VehicleHal. 2797 verify(mVehicleHal).unsubscribeProperty(any(), eq(PERF_VEHICLE_SPEED)); 2798 } 2799 2800 /** Creates a {@code CarSubscription} with Vur off. */ 2801 @VisibleForTesting createCarSubscriptionOption(int propertyId, int[] areaId, float updateRateHz)2802 public static CarSubscription createCarSubscriptionOption(int propertyId, 2803 int[] areaId, float updateRateHz) { 2804 return createCarSubscriptionOption(propertyId, areaId, updateRateHz, 2805 /* enableVur= */ false, /*resolution*/ 0.0f); 2806 } 2807 2808 /** Creates a {@code CarSubscription}. */ 2809 @VisibleForTesting createCarSubscriptionOption(int propertyId, int[] areaId, float updateRateHz, boolean enableVur)2810 public static CarSubscription createCarSubscriptionOption(int propertyId, 2811 int[] areaId, float updateRateHz, boolean enableVur) { 2812 return createCarSubscriptionOption(propertyId, areaId, updateRateHz, 2813 enableVur, /*resolution*/ 0.0f); 2814 } 2815 2816 /** Creates a {@code CarSubscription}. */ 2817 @VisibleForTesting createCarSubscriptionOption(int propertyId, int[] areaId, float updateRateHz, boolean enableVur, float resolution)2818 public static CarSubscription createCarSubscriptionOption(int propertyId, 2819 int[] areaId, float updateRateHz, boolean enableVur, float resolution) { 2820 CarSubscription options = new CarSubscription(); 2821 options.propertyId = propertyId; 2822 options.areaIds = areaId; 2823 options.updateRateHz = updateRateHz; 2824 options.enableVariableUpdateRate = enableVur; 2825 options.resolution = resolution; 2826 return options; 2827 } 2828 hvacHalSubscribeOption()2829 private static HalSubscribeOptions hvacHalSubscribeOption() { 2830 return new HalSubscribeOptions(HVAC_TEMPERATURE_SET, new int[]{0}, 0.0f, 2831 /* enableVariableUpdateRate= */ false); 2832 } 2833 speedHalSubscribeOption(float speed)2834 private static HalSubscribeOptions speedHalSubscribeOption(float speed) { 2835 return new HalSubscribeOptions( 2836 PERF_VEHICLE_SPEED, new int[]{0}, speed, /* enableVariableUpdateRate= */ true); 2837 } 2838 } 2839