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