1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car; 18 19 import static com.android.car.internal.property.CarPropertyErrorCodes.convertVhalStatusCodeToCarPropertyManagerErrorCodes; 20 21 import android.annotation.Nullable; 22 import android.car.builtin.os.ServiceManagerHelper; 23 import android.car.builtin.os.TraceHelper; 24 import android.car.builtin.util.Slogf; 25 import android.car.hardware.property.CarPropertyManager; 26 import android.car.util.concurrent.AndroidFuture; 27 import android.hardware.automotive.vehicle.GetValueRequest; 28 import android.hardware.automotive.vehicle.GetValueRequests; 29 import android.hardware.automotive.vehicle.GetValueResult; 30 import android.hardware.automotive.vehicle.GetValueResults; 31 import android.hardware.automotive.vehicle.IVehicle; 32 import android.hardware.automotive.vehicle.IVehicleCallback; 33 import android.hardware.automotive.vehicle.SetValueRequest; 34 import android.hardware.automotive.vehicle.SetValueRequests; 35 import android.hardware.automotive.vehicle.SetValueResult; 36 import android.hardware.automotive.vehicle.SetValueResults; 37 import android.hardware.automotive.vehicle.StatusCode; 38 import android.hardware.automotive.vehicle.SubscribeOptions; 39 import android.hardware.automotive.vehicle.VehiclePropConfig; 40 import android.hardware.automotive.vehicle.VehiclePropConfigs; 41 import android.hardware.automotive.vehicle.VehiclePropError; 42 import android.hardware.automotive.vehicle.VehiclePropErrors; 43 import android.hardware.automotive.vehicle.VehiclePropValue; 44 import android.hardware.automotive.vehicle.VehiclePropValues; 45 import android.os.Handler; 46 import android.os.HandlerThread; 47 import android.os.Looper; 48 import android.os.RemoteException; 49 import android.os.ServiceSpecificException; 50 import android.os.Trace; 51 import android.util.ArrayMap; 52 import android.util.ArraySet; 53 import android.util.LongSparseArray; 54 55 import com.android.car.hal.AidlHalPropConfig; 56 import com.android.car.hal.HalPropConfig; 57 import com.android.car.hal.HalPropValue; 58 import com.android.car.hal.HalPropValueBuilder; 59 import com.android.car.hal.VehicleHalCallback; 60 import com.android.car.internal.LargeParcelable; 61 import com.android.car.internal.LongPendingRequestPool; 62 import com.android.car.internal.LongPendingRequestPool.TimeoutCallback; 63 import com.android.car.internal.LongRequestIdWithTimeout; 64 import com.android.car.internal.property.CarPropertyErrorCodes; 65 import com.android.internal.annotations.GuardedBy; 66 import com.android.internal.annotations.VisibleForTesting; 67 import com.android.modules.expresslog.Histogram; 68 69 import java.io.FileDescriptor; 70 import java.util.ArrayList; 71 import java.util.List; 72 import java.util.Map; 73 import java.util.Set; 74 import java.util.concurrent.ExecutionException; 75 import java.util.concurrent.TimeUnit; 76 import java.util.concurrent.TimeoutException; 77 import java.util.concurrent.atomic.AtomicLong; 78 import java.util.function.Function; 79 80 final class AidlVehicleStub extends VehicleStub { 81 private static final Histogram sVehicleHalGetSyncLatencyHistogram = new Histogram( 82 "automotive_os.value_sync_hal_get_property_latency", 83 new Histogram.ScaledRangeOptions(/* binCount= */ 20, /* minValue= */ 0, 84 /* firstBinWidth= */ 2, /* scaleFactor= */ 1.5f)); 85 86 private static final Histogram sVehicleHalSetSyncLatencyHistogram = new Histogram( 87 "automotive_os.value_sync_hal_set_property_latency", 88 new Histogram.ScaledRangeOptions(/* binCount= */ 20, /* minValue= */ 0, 89 /* firstBinWidth= */ 2, /* scaleFactor= */ 1.5f)); 90 91 private static final String AIDL_VHAL_SERVICE = 92 "android.hardware.automotive.vehicle.IVehicle/default"; 93 // default timeout: 10s 94 private static final long DEFAULT_TIMEOUT_MS = 10_000; 95 96 private static final String TAG = CarLog.tagFor(AidlVehicleStub.class); 97 private static final long TRACE_TAG = TraceHelper.TRACE_TAG_CAR_SERVICE; 98 99 private final IVehicle mAidlVehicle; 100 private final HalPropValueBuilder mPropValueBuilder; 101 private final GetSetValuesCallback mGetSetValuesCallback; 102 private final HandlerThread mHandlerThread; 103 private final Handler mHandler; 104 private final AtomicLong mRequestId = new AtomicLong(0); 105 private final Object mLock = new Object(); 106 // PendingSyncRequestPool is thread-safe. 107 private final PendingSyncRequestPool<GetValueResult> mPendingSyncGetValueRequestPool = 108 new PendingSyncRequestPool<>(); 109 private final PendingSyncRequestPool<SetValueResult> mPendingSyncSetValueRequestPool = 110 new PendingSyncRequestPool<>(); 111 // PendingAsyncRequestPool is thread-safe. 112 private final PendingAsyncRequestPool mPendingAsyncRequestPool; 113 114 // This might be modifed during tests. 115 private long mSyncOpTimeoutInMs = DEFAULT_TIMEOUT_MS; 116 117 private static class AsyncRequestInfo implements LongRequestIdWithTimeout { 118 private final int mServiceRequestId; 119 private final VehicleStubCallbackInterface mClientCallback; 120 private final long mTimeoutUptimeMs; 121 private final long mVhalRequestId; 122 AsyncRequestInfo( long vhalRequestId, int serviceRequestId, VehicleStubCallbackInterface clientCallback, long timeoutUptimeMs)123 private AsyncRequestInfo( 124 long vhalRequestId, 125 int serviceRequestId, 126 VehicleStubCallbackInterface clientCallback, 127 long timeoutUptimeMs) { 128 mVhalRequestId = vhalRequestId; 129 mServiceRequestId = serviceRequestId; 130 mClientCallback = clientCallback; 131 mTimeoutUptimeMs = timeoutUptimeMs; 132 } 133 134 @Override getRequestId()135 public long getRequestId() { 136 return mVhalRequestId; 137 } 138 139 @Override getTimeoutUptimeMs()140 public long getTimeoutUptimeMs() { 141 return mTimeoutUptimeMs; 142 } 143 getServiceRequestId()144 public int getServiceRequestId() { 145 return mServiceRequestId; 146 } 147 getClientCallback()148 public VehicleStubCallbackInterface getClientCallback() { 149 return mClientCallback; 150 } 151 } 152 AidlVehicleStub()153 AidlVehicleStub() { 154 this(getAidlVehicle()); 155 } 156 157 @VisibleForTesting AidlVehicleStub(IVehicle aidlVehicle)158 AidlVehicleStub(IVehicle aidlVehicle) { 159 this(aidlVehicle, 160 CarServiceUtils.getHandlerThread(AidlVehicleStub.class.getSimpleName())); 161 } 162 163 @VisibleForTesting AidlVehicleStub(IVehicle aidlVehicle, HandlerThread handlerThread)164 AidlVehicleStub(IVehicle aidlVehicle, HandlerThread handlerThread) { 165 mAidlVehicle = aidlVehicle; 166 mPropValueBuilder = new HalPropValueBuilder(/*isAidl=*/true); 167 mHandlerThread = handlerThread; 168 mHandler = new Handler(mHandlerThread.getLooper()); 169 mGetSetValuesCallback = new GetSetValuesCallback(); 170 mPendingAsyncRequestPool = new PendingAsyncRequestPool(mHandler.getLooper()); 171 } 172 173 /** 174 * Sets the timeout for getValue/setValue requests in milliseconds. 175 */ 176 @VisibleForTesting setSyncOpTimeoutInMs(long timeoutMs)177 void setSyncOpTimeoutInMs(long timeoutMs) { 178 mSyncOpTimeoutInMs = timeoutMs; 179 } 180 181 @VisibleForTesting countPendingRequests()182 int countPendingRequests() { 183 synchronized (mLock) { 184 return mPendingAsyncRequestPool.size() 185 + mPendingSyncGetValueRequestPool.size() 186 + mPendingSyncSetValueRequestPool.size(); 187 } 188 } 189 190 /** 191 * Checks whether we are connected to AIDL VHAL: {@code true} or HIDL VHAL: {@code false}. 192 */ 193 @Override isAidlVhal()194 public boolean isAidlVhal() { 195 return true; 196 } 197 198 /** 199 * Gets a HalPropValueBuilder that could be used to build a HalPropValue. 200 * 201 * @return a builder to build HalPropValue. 202 */ 203 @Override getHalPropValueBuilder()204 public HalPropValueBuilder getHalPropValueBuilder() { 205 return mPropValueBuilder; 206 } 207 208 /** 209 * Returns whether this vehicle stub is connecting to a valid vehicle HAL. 210 * 211 * @return Whether this vehicle stub is connecting to a valid vehicle HAL. 212 */ 213 @Override isValid()214 public boolean isValid() { 215 return mAidlVehicle != null; 216 } 217 218 /** 219 * Gets the interface descriptor for the connecting vehicle HAL. 220 * 221 * @return the interface descriptor. 222 * @throws IllegalStateException If unable to get the descriptor. 223 */ 224 @Override getInterfaceDescriptor()225 public String getInterfaceDescriptor() throws IllegalStateException { 226 try { 227 return mAidlVehicle.asBinder().getInterfaceDescriptor(); 228 } catch (RemoteException e) { 229 throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e); 230 } 231 } 232 233 /** 234 * Registers a death recipient that would be called when vehicle HAL died. 235 * 236 * @param recipient A death recipient. 237 * @throws IllegalStateException If unable to register the death recipient. 238 */ 239 @Override linkToDeath(IVehicleDeathRecipient recipient)240 public void linkToDeath(IVehicleDeathRecipient recipient) throws IllegalStateException { 241 try { 242 mAidlVehicle.asBinder().linkToDeath(recipient, /*flag=*/ 0); 243 } catch (RemoteException e) { 244 throw new IllegalStateException("Failed to linkToDeath Vehicle HAL"); 245 } 246 } 247 248 /** 249 * Unlinks a previously linked death recipient. 250 * 251 * @param recipient A previously linked death recipient. 252 */ 253 @Override unlinkToDeath(IVehicleDeathRecipient recipient)254 public void unlinkToDeath(IVehicleDeathRecipient recipient) { 255 mAidlVehicle.asBinder().unlinkToDeath(recipient, /*flag=*/ 0); 256 } 257 258 /** 259 * Gets all property configs. 260 * 261 * @return All the property configs. 262 * @throws RemoteException if the remote operation fails. 263 * @throws ServiceSpecificException if VHAL returns service specific error. 264 */ 265 @Override getAllPropConfigs()266 public HalPropConfig[] getAllPropConfigs() 267 throws RemoteException, ServiceSpecificException { 268 VehiclePropConfigs propConfigs = (VehiclePropConfigs) 269 LargeParcelable.reconstructStableAIDLParcelable( 270 mAidlVehicle.getAllPropConfigs(), /* keepSharedMemory= */ false); 271 VehiclePropConfig[] payloads = propConfigs.payloads; 272 int size = payloads.length; 273 HalPropConfig[] configs = new HalPropConfig[size]; 274 for (int i = 0; i < size; i++) { 275 configs[i] = new AidlHalPropConfig(payloads[i]); 276 } 277 return configs; 278 } 279 280 /** 281 * Gets a new {@code SubscriptionClient} that could be used to subscribe/unsubscribe. 282 * 283 * @param callback A callback that could be used to receive events. 284 * @return a {@code SubscriptionClient} that could be used to subscribe/unsubscribe. 285 */ 286 @Override newSubscriptionClient(VehicleHalCallback callback)287 public SubscriptionClient newSubscriptionClient(VehicleHalCallback callback) { 288 return new AidlSubscriptionClient(callback, mPropValueBuilder); 289 } 290 291 /** 292 * Gets a property. 293 * 294 * @param requestedPropValue The property to get. 295 * @return The vehicle property value. 296 * @throws RemoteException if the remote operation fails. 297 * @throws ServiceSpecificException if VHAL returns service specific error. 298 */ 299 @Override 300 @Nullable get(HalPropValue requestedPropValue)301 public HalPropValue get(HalPropValue requestedPropValue) 302 throws RemoteException, ServiceSpecificException { 303 long currentTime = System.currentTimeMillis(); 304 HalPropValue halPropValue = getOrSetSync(requestedPropValue, 305 mPendingSyncGetValueRequestPool, new AsyncGetRequestsHandler(), 306 (result) -> { 307 if (result.status != StatusCode.OK) { 308 throw new ServiceSpecificException(result.status, 309 "failed to get value for " + printPropIdAreaId(requestedPropValue)); 310 } 311 if (result.prop == null) { 312 return null; 313 } 314 return mPropValueBuilder.build(result.prop); 315 }); 316 sVehicleHalGetSyncLatencyHistogram.logSample((float) 317 (System.currentTimeMillis() - currentTime)); 318 return halPropValue; 319 } 320 321 /** 322 * Sets a property. 323 * 324 * @param requestedPropValue The property to set. 325 * @throws RemoteException if the remote operation fails. 326 * @throws ServiceSpecificException if VHAL returns service specific error. 327 */ 328 @Override set(HalPropValue requestedPropValue)329 public void set(HalPropValue requestedPropValue) throws RemoteException, 330 ServiceSpecificException { 331 long currentTime = System.currentTimeMillis(); 332 getOrSetSync(requestedPropValue, mPendingSyncSetValueRequestPool, 333 new AsyncSetRequestsHandler(), 334 (result) -> { 335 if (result.status != StatusCode.OK) { 336 throw new ServiceSpecificException(result.status, 337 "failed to set value for " + printPropIdAreaId(requestedPropValue)); 338 } 339 return null; 340 }); 341 sVehicleHalSetSyncLatencyHistogram.logSample((float) 342 (System.currentTimeMillis() - currentTime)); 343 } 344 345 @Override getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests, VehicleStubCallbackInterface getCallback)346 public void getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests, 347 VehicleStubCallbackInterface getCallback) { 348 getOrSetAsync(getVehicleStubAsyncRequests, getCallback, new AsyncGetRequestsHandler(), 349 new AsyncGetResultsHandler(mPropValueBuilder)); 350 } 351 352 @Override setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests, VehicleStubCallbackInterface setCallback)353 public void setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests, 354 VehicleStubCallbackInterface setCallback) { 355 getOrSetAsync(setVehicleStubAsyncRequests, setCallback, new AsyncSetRequestsHandler(), 356 new AsyncSetResultsHandler()); 357 } 358 359 @Override dump(FileDescriptor fd, List<String> args)360 public void dump(FileDescriptor fd, List<String> args) throws RemoteException { 361 mAidlVehicle.asBinder().dump(fd, args.toArray(new String[args.size()])); 362 } 363 364 // Get all the VHAL request IDs according to the service request IDs and remove them from 365 // pending requests map. 366 @Override cancelRequests(List<Integer> serviceRequestIds)367 public void cancelRequests(List<Integer> serviceRequestIds) { 368 mPendingAsyncRequestPool.cancelRequests(serviceRequestIds); 369 } 370 371 /** 372 * A thread-safe pending sync request pool. 373 */ 374 private static final class PendingSyncRequestPool<VhalResultType> { 375 private final Object mSyncRequestPoolLock = new Object(); 376 @GuardedBy("mSyncRequestPoolLock") 377 private final LongSparseArray<AndroidFuture<VhalResultType>> 378 mPendingRequestsByVhalRequestId = new LongSparseArray(); 379 addRequest(long vhalRequestId)380 AndroidFuture<VhalResultType> addRequest(long vhalRequestId) { 381 synchronized (mSyncRequestPoolLock) { 382 AndroidFuture<VhalResultType> resultFuture = new AndroidFuture(); 383 mPendingRequestsByVhalRequestId.put(vhalRequestId, resultFuture); 384 return resultFuture; 385 } 386 } 387 finishRequestIfFound(long vhalRequestId)388 @Nullable AndroidFuture<VhalResultType> finishRequestIfFound(long vhalRequestId) { 389 synchronized (mSyncRequestPoolLock) { 390 AndroidFuture<VhalResultType> pendingRequest = 391 mPendingRequestsByVhalRequestId.get(vhalRequestId); 392 mPendingRequestsByVhalRequestId.remove(vhalRequestId); 393 return pendingRequest; 394 } 395 } 396 size()397 int size() { 398 synchronized (mSyncRequestPoolLock) { 399 return mPendingRequestsByVhalRequestId.size(); 400 } 401 } 402 } 403 404 /** 405 * A thread-safe pending async request pool. 406 */ 407 private static final class PendingAsyncRequestPool { 408 private final Object mAsyncRequestPoolLock = new Object(); 409 private final TimeoutCallback mTimeoutCallback = new AsyncRequestTimeoutCallback(); 410 private final Looper mLooper; 411 @GuardedBy("mAsyncRequestPoolLock") 412 private final LongPendingRequestPool<AsyncRequestInfo> mPendingRequestPool; 413 PendingAsyncRequestPool(Looper looper)414 PendingAsyncRequestPool(Looper looper) { 415 mLooper = looper; 416 mPendingRequestPool = new LongPendingRequestPool<>(mLooper, mTimeoutCallback); 417 } 418 419 private class AsyncRequestTimeoutCallback implements TimeoutCallback { 420 @Override onRequestsTimeout(List<Long> vhalRequestIds)421 public void onRequestsTimeout(List<Long> vhalRequestIds) { 422 ArrayMap<VehicleStubCallbackInterface, List<Integer>> serviceRequestIdsByCallback = 423 new ArrayMap<>(); 424 for (int i = 0; i < vhalRequestIds.size(); i++) { 425 long vhalRequestId = vhalRequestIds.get(i); 426 AsyncRequestInfo requestInfo = finishRequestIfFound(vhalRequestId); 427 if (requestInfo == null) { 428 // We already finished the request or the callback is already dead, ignore. 429 Slogf.w(TAG, "onRequestsTimeout: the request for VHAL request ID: %d is " 430 + "already finished or the callback is already dead, ignore", 431 vhalRequestId); 432 continue; 433 } 434 VehicleStubCallbackInterface getAsyncCallback = requestInfo.getClientCallback(); 435 if (serviceRequestIdsByCallback.get(getAsyncCallback) == null) { 436 serviceRequestIdsByCallback.put(getAsyncCallback, new ArrayList<>()); 437 } 438 serviceRequestIdsByCallback.get(getAsyncCallback).add( 439 requestInfo.getServiceRequestId()); 440 } 441 442 for (int i = 0; i < serviceRequestIdsByCallback.size(); i++) { 443 serviceRequestIdsByCallback.keyAt(i).onRequestsTimeout( 444 serviceRequestIdsByCallback.valueAt(i)); 445 } 446 } 447 } 448 449 addRequests(List<AsyncRequestInfo> requestInfo)450 void addRequests(List<AsyncRequestInfo> requestInfo) { 451 synchronized (mAsyncRequestPoolLock) { 452 mPendingRequestPool.addPendingRequests(requestInfo); 453 } 454 } 455 finishRequestIfFound(long vhalRequestId)456 @Nullable AsyncRequestInfo finishRequestIfFound(long vhalRequestId) { 457 synchronized (mAsyncRequestPoolLock) { 458 AsyncRequestInfo requestInfo = mPendingRequestPool.getRequestIfFound(vhalRequestId); 459 mPendingRequestPool.removeRequest(vhalRequestId); 460 return requestInfo; 461 } 462 } 463 size()464 int size() { 465 synchronized (mAsyncRequestPoolLock) { 466 return mPendingRequestPool.size(); 467 } 468 } 469 contains(long vhalRequestId)470 boolean contains(long vhalRequestId) { 471 synchronized (mAsyncRequestPoolLock) { 472 return mPendingRequestPool.getRequestIfFound(vhalRequestId) != null; 473 } 474 } 475 cancelRequests(List<Integer> serviceRequestIds)476 void cancelRequests(List<Integer> serviceRequestIds) { 477 Set<Integer> serviceRequestIdsSet = new ArraySet<>(serviceRequestIds); 478 List<Long> vhalRequestIdsToCancel = new ArrayList<>(); 479 synchronized (mAsyncRequestPoolLock) { 480 for (int i = 0; i < mPendingRequestPool.size(); i++) { 481 int serviceRequestId = mPendingRequestPool.valueAt(i) 482 .getServiceRequestId(); 483 if (serviceRequestIdsSet.contains(serviceRequestId)) { 484 vhalRequestIdsToCancel.add(mPendingRequestPool.keyAt(i)); 485 } 486 } 487 for (int i = 0; i < vhalRequestIdsToCancel.size(); i++) { 488 long vhalRequestIdToCancel = vhalRequestIdsToCancel.get(i); 489 Slogf.w(TAG, "the request for VHAL request ID: %d is cancelled", 490 vhalRequestIdToCancel); 491 mPendingRequestPool.removeRequest(vhalRequestIdToCancel); 492 } 493 } 494 } 495 removeRequestsForCallback(VehicleStubCallbackInterface callback)496 void removeRequestsForCallback(VehicleStubCallbackInterface callback) { 497 synchronized (mAsyncRequestPoolLock) { 498 List<Long> requestIdsToRemove = new ArrayList<>(); 499 500 for (int i = 0; i < mPendingRequestPool.size(); i++) { 501 if (mPendingRequestPool.valueAt(i).getClientCallback() == callback) { 502 requestIdsToRemove.add(mPendingRequestPool.keyAt(i)); 503 } 504 } 505 506 for (int i = 0; i < requestIdsToRemove.size(); i++) { 507 mPendingRequestPool.removeRequest(requestIdsToRemove.get(i)); 508 } 509 } 510 } 511 } 512 513 /** 514 * An abstract interface for handling async get/set value requests from vehicle stub. 515 */ 516 private abstract static class AsyncRequestsHandler<VhalRequestType, VhalRequestsType> { 517 /** 518 * Preallocsate size array for storing VHAL requests. 519 */ allocateVhalRequestSize(int size)520 abstract void allocateVhalRequestSize(int size); 521 522 /** 523 * Add a vhal request to be sent later. 524 */ addVhalRequest(long vhalRequestId, HalPropValue halPropValue)525 abstract void addVhalRequest(long vhalRequestId, HalPropValue halPropValue); 526 527 /** 528 * Get the list of stored request items. 529 */ getRequestItems()530 abstract VhalRequestType[] getRequestItems(); 531 532 /** 533 * Send the prepared requests to VHAL. 534 */ sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal)535 abstract void sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal) 536 throws RemoteException, ServiceSpecificException; 537 538 /** 539 * Get the request ID for the request. 540 */ getVhalRequestId(VhalRequestType vhalRequest)541 abstract long getVhalRequestId(VhalRequestType vhalRequest); 542 } 543 544 /** 545 * An abstract class to handle async get/set value results from VHAL. 546 */ 547 private abstract static class AsyncResultsHandler<VhalResultType, VehicleStubResultType> { 548 protected Map<VehicleStubCallbackInterface, List<VehicleStubResultType>> mCallbackToResults; 549 550 /** 551 * Add an error result to be sent to vehicleStub through the callback later. 552 */ addErrorResult(VehicleStubCallbackInterface callback, int serviceRequestId, CarPropertyErrorCodes errorCodes)553 abstract void addErrorResult(VehicleStubCallbackInterface callback, int serviceRequestId, 554 CarPropertyErrorCodes errorCodes); 555 /** 556 * Add a VHAL result to be sent to vehicleStub through the callback later. 557 */ addVhalResult(VehicleStubCallbackInterface callback, int serviceRequestId, VhalResultType result)558 abstract void addVhalResult(VehicleStubCallbackInterface callback, int serviceRequestId, 559 VhalResultType result); 560 /** 561 * Send all the stored results to vehicleStub. 562 */ callVehicleStubCallback()563 abstract void callVehicleStubCallback(); 564 565 /** 566 * Get the request ID for the result. 567 */ getVhalRequestId(VhalResultType vhalRequest)568 abstract long getVhalRequestId(VhalResultType vhalRequest); 569 addVehicleStubResult(VehicleStubCallbackInterface callback, VehicleStubResultType vehicleStubResult)570 protected void addVehicleStubResult(VehicleStubCallbackInterface callback, 571 VehicleStubResultType vehicleStubResult) { 572 if (mCallbackToResults.get(callback) == null) { 573 mCallbackToResults.put(callback, new ArrayList<>()); 574 } 575 mCallbackToResults.get(callback).add(vehicleStubResult); 576 } 577 } 578 579 @Nullable getAidlVehicle()580 private static IVehicle getAidlVehicle() { 581 try { 582 return IVehicle.Stub.asInterface( 583 ServiceManagerHelper.waitForDeclaredService(AIDL_VHAL_SERVICE)); 584 } catch (RuntimeException e) { 585 Slogf.w(TAG, "Failed to get \"" + AIDL_VHAL_SERVICE + "\" service", e); 586 } 587 return null; 588 } 589 590 private class AidlSubscriptionClient extends IVehicleCallback.Stub 591 implements SubscriptionClient { 592 private final VehicleHalCallback mCallback; 593 private final HalPropValueBuilder mBuilder; 594 AidlSubscriptionClient(VehicleHalCallback callback, HalPropValueBuilder builder)595 AidlSubscriptionClient(VehicleHalCallback callback, HalPropValueBuilder builder) { 596 mCallback = callback; 597 mBuilder = builder; 598 } 599 600 @Override onGetValues(GetValueResults responses)601 public void onGetValues(GetValueResults responses) throws RemoteException { 602 // We use GetSetValuesCallback for getValues and setValues operation. 603 throw new UnsupportedOperationException( 604 "onGetValues should never be called on AidlSubscriptionClient"); 605 } 606 607 @Override onSetValues(SetValueResults responses)608 public void onSetValues(SetValueResults responses) throws RemoteException { 609 // We use GetSetValuesCallback for getValues and setValues operation. 610 throw new UnsupportedOperationException( 611 "onSetValues should never be called on AidlSubscriptionClient"); 612 } 613 614 @Override onPropertyEvent(VehiclePropValues propValues, int sharedMemoryFileCount)615 public void onPropertyEvent(VehiclePropValues propValues, int sharedMemoryFileCount) 616 throws RemoteException { 617 VehiclePropValues origPropValues = (VehiclePropValues) 618 LargeParcelable.reconstructStableAIDLParcelable(propValues, 619 /* keepSharedMemory= */ false); 620 ArrayList<HalPropValue> values = new ArrayList<>(origPropValues.payloads.length); 621 for (VehiclePropValue value : origPropValues.payloads) { 622 values.add(mBuilder.build(value)); 623 } 624 mCallback.onPropertyEvent(values); 625 } 626 627 @Override onPropertySetError(VehiclePropErrors errors)628 public void onPropertySetError(VehiclePropErrors errors) throws RemoteException { 629 VehiclePropErrors origErrors = (VehiclePropErrors) 630 LargeParcelable.reconstructStableAIDLParcelable(errors, 631 /* keepSharedMemory= */ false); 632 ArrayList<VehiclePropError> errorList = new ArrayList<>(origErrors.payloads.length); 633 for (VehiclePropError error : origErrors.payloads) { 634 errorList.add(error); 635 } 636 mCallback.onPropertySetError(errorList); 637 } 638 639 @Override subscribe(SubscribeOptions[] options)640 public void subscribe(SubscribeOptions[] options) 641 throws RemoteException, ServiceSpecificException { 642 mAidlVehicle.subscribe(this, options, /* maxSharedMemoryFileCount= */ 2); 643 } 644 645 @Override unsubscribe(int prop)646 public void unsubscribe(int prop) throws RemoteException, ServiceSpecificException { 647 mAidlVehicle.unsubscribe(this, new int[]{prop}); 648 } 649 650 @Override getInterfaceHash()651 public String getInterfaceHash() { 652 return IVehicleCallback.HASH; 653 } 654 655 @Override getInterfaceVersion()656 public int getInterfaceVersion() { 657 return IVehicleCallback.VERSION; 658 } 659 } 660 onGetValues(GetValueResults responses)661 private void onGetValues(GetValueResults responses) { 662 Trace.traceBegin(TRACE_TAG, "AidlVehicleStub#onGetValues"); 663 GetValueResults origResponses = (GetValueResults) 664 LargeParcelable.reconstructStableAIDLParcelable(responses, 665 /* keepSharedMemory= */ false); 666 onGetSetValues(origResponses.payloads, new AsyncGetResultsHandler(mPropValueBuilder), 667 mPendingSyncGetValueRequestPool); 668 Trace.traceEnd(TRACE_TAG); 669 } 670 onSetValues(SetValueResults responses)671 private void onSetValues(SetValueResults responses) { 672 Trace.traceBegin(TRACE_TAG, "AidlVehicleStub#onSetValues"); 673 SetValueResults origResponses = (SetValueResults) 674 LargeParcelable.reconstructStableAIDLParcelable(responses, 675 /* keepSharedMemory= */ false); 676 onGetSetValues(origResponses.payloads, new AsyncSetResultsHandler(), 677 mPendingSyncSetValueRequestPool); 678 Trace.traceEnd(TRACE_TAG); 679 } 680 681 /** 682 * A generic function for {@link onGetValues} / {@link onSetValues}. 683 */ onGetSetValues(VhalResultType[] vhalResults, AsyncResultsHandler asyncResultsHandler, PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool)684 private <VhalResultType> void onGetSetValues(VhalResultType[] vhalResults, 685 AsyncResultsHandler asyncResultsHandler, 686 PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool) { 687 synchronized (mLock) { 688 for (VhalResultType result : vhalResults) { 689 long vhalRequestId = asyncResultsHandler.getVhalRequestId(result); 690 if (!mPendingAsyncRequestPool.contains(vhalRequestId)) { 691 // If we cannot find the request Id in the async map, we assume it is for a 692 // sync request. 693 completePendingSyncRequestLocked(pendingSyncRequestPool, vhalRequestId, result); 694 continue; 695 } 696 697 AsyncRequestInfo requestInfo = mPendingAsyncRequestPool.finishRequestIfFound( 698 vhalRequestId); 699 if (requestInfo == null) { 700 Slogf.w(TAG, 701 "No pending request for ID: %s, possibly already timed out, " 702 + "or cancelled, or the client already died", vhalRequestId); 703 continue; 704 } 705 asyncResultsHandler.addVhalResult(requestInfo.getClientCallback(), 706 requestInfo.getServiceRequestId(), result); 707 } 708 } 709 Trace.traceBegin(TRACE_TAG, "AidlVehicleStub call async result callback"); 710 asyncResultsHandler.callVehicleStubCallback(); 711 Trace.traceEnd(TRACE_TAG); 712 } 713 printPropIdAreaId(HalPropValue value)714 private static String printPropIdAreaId(HalPropValue value) { 715 return "propID: " + value.getPropId() + ", areaID: " + value.getAreaId(); 716 } 717 718 private final class GetSetValuesCallback extends IVehicleCallback.Stub { 719 720 @Override onGetValues(GetValueResults responses)721 public void onGetValues(GetValueResults responses) throws RemoteException { 722 AidlVehicleStub.this.onGetValues(responses); 723 } 724 725 @Override onSetValues(SetValueResults responses)726 public void onSetValues(SetValueResults responses) throws RemoteException { 727 AidlVehicleStub.this.onSetValues(responses); 728 } 729 730 @Override onPropertyEvent(VehiclePropValues propValues, int sharedMemoryFileCount)731 public void onPropertyEvent(VehiclePropValues propValues, int sharedMemoryFileCount) 732 throws RemoteException { 733 throw new UnsupportedOperationException( 734 "GetSetValuesCallback only support onGetValues or onSetValues"); 735 } 736 737 @Override onPropertySetError(VehiclePropErrors errors)738 public void onPropertySetError(VehiclePropErrors errors) throws RemoteException { 739 throw new UnsupportedOperationException( 740 "GetSetValuesCallback only support onGetValues or onSetValues"); 741 } 742 743 @Override getInterfaceHash()744 public String getInterfaceHash() { 745 return IVehicleCallback.HASH; 746 } 747 748 @Override getInterfaceVersion()749 public int getInterfaceVersion() { 750 return IVehicleCallback.VERSION; 751 } 752 } 753 754 /** 755 * Mark a pending sync get/set property request as complete and deliver the result. 756 */ 757 @GuardedBy("mLock") completePendingSyncRequestLocked( PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool, long vhalRequestId, VhalResultType result)758 private <VhalResultType> void completePendingSyncRequestLocked( 759 PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool, long vhalRequestId, 760 VhalResultType result) { 761 Trace.traceBegin(TRACE_TAG, "AidlVehicleStub#completePendingSyncRequestLocked"); 762 AndroidFuture<VhalResultType> pendingRequest = 763 pendingSyncRequestPool.finishRequestIfFound(vhalRequestId); 764 if (pendingRequest == null) { 765 Slogf.w(TAG, "No pending request for ID: " + vhalRequestId 766 + ", possibly already timed out"); 767 return; 768 } 769 770 Trace.traceBegin(TRACE_TAG, "AidlVehicleStub#complete pending request"); 771 // This might fail if the request already timed out. 772 pendingRequest.complete(result); 773 Trace.traceEnd(TRACE_TAG); 774 Trace.traceEnd(TRACE_TAG); 775 } 776 777 private static final class AsyncGetRequestsHandler 778 extends AsyncRequestsHandler<GetValueRequest, GetValueRequests> { 779 private GetValueRequest[] mVhalRequestItems; 780 private int mIndex; 781 782 @Override allocateVhalRequestSize(int size)783 public void allocateVhalRequestSize(int size) { 784 mVhalRequestItems = new GetValueRequest[size]; 785 } 786 787 @Override addVhalRequest(long vhalRequestId, HalPropValue halPropValue)788 public void addVhalRequest(long vhalRequestId, HalPropValue halPropValue) { 789 mVhalRequestItems[mIndex] = new GetValueRequest(); 790 mVhalRequestItems[mIndex].requestId = vhalRequestId; 791 mVhalRequestItems[mIndex].prop = (VehiclePropValue) halPropValue.toVehiclePropValue(); 792 mIndex++; 793 } 794 795 @Override getRequestItems()796 public GetValueRequest[] getRequestItems() { 797 return mVhalRequestItems; 798 } 799 800 @Override sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal)801 public void sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal) 802 throws RemoteException, ServiceSpecificException { 803 Trace.traceBegin(TRACE_TAG, "Prepare LargeParcelable"); 804 GetValueRequests largeParcelableRequest = new GetValueRequests(); 805 largeParcelableRequest.payloads = mVhalRequestItems; 806 807 // TODO(b/269669729): Don't try to use large parcelable if the request size is too 808 // small. 809 largeParcelableRequest = (GetValueRequests) LargeParcelable.toLargeParcelable( 810 largeParcelableRequest, () -> { 811 GetValueRequests newRequests = new GetValueRequests(); 812 newRequests.payloads = new GetValueRequest[0]; 813 return newRequests; 814 }); 815 Trace.traceEnd(TRACE_TAG); 816 Trace.traceBegin(TRACE_TAG, "IVehicle#getValues"); 817 iVehicle.getValues(callbackForVhal, largeParcelableRequest); 818 Trace.traceEnd(TRACE_TAG); 819 } 820 821 @Override getVhalRequestId(GetValueRequest request)822 public long getVhalRequestId(GetValueRequest request) { 823 return request.requestId; 824 } 825 } 826 827 private static final class AsyncSetRequestsHandler 828 extends AsyncRequestsHandler<SetValueRequest, SetValueRequests> { 829 private SetValueRequest[] mVhalRequestItems; 830 private int mIndex; 831 832 @Override allocateVhalRequestSize(int size)833 public void allocateVhalRequestSize(int size) { 834 mVhalRequestItems = new SetValueRequest[size]; 835 } 836 837 @Override addVhalRequest(long vhalRequestId, HalPropValue halPropValue)838 public void addVhalRequest(long vhalRequestId, HalPropValue halPropValue) { 839 mVhalRequestItems[mIndex] = new SetValueRequest(); 840 mVhalRequestItems[mIndex].requestId = vhalRequestId; 841 mVhalRequestItems[mIndex].value = (VehiclePropValue) halPropValue.toVehiclePropValue(); 842 mIndex++; 843 } 844 845 @Override getRequestItems()846 public SetValueRequest[] getRequestItems() { 847 return mVhalRequestItems; 848 } 849 850 @Override sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal)851 public void sendRequestsToVhal(IVehicle iVehicle, GetSetValuesCallback callbackForVhal) 852 throws RemoteException, ServiceSpecificException { 853 SetValueRequests largeParcelableRequest = new SetValueRequests(); 854 largeParcelableRequest.payloads = mVhalRequestItems; 855 largeParcelableRequest = (SetValueRequests) LargeParcelable.toLargeParcelable( 856 largeParcelableRequest, () -> { 857 SetValueRequests newRequests = new SetValueRequests(); 858 newRequests.payloads = new SetValueRequest[0]; 859 return newRequests; 860 }); 861 iVehicle.setValues(callbackForVhal, largeParcelableRequest); 862 } 863 864 @Override getVhalRequestId(SetValueRequest request)865 public long getVhalRequestId(SetValueRequest request) { 866 return request.requestId; 867 } 868 } 869 870 private static final class AsyncGetResultsHandler extends 871 AsyncResultsHandler<GetValueResult, GetVehicleStubAsyncResult> { 872 private HalPropValueBuilder mPropValueBuilder; 873 AsyncGetResultsHandler(HalPropValueBuilder propValueBuilder)874 AsyncGetResultsHandler(HalPropValueBuilder propValueBuilder) { 875 mPropValueBuilder = propValueBuilder; 876 mCallbackToResults = new ArrayMap<VehicleStubCallbackInterface, 877 List<GetVehicleStubAsyncResult>>(); 878 } 879 880 @Override addErrorResult(VehicleStubCallbackInterface callback, int serviceRequestId, CarPropertyErrorCodes errorCodes)881 void addErrorResult(VehicleStubCallbackInterface callback, int serviceRequestId, 882 CarPropertyErrorCodes errorCodes) { 883 addVehicleStubResult(callback, new GetVehicleStubAsyncResult(serviceRequestId, 884 errorCodes)); 885 } 886 887 @Override addVhalResult(VehicleStubCallbackInterface callback, int serviceRequestId, GetValueResult result)888 void addVhalResult(VehicleStubCallbackInterface callback, int serviceRequestId, 889 GetValueResult result) { 890 addVehicleStubResult(callback, toVehicleStubResult(serviceRequestId, result)); 891 } 892 893 @Override callVehicleStubCallback()894 void callVehicleStubCallback() { 895 for (Map.Entry<VehicleStubCallbackInterface, List<GetVehicleStubAsyncResult>> entry : 896 mCallbackToResults.entrySet()) { 897 entry.getKey().onGetAsyncResults(entry.getValue()); 898 } 899 } 900 901 @Override getVhalRequestId(GetValueResult result)902 long getVhalRequestId(GetValueResult result) { 903 return result.requestId; 904 } 905 toVehicleStubResult(int serviceRequestId, GetValueResult vhalResult)906 private GetVehicleStubAsyncResult toVehicleStubResult(int serviceRequestId, 907 GetValueResult vhalResult) { 908 if (vhalResult.status != StatusCode.OK) { 909 CarPropertyErrorCodes carPropertyErrorCodes = 910 convertVhalStatusCodeToCarPropertyManagerErrorCodes(vhalResult.status); 911 return new GetVehicleStubAsyncResult(serviceRequestId, carPropertyErrorCodes); 912 } else if (vhalResult.prop == null) { 913 // If status is OKAY but no property is returned, treat it as not_available. 914 return new GetVehicleStubAsyncResult(serviceRequestId, 915 new CarPropertyErrorCodes( 916 CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE, 917 /* vendorErrorCode= */ 0, 918 /* systemErrorCode= */ 0)); 919 } 920 return new GetVehicleStubAsyncResult(serviceRequestId, 921 mPropValueBuilder.build(vhalResult.prop)); 922 } 923 } 924 925 private static final class AsyncSetResultsHandler extends 926 AsyncResultsHandler<SetValueResult, SetVehicleStubAsyncResult> { AsyncSetResultsHandler()927 AsyncSetResultsHandler() { 928 mCallbackToResults = new ArrayMap<VehicleStubCallbackInterface, 929 List<SetVehicleStubAsyncResult>>(); 930 } 931 932 @Override addErrorResult(VehicleStubCallbackInterface callback, int serviceRequestId, CarPropertyErrorCodes errorCodes)933 void addErrorResult(VehicleStubCallbackInterface callback, int serviceRequestId, 934 CarPropertyErrorCodes errorCodes) { 935 addVehicleStubResult(callback, 936 new SetVehicleStubAsyncResult(serviceRequestId, errorCodes)); 937 } 938 939 @Override addVhalResult(VehicleStubCallbackInterface callback, int serviceRequestId, SetValueResult result)940 void addVhalResult(VehicleStubCallbackInterface callback, int serviceRequestId, 941 SetValueResult result) { 942 addVehicleStubResult(callback, toVehicleStubResult(serviceRequestId, result)); 943 944 } 945 946 @Override callVehicleStubCallback()947 void callVehicleStubCallback() { 948 for (Map.Entry<VehicleStubCallbackInterface, List<SetVehicleStubAsyncResult>> entry : 949 mCallbackToResults.entrySet()) { 950 entry.getKey().onSetAsyncResults(entry.getValue()); 951 } 952 } 953 954 @Override getVhalRequestId(SetValueResult result)955 long getVhalRequestId(SetValueResult result) { 956 return result.requestId; 957 } 958 toVehicleStubResult(int serviceRequestId, SetValueResult vhalResult)959 private SetVehicleStubAsyncResult toVehicleStubResult(int serviceRequestId, 960 SetValueResult vhalResult) { 961 if (vhalResult.status != StatusCode.OK) { 962 CarPropertyErrorCodes carPropertyErrorCodes = 963 convertVhalStatusCodeToCarPropertyManagerErrorCodes(vhalResult.status); 964 return new SetVehicleStubAsyncResult(serviceRequestId, carPropertyErrorCodes); 965 } 966 return new SetVehicleStubAsyncResult(serviceRequestId); 967 } 968 } 969 970 /** 971 * Generic function for {@link get} or {@link set}. 972 */ getOrSetSync( HalPropValue requestedPropValue, PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool, AsyncRequestsHandler requestsHandler, Function<VhalResultType, HalPropValue> resultHandler)973 private <VhalResultType> HalPropValue getOrSetSync( 974 HalPropValue requestedPropValue, 975 PendingSyncRequestPool<VhalResultType> pendingSyncRequestPool, 976 AsyncRequestsHandler requestsHandler, 977 Function<VhalResultType, HalPropValue> resultHandler) 978 throws RemoteException, ServiceSpecificException { 979 Trace.traceBegin(TRACE_TAG, "AidlVehicleStub#getOrSetSync"); 980 long vhalRequestId = mRequestId.getAndIncrement(); 981 982 AndroidFuture<VhalResultType> resultFuture = pendingSyncRequestPool.addRequest( 983 vhalRequestId); 984 985 requestsHandler.allocateVhalRequestSize(1); 986 requestsHandler.addVhalRequest(vhalRequestId, requestedPropValue); 987 requestsHandler.sendRequestsToVhal(mAidlVehicle, mGetSetValuesCallback); 988 989 boolean gotResult = false; 990 991 try { 992 Trace.traceBegin(TRACE_TAG, "AidlVehicleStub#waitingForSyncResult"); 993 VhalResultType result = resultFuture.get(mSyncOpTimeoutInMs, 994 TimeUnit.MILLISECONDS); 995 gotResult = true; 996 return resultHandler.apply(result); 997 } catch (InterruptedException e) { 998 Thread.currentThread().interrupt(); // Restore the interrupted status 999 throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR, 1000 "thread interrupted, possibly exiting the thread"); 1001 } catch (ExecutionException e) { 1002 throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR, 1003 "failed to resolve future, error: " + e); 1004 } catch (TimeoutException e) { 1005 throw new ServiceSpecificException(StatusCode.INTERNAL_ERROR, 1006 "get/set value request timeout for: " + printPropIdAreaId(requestedPropValue)); 1007 } finally { 1008 Trace.traceEnd(TRACE_TAG); 1009 if (!gotResult) { 1010 resultFuture = pendingSyncRequestPool.finishRequestIfFound(vhalRequestId); 1011 // Something wrong happened, the future is guaranteed not to be used again. 1012 resultFuture.cancel(/* mayInterruptIfRunning= */ false); 1013 } 1014 Trace.traceEnd(TRACE_TAG); 1015 } 1016 } 1017 1018 /** 1019 * Generic function for {@link getAsync} or {@link setAsync}. 1020 */ getOrSetAsync( List<AsyncGetSetRequest> vehicleStubAsyncRequests, VehicleStubCallbackInterface vehicleStubCallback, AsyncRequestsHandler<VhalRequestType, VhalRequestsType> asyncRequestsHandler, AsyncResultsHandler asyncResultsHandler)1021 private <VhalRequestType, VhalRequestsType> void getOrSetAsync( 1022 List<AsyncGetSetRequest> vehicleStubAsyncRequests, 1023 VehicleStubCallbackInterface vehicleStubCallback, 1024 AsyncRequestsHandler<VhalRequestType, VhalRequestsType> asyncRequestsHandler, 1025 AsyncResultsHandler asyncResultsHandler) { 1026 prepareAndConvertAsyncRequests(vehicleStubAsyncRequests, vehicleStubCallback, 1027 asyncRequestsHandler); 1028 1029 try { 1030 asyncRequestsHandler.sendRequestsToVhal(mAidlVehicle, mGetSetValuesCallback); 1031 } catch (RemoteException e) { 1032 handleAsyncExceptionFromVhal( 1033 asyncRequestsHandler, 1034 vehicleStubCallback, 1035 new CarPropertyErrorCodes( 1036 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR, 1037 /* vendorErrorCode= */ 0, 1038 /* systemErrorCode= */ 0), 1039 asyncResultsHandler); 1040 return; 1041 } catch (ServiceSpecificException e) { 1042 CarPropertyErrorCodes carPropertyErrorCodes = 1043 convertVhalStatusCodeToCarPropertyManagerErrorCodes(e.errorCode); 1044 handleAsyncExceptionFromVhal(asyncRequestsHandler, vehicleStubCallback, 1045 carPropertyErrorCodes, asyncResultsHandler); 1046 return; 1047 } 1048 } 1049 1050 /** 1051 * Prepare an async get/set request from client and convert it to vhal requests. 1052 * 1053 * <p> It does the following things: 1054 * <ul> 1055 * <li> Add a client callback death listener which will clear the pending requests when client 1056 * died 1057 * <li> Store the async requests to a pending request map. 1058 * <li> For each client request, generate a unique VHAL request ID and convert the request to 1059 * VHAL request type. 1060 * <li> Stores the time-out information for each request into a map so that we can register 1061 * timeout handlers later. 1062 * <li> Convert the vhal request items to a single large parcelable class. 1063 */ prepareAndConvertAsyncRequests( List<AsyncGetSetRequest> vehicleStubRequests, VehicleStubCallbackInterface clientCallback, AsyncRequestsHandler<VhalRequestType, VhalRequestsType> asyncRequestsHandler)1064 private <VhalRequestType, VhalRequestsType> void prepareAndConvertAsyncRequests( 1065 List<AsyncGetSetRequest> vehicleStubRequests, 1066 VehicleStubCallbackInterface clientCallback, 1067 AsyncRequestsHandler<VhalRequestType, VhalRequestsType> asyncRequestsHandler) { 1068 asyncRequestsHandler.allocateVhalRequestSize(vehicleStubRequests.size()); 1069 synchronized (mLock) { 1070 // Add the death recipient so that all client info for a dead callback will be cleaned 1071 // up. Note that this must be in the same critical section as the following code to 1072 // store the client info into the map. This makes sure that even if the client is 1073 // died half way while adding the client info, it will wait until all the clients are 1074 // added and then remove them all. 1075 try { 1076 clientCallback.linkToDeath(() -> { 1077 // This function will be invoked from a different thread. It needs to be 1078 // guarded by a lock so that the whole 'prepareAndConvertAsyncRequests' finishes 1079 // before we remove the callback. 1080 synchronized (mLock) { 1081 mPendingAsyncRequestPool.removeRequestsForCallback(clientCallback); 1082 } 1083 }); 1084 } catch (RemoteException e) { 1085 // The binder is already died. 1086 throw new IllegalStateException("Failed to link callback to death recipient, the " 1087 + "client maybe already died"); 1088 } 1089 1090 List<AsyncRequestInfo> requestInfoList = new ArrayList<>(); 1091 for (int i = 0; i < vehicleStubRequests.size(); i++) { 1092 AsyncGetSetRequest vehicleStubRequest = vehicleStubRequests.get(i); 1093 long vhalRequestId = mRequestId.getAndIncrement(); 1094 asyncRequestsHandler.addVhalRequest(vhalRequestId, 1095 vehicleStubRequest.getHalPropValue()); 1096 requestInfoList.add(new AsyncRequestInfo( 1097 vhalRequestId, vehicleStubRequest.getServiceRequestId(), clientCallback, 1098 vehicleStubRequest.getTimeoutUptimeMs())); 1099 } 1100 mPendingAsyncRequestPool.addRequests(requestInfoList); 1101 } 1102 1103 } 1104 1105 /** 1106 * Callback to deliver async get/set error results back to the client. 1107 * 1108 * <p>When an exception is received, the callback delivers the error results on the same thread 1109 * where the caller is. 1110 */ handleAsyncExceptionFromVhal( AsyncRequestsHandler<VhalRequestType, VhalRequestsType> asyncRequestsHandler, VehicleStubCallbackInterface vehicleStubCallback, CarPropertyErrorCodes errorCodes, AsyncResultsHandler asyncResultsHandler)1111 private <VhalRequestType, VhalRequestsType> void handleAsyncExceptionFromVhal( 1112 AsyncRequestsHandler<VhalRequestType, VhalRequestsType> asyncRequestsHandler, 1113 VehicleStubCallbackInterface vehicleStubCallback, CarPropertyErrorCodes errorCodes, 1114 AsyncResultsHandler asyncResultsHandler) { 1115 Slogf.w(TAG, 1116 "Received RemoteException or ServiceSpecificException from VHAL. VHAL is likely " 1117 + "dead, system error code: %d, vendor error code: %d", 1118 errorCodes.getCarPropertyManagerErrorCode(), errorCodes.getVendorErrorCode()); 1119 synchronized (mLock) { 1120 VhalRequestType[] requests = asyncRequestsHandler.getRequestItems(); 1121 for (int i = 0; i < requests.length; i++) { 1122 long vhalRequestId = asyncRequestsHandler.getVhalRequestId(requests[i]); 1123 AsyncRequestInfo requestInfo = mPendingAsyncRequestPool.finishRequestIfFound( 1124 vhalRequestId); 1125 if (requestInfo == null) { 1126 Slogf.w(TAG, 1127 "No pending request for ID: %s, possibly already timed out or " 1128 + "the client already died", vhalRequestId); 1129 continue; 1130 } 1131 asyncResultsHandler.addErrorResult( 1132 vehicleStubCallback, requestInfo.getServiceRequestId(), errorCodes); 1133 } 1134 } 1135 asyncResultsHandler.callVehicleStubCallback(); 1136 } 1137 1138 } 1139