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