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