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.BuildHelper;
21 import android.car.builtin.util.Slogf;
22 import android.hardware.automotive.vehicle.RawPropValues;
23 import android.hardware.automotive.vehicle.SubscribeOptions;
24 import android.os.IBinder.DeathRecipient;
25 import android.os.RemoteException;
26 import android.os.ServiceSpecificException;
27 
28 import com.android.car.hal.HalPropConfig;
29 import com.android.car.hal.HalPropValue;
30 import com.android.car.hal.HalPropValueBuilder;
31 import com.android.car.hal.VehicleHalCallback;
32 import com.android.car.hal.fakevhal.FakeVehicleStub;
33 import com.android.car.internal.property.CarPropertyErrorCodes;
34 import com.android.car.internal.property.CarPropertyErrorCodes.CarPropMgrErrorCode;
35 import com.android.car.internal.property.PropIdAreaId;
36 
37 import java.io.FileDescriptor;
38 import java.util.List;
39 
40 /**
41  * VehicleStub represents an IVehicle service interface in either AIDL or legacy HIDL version. It
42  * exposes common interface so that the client does not need to care about which version the
43  * underlying IVehicle service is in.
44  */
45 public abstract class VehicleStub {
46 
47     /**
48      * SubscriptionClient represents a client that could subscribe/unsubscribe to properties.
49      */
50     public interface SubscriptionClient {
51         /**
52          * Subscribes to a property.
53          *
54          * @param options The list of subscribe options.
55          * @throws RemoteException if the remote operation fails.
56          * @throws ServiceSpecificException if VHAL returns service specific error.
57          */
subscribe(SubscribeOptions[] options)58         void subscribe(SubscribeOptions[] options) throws RemoteException, ServiceSpecificException;
59 
60         /**
61          * Unsubscribes from a property.
62          *
63          * @param prop The ID for the property to unsubscribe.
64          * @throws RemoteException if the remote operation fails.
65          * @throws ServiceSpecificException if VHAL returns service specific error.
66          */
unsubscribe(int prop)67         void unsubscribe(int prop) throws RemoteException, ServiceSpecificException;
68 
69         /**
70          * Registers the callback to be called when the min/max supported value or supportd values
71          * list change for the [propId, areaId]s.
72          *
73          * @throws ServiceSpecificException If VHAL returns error or VHAL connection fails.
74          */
registerSupportedValuesChange(List<PropIdAreaId> propIdAreaIds)75         void registerSupportedValuesChange(List<PropIdAreaId> propIdAreaIds);
76 
77         /**
78          * Unregisters the [propId, areaId]s previously registered with
79          * registerSupportedValuesChange.
80          *
81          * Do nothing if the [propId, areaId]s were not previously registered.
82          *
83          * This operation is always assumed succeeded.
84          */
unregisterSupportedValuesChange(List<PropIdAreaId> propIdAreaIds)85         void unregisterSupportedValuesChange(List<PropIdAreaId> propIdAreaIds);
86     }
87 
88     /**
89      * A request for {@link VehicleStub#getAsync} or {@link VehicleStub#setAsync}.
90      */
91     public static class AsyncGetSetRequest {
92         private final int mServiceRequestId;
93         private final HalPropValue mHalPropValue;
94         private final long mTimeoutUptimeMs;
95 
getServiceRequestId()96         public int getServiceRequestId() {
97             return mServiceRequestId;
98         }
99 
getHalPropValue()100         public HalPropValue getHalPropValue() {
101             return mHalPropValue;
102         }
103 
getTimeoutUptimeMs()104         public long getTimeoutUptimeMs() {
105             return mTimeoutUptimeMs;
106         }
107 
108         /**
109          * Get an instance for AsyncGetSetRequest.
110          */
AsyncGetSetRequest(int serviceRequestId, HalPropValue halPropValue, long timeoutUptimeMs)111         public AsyncGetSetRequest(int serviceRequestId, HalPropValue halPropValue,
112                 long timeoutUptimeMs) {
113             mServiceRequestId = serviceRequestId;
114             mHalPropValue = halPropValue;
115             mTimeoutUptimeMs = timeoutUptimeMs;
116         }
117     }
118 
119     /**
120      * A result for {@link VehicleStub#getAsync}.
121      */
122     public static final class GetVehicleStubAsyncResult {
123         private final int mServiceRequestId;
124         @Nullable
125         private final HalPropValue mHalPropValue;
126         private final CarPropertyErrorCodes mCarPropertyErrorCodes;
127 
getServiceRequestId()128         public int getServiceRequestId() {
129             return mServiceRequestId;
130         }
131 
132         @Nullable
getHalPropValue()133         public HalPropValue getHalPropValue() {
134             return mHalPropValue;
135         }
136 
137         @CarPropMgrErrorCode
getErrorCode()138         public int getErrorCode() {
139             return mCarPropertyErrorCodes.getCarPropertyManagerErrorCode();
140         }
141 
getVendorErrorCode()142         public int getVendorErrorCode() {
143             return mCarPropertyErrorCodes.getVendorErrorCode();
144         }
145 
getSystemErrorCode()146         public int getSystemErrorCode() {
147             return mCarPropertyErrorCodes.getSystemErrorCode();
148         }
149 
getCarPropertyErrorCodes()150         public CarPropertyErrorCodes getCarPropertyErrorCodes() {
151             return mCarPropertyErrorCodes;
152         }
153 
154         /**
155          * Constructs an instance for GetVehicleStubAsyncResult when result returned successfully.
156          */
GetVehicleStubAsyncResult(int serviceRequestId, HalPropValue halPropValue)157         public GetVehicleStubAsyncResult(int serviceRequestId, HalPropValue halPropValue) {
158             mServiceRequestId = serviceRequestId;
159             mHalPropValue = halPropValue;
160             mCarPropertyErrorCodes = CarPropertyErrorCodes.STATUS_OK_NO_ERROR;
161         }
162 
163         /**
164          * Constructs an instance for GetVehicleStubAsyncResult when errors.
165          */
GetVehicleStubAsyncResult(int serviceRequestId, CarPropertyErrorCodes errorCodes)166         public GetVehicleStubAsyncResult(int serviceRequestId, CarPropertyErrorCodes errorCodes) {
167             mServiceRequestId = serviceRequestId;
168             mHalPropValue = null;
169             mCarPropertyErrorCodes = errorCodes;
170         }
171     }
172 
173     /**
174      * A result for {@link VehicleStub#setAsync}.
175      */
176     public static final class SetVehicleStubAsyncResult {
177         private final int mServiceRequestId;
178         @CarPropMgrErrorCode
179         private final CarPropertyErrorCodes mCarPropertyErrorCodes;
180 
getServiceRequestId()181         public int getServiceRequestId() {
182             return mServiceRequestId;
183         }
184 
185         @CarPropMgrErrorCode
getErrorCode()186         public int getErrorCode() {
187             return mCarPropertyErrorCodes.getCarPropertyManagerErrorCode();
188         }
189 
getVendorErrorCode()190         public int getVendorErrorCode() {
191             return mCarPropertyErrorCodes.getVendorErrorCode();
192         }
193 
getSystemErrorCode()194         public int getSystemErrorCode() {
195             return mCarPropertyErrorCodes.getSystemErrorCode();
196         }
197 
getCarPropertyErrorCodes()198         public CarPropertyErrorCodes getCarPropertyErrorCodes() {
199             return mCarPropertyErrorCodes;
200         }
201 
202         /**
203          * Constructs an success result.
204          */
SetVehicleStubAsyncResult(int serviceRequestId)205         public SetVehicleStubAsyncResult(int serviceRequestId) {
206             mServiceRequestId = serviceRequestId;
207             mCarPropertyErrorCodes = CarPropertyErrorCodes.STATUS_OK_NO_ERROR;
208         }
209 
210         /**
211          * Constructs an instance for SetVehicleStubAsyncResult when errors.
212          */
SetVehicleStubAsyncResult(int serviceRequestId, CarPropertyErrorCodes errorCodes)213         public SetVehicleStubAsyncResult(int serviceRequestId, CarPropertyErrorCodes errorCodes) {
214             mServiceRequestId = serviceRequestId;
215             mCarPropertyErrorCodes = errorCodes;
216         }
217     }
218 
219     /**
220      * A callback for asynchronous operations.
221      */
222     public abstract static class VehicleStubCallbackInterface {
223         /**
224          * Method called when {@link getAsync} returns results.
225          */
onGetAsyncResults( List<GetVehicleStubAsyncResult> getVehicleStubAsyncResults)226         public abstract void onGetAsyncResults(
227                 List<GetVehicleStubAsyncResult> getVehicleStubAsyncResults);
228 
229         /**
230          * Method called when {@link setAsync} returns results.
231          */
onSetAsyncResults( List<SetVehicleStubAsyncResult> setVehicleStubAsyncResults)232         public abstract void onSetAsyncResults(
233                 List<SetVehicleStubAsyncResult> setVehicleStubAsyncResults);
234 
235         /**
236          * Register a callback that will be called when the callback binder died.
237          */
linkToDeath(DeathRecipient recipient)238         public abstract void linkToDeath(DeathRecipient recipient) throws RemoteException;
239 
240         /**
241          * Method called when async requests timed-out.
242          *
243          * If the callback's binder is already dead, this function will not be called.
244          */
onRequestsTimeout(List<Integer> serviceRequestIds)245         public abstract void onRequestsTimeout(List<Integer> serviceRequestIds);
246     }
247 
248     /**
249      * Gets a property asynchronously.
250      */
getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests, VehicleStubCallbackInterface getVehicleStubAsyncCallback)251     public abstract void getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests,
252             VehicleStubCallbackInterface getVehicleStubAsyncCallback);
253 
254     /**
255      * Sets a property asynchronously.
256      */
setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests, VehicleStubCallbackInterface setVehicleStubAsyncCallback)257     public abstract void setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests,
258             VehicleStubCallbackInterface setVehicleStubAsyncCallback);
259 
260     /**
261      * Checks whether we are connected to AIDL VHAL: {@code true} or HIDL VHAL: {@code false}.
262      */
isAidlVhal()263     public abstract boolean isAidlVhal();
264 
265     /**
266      * Creates a new VehicleStub to connect to Vehicle HAL.
267      *
268      * Create a new VehicleStub to connect to Vehicle HAL according to which backend (AIDL or HIDL)
269      * is available. This function will throw {@link IllegalStateException} if no vehicle HAL is
270      * available.
271      *
272      * @return a vehicle stub to connect to Vehicle HAL.
273      */
newVehicleStub()274     public static VehicleStub newVehicleStub() throws IllegalStateException {
275         VehicleStub stub = new AidlVehicleStub();
276         if (stub.isValid()) {
277             if ((BuildHelper.isUserDebugBuild() || BuildHelper.isEngBuild())
278                     && FakeVehicleStub.doesEnableFileExist()) {
279                 try {
280                     return new FakeVehicleStub(stub);
281                 } catch (Exception e) {
282                     Slogf.e(CarLog.TAG_SERVICE, e, "Failed to create FakeVehicleStub. "
283                             + "Fallback to using real VehicleStub.");
284                 }
285             }
286             return stub;
287         }
288 
289         Slogf.i(CarLog.TAG_SERVICE, "No AIDL vehicle HAL found, fall back to HIDL version");
290 
291         stub = new HidlVehicleStub();
292 
293         if (!stub.isValid()) {
294             throw new IllegalStateException("Vehicle HAL service is not available.");
295         }
296 
297         return stub;
298     }
299 
300     /**
301      * Gets a HalPropValueBuilder that could be used to build a HalPropValue.
302      *
303      * @return a builder to build HalPropValue.
304      */
getHalPropValueBuilder()305     public abstract HalPropValueBuilder getHalPropValueBuilder();
306 
307     /**
308      * Returns whether this vehicle stub is connecting to a valid vehicle HAL.
309      *
310      * @return Whether this vehicle stub is connecting to a valid vehicle HAL.
311      */
isValid()312     public abstract boolean isValid();
313 
314     /**
315      * Gets the interface descriptor for the connecting vehicle HAL.
316      *
317      * @return the interface descriptor.
318      * @throws IllegalStateException If unable to get the descriptor.
319      */
getInterfaceDescriptor()320     public abstract String getInterfaceDescriptor() throws IllegalStateException;
321 
322     /**
323      * Registers a death recipient that would be called when vehicle HAL died.
324      *
325      * @param recipient A death recipient.
326      * @throws IllegalStateException If unable to register the death recipient.
327      */
linkToDeath(IVehicleDeathRecipient recipient)328     public abstract void linkToDeath(IVehicleDeathRecipient recipient) throws IllegalStateException;
329 
330     /**
331      * Unlinks a previously linked death recipient.
332      *
333      * @param recipient A previously linked death recipient.
334      */
unlinkToDeath(IVehicleDeathRecipient recipient)335     public abstract void unlinkToDeath(IVehicleDeathRecipient recipient);
336 
337     /**
338      * Gets all property configs.
339      *
340      * @return All the property configs.
341      * @throws RemoteException if the remote operation fails.
342      * @throws ServiceSpecificException if VHAL returns service specific error.
343      */
getAllPropConfigs()344     public abstract HalPropConfig[] getAllPropConfigs()
345             throws RemoteException, ServiceSpecificException;
346 
347     /**
348      * Gets a new {@code SubscriptionClient} that could be used to subscribe/unsubscribe.
349      *
350      * Caller MUST unsubscribe all subscribed properties before discarding the client to prevent
351      * resource leak.
352      *
353      * @param callback A callback that could be used to receive events.
354      * @return a {@code SubscriptionClient} that could be used to subscribe/unsubscribe.
355      */
newSubscriptionClient(VehicleHalCallback callback)356     public abstract SubscriptionClient newSubscriptionClient(VehicleHalCallback callback);
357 
358     /**
359      * Gets a property.
360      *
361      * @param requestedPropValue The property to get.
362      * @return The vehicle property value.
363      * @throws RemoteException if the remote operation fails.
364      * @throws ServiceSpecificException if VHAL returns service specific error.
365      */
366     @Nullable
get(HalPropValue requestedPropValue)367     public abstract HalPropValue get(HalPropValue requestedPropValue)
368             throws RemoteException, ServiceSpecificException;
369 
370     /**
371      * Sets a property.
372      *
373      * @param propValue The property to set.
374      * @throws RemoteException if the remote operation fails.
375      * @throws ServiceSpecificException if VHAL returns service specific error.
376      */
set(HalPropValue propValue)377     public abstract void set(HalPropValue propValue)
378             throws RemoteException, ServiceSpecificException;
379 
380     /**
381      * Dumps VHAL debug information.
382      *
383      * Additional arguments could also be provided through {@link args} to debug VHAL.
384      *
385      * @param fd The file descriptor to print output.
386      * @param args Optional additional arguments for the debug command. Can be empty.
387      * @throws RemoteException if the remote operation fails.
388      * @throws ServiceSpecificException if VHAL returns service specific error.
389      */
dump(FileDescriptor fd, List<String> args)390     public abstract void dump(FileDescriptor fd, List<String> args)
391             throws RemoteException, ServiceSpecificException;
392 
393     /**
394      * Checks if fake VHAL is enabled.
395      *
396      * @return {@code true} if a FakeVehicleStub instance is created.
397      */
isFakeModeEnabled()398     public boolean isFakeModeEnabled() {
399         return false;
400     }
401 
402     /**
403      * Cancels all the on-going async requests with the given request IDs.
404      *
405      * @param requestIds a list of async get/set request IDs.
406      */
cancelRequests(List<Integer> requestIds)407     public void cancelRequests(List<Integer> requestIds) {}
408 
409     /**
410      * Whether this VehicleStub supports dynamic supported values API.
411      *
412      * This is only supported on AIDL VHAL >= V4.
413      */
isSupportedValuesImplemented()414     public boolean isSupportedValuesImplemented() {
415         return false;
416     }
417 
MinMaxSupportedRawPropValues( @ullable RawPropValues minValue, @Nullable RawPropValues maxValue)418     public record MinMaxSupportedRawPropValues(
419             @Nullable RawPropValues minValue, @Nullable RawPropValues maxValue) {};
420 
421     /**
422      * Gets the min/max supported value.
423      *
424      * Caller should only call this if {@link #isSupportedValuesImplemented} is {@code true}.
425      *
426      * If no min/max supported value is specified, return an empty structure.
427      *
428      * @throws ServiceSpecificException if the operation fails.
429      */
getMinMaxSupportedValue(int propertyId, int areaId)430     public MinMaxSupportedRawPropValues getMinMaxSupportedValue(int propertyId, int areaId)
431             throws ServiceSpecificException {
432         throw new UnsupportedOperationException();
433     }
434 
435     /**
436      * Gets the supported values list.
437      *
438      * Caller should only call this if {@link #isSupportedValuesImplemented} is {@code true}.
439      *
440      * If no supported values list is specified, return {@code null}.
441      *
442      * @throws ServiceSpecificException if the operation fails.
443      */
getSupportedValuesList(int propertyId, int areaId)444     public @Nullable List<RawPropValues> getSupportedValuesList(int propertyId, int areaId)
445             throws ServiceSpecificException {
446         throw new UnsupportedOperationException();
447     }
448 }
449