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