• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022, 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 #ifndef CPP_VHAL_CLIENT_INCLUDE_IVHALCLIENT_H_
18 #define CPP_VHAL_CLIENT_INCLUDE_IVHALCLIENT_H_
19 
20 #include "IHalPropConfig.h"
21 #include "IHalPropValue.h"
22 
23 #include <aidl/android/hardware/automotive/vehicle/MinMaxSupportedValueResult.h>
24 #include <aidl/android/hardware/automotive/vehicle/PropIdAreaId.h>
25 #include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
26 #include <aidl/android/hardware/automotive/vehicle/SubscribeOptions.h>
27 #include <android-base/result.h>
28 #include <android-base/strings.h>
29 #include <android-base/thread_annotations.h>
30 
31 #include <VehicleUtils.h>
32 
33 #include <unordered_set>
34 
35 namespace android {
36 namespace frameworks {
37 namespace automotive {
38 namespace vhal {
39 
40 struct HalPropError {
41     int32_t propId;
42     int32_t areaId;
43     aidl::android::hardware::automotive::vehicle::StatusCode status;
44 };
45 
46 // ISubscriptionCallback is a general interface to delivery property events caused by subscription.
47 class ISubscriptionCallback {
48 public:
49     virtual ~ISubscriptionCallback() = default;
50     /**
51      * Called when new property events happen.
52      */
53     virtual void onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>>& values) = 0;
54 
55     /**
56      * Called when property set errors happen.
57      */
58     virtual void onPropertySetError(const std::vector<HalPropError>& errors) = 0;
59 };
60 
61 // Errors for vehicle HAL client interface.
62 enum class ErrorCode : int {
63     // Response status is OK. No errors.
64     OK = 0,
65     // The argument is invalid.
66     INVALID_ARG = 1,
67     // The request timed out. The client may try again.
68     TIMEOUT = 2,
69     // Some errors occur while connecting VHAL. The client may try again.
70     TRANSACTION_ERROR = 3,
71     // Some unexpected errors happen in VHAL. Needs to try again.
72     TRY_AGAIN_FROM_VHAL = 4,
73     // The device of corresponding vehicle property is not available.
74     // Example: the HVAC unit is turned OFF when user wants to adjust temperature.
75     NOT_AVAILABLE_FROM_VHAL = 5,
76     // The request is unauthorized.
77     ACCESS_DENIED_FROM_VHAL = 6,
78     // Some unexpected errors, for example OOM, happen in VHAL.
79     INTERNAL_ERROR_FROM_VHAL = 7,
80     // The operation is not supported for the current VHAL.
81     NOT_SUPPORTED = 8,
82 };
83 
84 // Convert the VHAL {@code StatusCode} to {@code ErrorCode}.
statusCodeToErrorCode(const aidl::android::hardware::automotive::vehicle::StatusCode & code)85 static ErrorCode statusCodeToErrorCode(
86         const aidl::android::hardware::automotive::vehicle::StatusCode& code) {
87     switch (code) {
88         case aidl::android::hardware::automotive::vehicle::StatusCode::OK:
89             return ErrorCode::OK;
90         case aidl::android::hardware::automotive::vehicle::StatusCode::TRY_AGAIN:
91             return ErrorCode::TRY_AGAIN_FROM_VHAL;
92         case aidl::android::hardware::automotive::vehicle::StatusCode::INVALID_ARG:
93             return ErrorCode::INVALID_ARG;
94         case aidl::android::hardware::automotive::vehicle::StatusCode::NOT_AVAILABLE:
95             return ErrorCode::NOT_AVAILABLE_FROM_VHAL;
96         case aidl::android::hardware::automotive::vehicle::StatusCode::ACCESS_DENIED:
97             return ErrorCode::ACCESS_DENIED_FROM_VHAL;
98         case aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR:
99             return ErrorCode::INTERNAL_ERROR_FROM_VHAL;
100         default:
101             return ErrorCode::INTERNAL_ERROR_FROM_VHAL;
102     }
103 }
104 
105 // VhalClientError is a wrapper class for {@code ErrorCode} that could act as E in {@code
106 // Result<T,E>}.
107 class VhalClientError final {
108 public:
VhalClientError()109     VhalClientError() : mCode(ErrorCode::OK) {}
110 
VhalClientError(ErrorCode && code)111     VhalClientError(ErrorCode&& code) : mCode(code) {}
112 
VhalClientError(const ErrorCode & code)113     VhalClientError(const ErrorCode& code) : mCode(code) {}
114 
VhalClientError(aidl::android::hardware::automotive::vehicle::StatusCode && code)115     VhalClientError(aidl::android::hardware::automotive::vehicle::StatusCode&& code) :
116           mCode(statusCodeToErrorCode(code)) {}
117 
VhalClientError(const aidl::android::hardware::automotive::vehicle::StatusCode & code)118     VhalClientError(const aidl::android::hardware::automotive::vehicle::StatusCode& code) :
119           mCode(statusCodeToErrorCode(code)) {}
120 
121     ErrorCode value() const;
122 
ErrorCode()123     inline operator ErrorCode() const { return value(); }
124 
125     static std::string toString(ErrorCode code);
126 
127     std::string print() const;
128 
129 private:
130     ErrorCode mCode;
131 };
132 
133 // VhalClientResult is a {@code Result} that contains {@code ErrorCode} as error type.
134 template <class T>
135 using VhalClientResult = android::base::Result<T, VhalClientError>;
136 
137 // ClientStatusError could be cast to {@code ResultError} with a {@code ErrorCode}
138 // and should be used as error type for {@VhalClientResult}.
139 using ClientStatusError = android::base::Error<VhalClientError>;
140 
141 // ISubscriptionCallback is a client that could be used to subscribe/unsubscribe.
142 //
143 // Before destroying this client instance, client must call unsubscribeAll, otherwise, the
144 // subscribed properties will still be subscribed and the callback will be kept alive until
145 // the process ends.
146 class ISubscriptionClient {
147 public:
148     virtual ~ISubscriptionClient() = default;
149 
150     // Subscribes to properties. It is recommended to use SubscribeOptionsBuilder to build
151     // the options.
152     virtual VhalClientResult<void> subscribe(
153             const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
154                     options) = 0;
155 
156     virtual VhalClientResult<void> unsubscribe(const std::vector<int32_t>& propIds) = 0;
157 
158     virtual void unsubscribeAll() = 0;
159 };
160 
161 class SubscribeOptionsBuilder {
162 private:
163     int32_t mPropId;
164     std::vector<int32_t> mAreaIds;
165     float mSampleRate = 0;
166     float mResolution = 0.0f;
167     // VUR is on by default.
168     bool mEnableVariableUpdateRate = true;
169 
170 public:
SubscribeOptionsBuilder(int32_t propId)171     explicit SubscribeOptionsBuilder(int32_t propId) : mPropId(propId) {}
172 
173     // Sets the sample rate.
setSampleRate(float sampleRate)174     void setSampleRate(float sampleRate) { mSampleRate = sampleRate; }
175 
176     // Adds an area ID to subscribe.
177     //
178     // Only supported for AIDL VHAL client.
179     //
180     // For HIDL VHAL client, per-area ID subscription is not supported, this is ignored and all
181     // area IDs for the property will be subscribed.
addAreaId(int32_t areaId)182     void addAreaId(int32_t areaId) { mAreaIds.push_back(areaId); }
183 
184     // Sets the resolution of property updates for continuous property.
185     //
186     // Only supported for continuous property. Ignored for non-cotinuous property.
187     //
188     // Only supported for AIDL VHAL client. Ignored for HIDL VHAL client.
189     //
190     // This value indicates the resolution at which continuous property updates should be sent to
191     // the platform. For example, if resolution is 0.01, the subscribed property value should be
192     // rounded to two decimal places.
193     //
194     // The resolution must be an integer power of 10, (e.g. 0.01, 0.1, 1, 10, etc.).
setResolution(float resolution)195     void setResolution(float resolution) { mResolution = resolution; }
196 
197     // Sets whether to enable varialbe update rate.
198     //
199     // Only supported for continuous property. Ignored for non-cotinuous property.
200     //
201     // Only supported for AIDL VHAL client. Ignored for HIDL VHAL client.
202     //
203     // If variable update rate is enabled, for each given areaId, if VHAL supports variable update
204     // rate for the [propId, areaId], VHAL must ignore duplicate property value events
205     // and only sends changed value events (a.k.a treat continuous as an on-change property).
setEnableVariableUpdateRate(bool enableVariableUpdateRate)206     void setEnableVariableUpdateRate(bool enableVariableUpdateRate) {
207         mEnableVariableUpdateRate = enableVariableUpdateRate;
208     }
209 
210     // Builds the SubscribeOptions.
build()211     aidl::android::hardware::automotive::vehicle::SubscribeOptions build() {
212         return {
213                 .propId = mPropId,
214                 .areaIds = mAreaIds,
215                 .sampleRate = mSampleRate,
216                 .resolution = mResolution,
217                 .enableVariableUpdateRate = mEnableVariableUpdateRate,
218         };
219     }
220 };
221 
222 // IVhalClient is a thread-safe client for AIDL or HIDL VHAL backend.
223 class IVhalClient {
224 public:
225     [[deprecated("Use create(startThreadPool) instead")]]
create()226     static std::shared_ptr<IVhalClient> create() {
227         return create(/*startThreadPool=*/true);
228     }
229 
230     // Waits for VHAL service and create a client. Return nullptr if failed to connect to VHAL.
231     //
232     // This waits for a certain short time period determined by the system. It is recommended to
233     // use tryCreate if you do not want to block.
234     //
235     // startThreadPool indicates whether the IVhalClient will create a binder thread pool for
236     // receiving callbacks. It is recommended to call ABinderProcess_startThreadPool only once from
237     // the app's main function and then call this method with startThreadPool as false.
238     static std::shared_ptr<IVhalClient> create(bool startThreadPool);
239 
240     [[deprecated("Use tryCreate(startThreadPool) instead")]]
tryCreate()241     static std::shared_ptr<IVhalClient> tryCreate() {
242         return tryCreate(/*startThreadPool=*/true);
243     }
244 
245     // Tries to get the VHAL service and create a client. Return nullptr if failed to connect to
246     // VHAL.
247     //
248     // This function does not block and returns immediately. It is possible that VHAL is still
249     // starting up so the client should typically retry if failed to connect to VHAL.
250     //
251     // startThreadPool indicates whether the IVhalClient will create a binder thread pool for
252     // receiving callbacks. It is recommended to call ABinderProcess_startThreadPool only once from
253     // the app's main function and then call this method with startThreadPool as false.
254     static std::shared_ptr<IVhalClient> tryCreate(bool startThreadPool);
255 
256     [[deprecated("Use tryCreateAidlClient(descriptor, startThreadPool) instead")]]
tryCreateAidlClient(const char * descriptor)257     static std::shared_ptr<IVhalClient> tryCreateAidlClient(const char* descriptor) {
258         return tryCreateAidlClient(descriptor, /*startThreadPool=*/true);
259     }
260 
261     // Tries to create a client based on the AIDL VHAL service descriptor.
262     //
263     // startThreadPool indicates whether the IVhalClient will create a binder thread pool for
264     // receiving callbacks. It is recommended to call ABinderProcess_startThreadPool only once from
265     // the app's main function and then call this method with startThreadPool as false.
266     static std::shared_ptr<IVhalClient> tryCreateAidlClient(const char* descriptor,
267                                                             bool startThreadPool);
268 
269     // Tries to create a client based on the HIDL VHAL service descriptor.
270     static std::shared_ptr<IVhalClient> tryCreateHidlClient(const char* descriptor);
271 
272     // The default timeout for callbacks.
273     constexpr static int64_t DEFAULT_TIMEOUT_IN_SEC = 10;
274 
275     virtual ~IVhalClient() = default;
276 
277     using GetValueCallbackFunc =
278             std::function<void(VhalClientResult<std::unique_ptr<IHalPropValue>>)>;
279     using SetValueCallbackFunc = std::function<void(VhalClientResult<void>)>;
280     using OnBinderDiedCallbackFunc = std::function<void()>;
281 
282     /**
283      * Checks whether we are connected to AIDL VHAL backend.
284      *
285      * Returns {@code true} if we are connected to AIDL VHAL backend, {@code false} if we are
286      * connected to HIDL backend.
287      */
288     virtual bool isAidlVhal() = 0;
289 
290     /**
291      * Creates a new {@code IHalpropValue}.
292      *
293      * @param propId The property ID.
294      * @return The created {@code IHalPropValue}.
295      */
296     virtual std::unique_ptr<IHalPropValue> createHalPropValue(int32_t propId) = 0;
297 
298     /**
299      * Creates a new {@code IHalpropValue}.
300      *
301      * @param propId The property ID.
302      * @param areaId The area ID for the property.
303      * @return The created {@code IHalPropValue}.
304      */
305     virtual std::unique_ptr<IHalPropValue> createHalPropValue(int32_t propId, int32_t areaId) = 0;
306 
307     /**
308      * Gets a property value asynchronously.
309      *
310      * @param requestValue The value to request.
311      * @param callback The callback that would be called when the result is ready. The callback
312      *    would be called with an okay result with the got value inside on success. The callback
313      *    would be called with an error result with error code as the returned status code on
314      *    failure.
315      */
316     virtual void getValue(const IHalPropValue& requestValue,
317                           std::shared_ptr<GetValueCallbackFunc> callback) = 0;
318 
319     /**
320      * Gets a property value synchronously.
321      *
322      * @param requestValue the value to request.
323      * @return An okay result with the returned value on success or an error result with returned
324      *    status code as error code. For AIDL backend, this would return TRY_AGAIN error on timeout.
325      *    For HIDL backend, because HIDL backend is synchronous, timeout does not apply.
326      */
327     virtual VhalClientResult<std::unique_ptr<IHalPropValue>> getValueSync(
328             const IHalPropValue& requestValue);
329 
330     /**
331      * Sets a property value asynchronously.
332      *
333      * @param requestValue The value to set.
334      * @param callback The callback that would be called when the request is processed. The callback
335      *    would be called with an empty okay result on success. The callback would be called with
336      *    an error result with error code as the returned status code on failure.
337      */
338     virtual void setValue(const IHalPropValue& requestValue,
339                           std::shared_ptr<SetValueCallbackFunc> callback) = 0;
340 
341     /**
342      * Sets a property value synchronously.
343      *
344      * @param requestValue the value to set.
345      * @return An empty okay result on success or an error result with returned status code as
346      *    error code. For AIDL backend, this would return TIMEOUT error on timeout.
347      *    For HIDL backend, because HIDL backend is synchronous, timeout does not apply.
348      */
349     virtual VhalClientResult<void> setValueSync(const IHalPropValue& requestValue);
350 
351     /**
352      * Adds a callback that would be called when the binder connection to VHAL died.
353      *
354      * @param callback The callback that would be called when the binder died.
355      * @return An okay result on success or an error on failure.
356      */
357     virtual VhalClientResult<void> addOnBinderDiedCallback(
358             std::shared_ptr<OnBinderDiedCallbackFunc> callback) = 0;
359 
360     /**
361      * Removes a previously added OnBinderDied callback.
362      *
363      * @param callback The callback that would be removed.
364      * @return An okay result on success, or an error if the callback is not added before.
365      */
366     virtual VhalClientResult<void> removeOnBinderDiedCallback(
367             std::shared_ptr<OnBinderDiedCallbackFunc> callback) = 0;
368 
369     /**
370      * Gets all the property configurations.
371      *
372      * @return An okay result that contains all property configs on success or an error on failure.
373      */
374     virtual VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() = 0;
375 
376     /**
377      * Gets the configs for specified properties.
378      *
379      * @param propIds A list of property IDs to get configs for.
380      * @return An okay result that contains property configs for specified properties on success or
381      *    an error if failed to get any of the property configs.
382      */
383     virtual VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
384             std::vector<int32_t> propIds) = 0;
385 
386     /**
387      * Gets a {@code ISubscriptionClient} that could be used to subscribe/unsubscribe to properties.
388      *
389      * @param callback The callback that would be called when property event happens.
390      * @return A {@code ISubscriptionClient} used to subscribe/unsubscribe.
391      */
392     virtual std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
393             std::shared_ptr<ISubscriptionCallback> callback) = 0;
394 
395     /**
396      * Gets the min/max supported values for the specified [propId, areaId]s if they are provided
397      * by VHAL.
398      *
399      * This is only supported for AIDL VHAL V4 and above.
400      *
401      * @param propIdAreaIds A list of [propId, areaId] to get the min/max supported values.
402      * @return A list of results, one for each [propId, areaId], or error if failed to get any
403      *      get any results. Caller must check the status inside each result before accessing
404      *      the min/max value. Even if status is OK, minSupportedValue or maxSupportedValue may
405      *      be std::nullopt if it is not specified by VHAL.
406      */
407     virtual VhalClientResult<
408             std::vector<::aidl::android::hardware::automotive::vehicle::MinMaxSupportedValueResult>>
getMinMaxSupportedValue(const std::vector<::aidl::android::hardware::automotive::vehicle::PropIdAreaId> & propIdAreaIds)409     getMinMaxSupportedValue(
410             [[maybe_unused]] const std::vector<
411                     ::aidl::android::hardware::automotive::vehicle::PropIdAreaId>& propIdAreaIds) {
412         return ClientStatusError(ErrorCode::NOT_SUPPORTED)
413                 << "getMinMaxSupportedValue is not supported for the VHAL implementation";
414     }
415 
416     /**
417      * Gets the supported values lists for the specified [propId, areaId]s if they are provided
418      * by VHAL.
419      *
420      * This is only supported for AIDL VHAL V4 and above.
421      *
422      * @param propIdAreaIds A list of [propId, areaId] to get the supported values lists.
423      * @return A list of results, one for each [propId, areaId], or error if failed to get any
424      *      get any results. Caller must check the status inside each result before accessing
425      *      the supported values list. Even if status is OK, supportedValuesList may be
426      *      {@code std::nullopt} if it is not specified by VHAL. If the supportedValuesList has
427      *      value, each element inside the list is guaranteed to have value.
428      */
429     virtual VhalClientResult<
430             std::vector<::aidl::android::hardware::automotive::vehicle::SupportedValuesListResult>>
getSupportedValuesLists(const std::vector<::aidl::android::hardware::automotive::vehicle::PropIdAreaId> & propIdAreaIds)431     getSupportedValuesLists(
432             [[maybe_unused]] const std::vector<
433                     ::aidl::android::hardware::automotive::vehicle::PropIdAreaId>& propIdAreaIds) {
434         return ClientStatusError(ErrorCode::NOT_SUPPORTED)
435                 << "getSupportedValuesLists is not supported for the VHAL implementation";
436     }
437 
438     /**
439      * Gets the VHAL interface version used by VHAL.
440      *
441      * This is only useful for AIDL VHAL.
442      */
getRemoteInterfaceVersion()443     virtual int32_t getRemoteInterfaceVersion() { return 0; }
444 };
445 
446 namespace internal {
447 
toString(const std::vector<int32_t> & values)448 inline std::string toString(const std::vector<int32_t>& values) {
449     std::vector<std::string> strings;
450     for (int32_t value : values) {
451         strings.push_back(std::to_string(value));
452     }
453     return "[" + android::base::Join(strings, ",") + "]";
454 }
455 
456 // SubscriptionClient is the common base class for Aidl and Hidl Subscription Client.
457 class SubscriptionClient : public ISubscriptionClient {
458 protected:
459     virtual std::unordered_set<int32_t> getSubscribedPropIds() = 0;
460 
461     // This should be called inside subclass's destructor.
verifySubscribedPropIdsEmpty()462     void verifySubscribedPropIdsEmpty() {
463         const auto& subscribedPropIds = getSubscribedPropIds();
464         if (!subscribedPropIds.empty()) {
465             ALOGW("Properties: %s are still subscribed when the SubscriptionClient is destroyed, "
466                   "they will always be subscribed until the client process ends, do you forget"
467                   " to call unsubscribeAll?",
468                   toString(std::vector<int32_t>(subscribedPropIds.begin(), subscribedPropIds.end()))
469                           .c_str());
470         }
471     }
472 };
473 
474 }  // namespace internal
475 
476 }  // namespace vhal
477 }  // namespace automotive
478 }  // namespace frameworks
479 }  // namespace android
480 
481 #endif  // CPP_VHAL_CLIENT_INCLUDE_IVHALCLIENT_H_
482