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/StatusCode.h>
24 #include <aidl/android/hardware/automotive/vehicle/SubscribeOptions.h>
25 #include <android-base/result.h>
26
27 #include <VehicleUtils.h>
28
29 namespace android {
30 namespace frameworks {
31 namespace automotive {
32 namespace vhal {
33
34 struct HalPropError {
35 int32_t propId;
36 int32_t areaId;
37 aidl::android::hardware::automotive::vehicle::StatusCode status;
38 };
39
40 // ISubscriptionCallback is a general interface to delivery property events caused by subscription.
41 class ISubscriptionCallback {
42 public:
43 virtual ~ISubscriptionCallback() = default;
44 /**
45 * Called when new property events happen.
46 */
47 virtual void onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>>& values) = 0;
48
49 /**
50 * Called when property set errors happen.
51 */
52 virtual void onPropertySetError(const std::vector<HalPropError>& errors) = 0;
53 };
54
55 // Errors for vehicle HAL client interface.
56 enum class ErrorCode : int {
57 // Response status is OK. No errors.
58 OK = 0,
59 // The argument is invalid.
60 INVALID_ARG = 1,
61 // The request timed out. The client may try again.
62 TIMEOUT = 2,
63 // Some errors occur while connecting VHAL. The client may try again.
64 TRANSACTION_ERROR = 3,
65 // Some unexpected errors happen in VHAL. Needs to try again.
66 TRY_AGAIN_FROM_VHAL = 4,
67 // The device of corresponding vehicle property is not available.
68 // Example: the HVAC unit is turned OFF when user wants to adjust temperature.
69 NOT_AVAILABLE_FROM_VHAL = 5,
70 // The request is unauthorized.
71 ACCESS_DENIED_FROM_VHAL = 6,
72 // Some unexpected errors, for example OOM, happen in VHAL.
73 INTERNAL_ERROR_FROM_VHAL = 7,
74 };
75
76 // Convert the VHAL {@code StatusCode} to {@code ErrorCode}.
statusCodeToErrorCode(const aidl::android::hardware::automotive::vehicle::StatusCode & code)77 static ErrorCode statusCodeToErrorCode(
78 const aidl::android::hardware::automotive::vehicle::StatusCode& code) {
79 switch (code) {
80 case aidl::android::hardware::automotive::vehicle::StatusCode::OK:
81 return ErrorCode::OK;
82 case aidl::android::hardware::automotive::vehicle::StatusCode::TRY_AGAIN:
83 return ErrorCode::TRY_AGAIN_FROM_VHAL;
84 case aidl::android::hardware::automotive::vehicle::StatusCode::INVALID_ARG:
85 return ErrorCode::INVALID_ARG;
86 case aidl::android::hardware::automotive::vehicle::StatusCode::NOT_AVAILABLE:
87 return ErrorCode::NOT_AVAILABLE_FROM_VHAL;
88 case aidl::android::hardware::automotive::vehicle::StatusCode::ACCESS_DENIED:
89 return ErrorCode::ACCESS_DENIED_FROM_VHAL;
90 case aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR:
91 return ErrorCode::INTERNAL_ERROR_FROM_VHAL;
92 default:
93 return ErrorCode::INTERNAL_ERROR_FROM_VHAL;
94 }
95 }
96
97 // VhalClientError is a wrapper class for {@code ErrorCode} that could act as E in {@code
98 // Result<T,E>}.
99 class VhalClientError final {
100 public:
VhalClientError()101 VhalClientError() : mCode(ErrorCode::OK) {}
102
VhalClientError(ErrorCode && code)103 VhalClientError(ErrorCode&& code) : mCode(code) {}
104
VhalClientError(const ErrorCode & code)105 VhalClientError(const ErrorCode& code) : mCode(code) {}
106
VhalClientError(aidl::android::hardware::automotive::vehicle::StatusCode && code)107 VhalClientError(aidl::android::hardware::automotive::vehicle::StatusCode&& code) :
108 mCode(statusCodeToErrorCode(code)) {}
109
VhalClientError(const aidl::android::hardware::automotive::vehicle::StatusCode & code)110 VhalClientError(const aidl::android::hardware::automotive::vehicle::StatusCode& code) :
111 mCode(statusCodeToErrorCode(code)) {}
112
113 ErrorCode value() const;
114
ErrorCode()115 inline operator ErrorCode() const { return value(); }
116
117 static std::string toString(ErrorCode code);
118
119 std::string print() const;
120
121 private:
122 ErrorCode mCode;
123 };
124
125 // VhalClientResult is a {@code Result} that contains {@code ErrorCode} as error type.
126 template <class T>
127 using VhalClientResult = android::base::Result<T, VhalClientError>;
128
129 // ClientStatusError could be cast to {@code ResultError} with a {@code ErrorCode}
130 // and should be used as error type for {@VhalClientResult}.
131 using ClientStatusError = android::base::Error<VhalClientError>;
132
133 // ISubscriptionCallback is a client that could be used to subscribe/unsubscribe.
134 class ISubscriptionClient {
135 public:
136 virtual ~ISubscriptionClient() = default;
137
138 // Subscribes to properties. It is recommended to use SubscribeOptionsBuilder to build
139 // the options.
140 virtual VhalClientResult<void> subscribe(
141 const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
142 options) = 0;
143
144 virtual VhalClientResult<void> unsubscribe(const std::vector<int32_t>& propIds) = 0;
145 };
146
147 class SubscribeOptionsBuilder {
148 private:
149 int32_t mPropId;
150 std::vector<int32_t> mAreaIds;
151 float mSampleRate = 0;
152 float mResolution = 0.0f;
153 // VUR is on by default.
154 bool mEnableVariableUpdateRate = true;
155
156 public:
SubscribeOptionsBuilder(int32_t propId)157 explicit SubscribeOptionsBuilder(int32_t propId) : mPropId(propId) {}
158
159 // Sets the sample rate.
setSampleRate(float sampleRate)160 void setSampleRate(float sampleRate) { mSampleRate = sampleRate; }
161
162 // Adds an area ID to subscribe.
163 //
164 // Only supported for AIDL VHAL client.
165 //
166 // For HIDL VHAL client, per-area ID subscription is not supported, this is ignored and all
167 // area IDs for the property will be subscribed.
addAreaId(int32_t areaId)168 void addAreaId(int32_t areaId) { mAreaIds.push_back(areaId); }
169
170 // Sets the resolution of property updates for continuous property.
171 //
172 // Only supported for continuous property. Ignored for non-cotinuous property.
173 //
174 // Only supported for AIDL VHAL client. Ignored for HIDL VHAL client.
175 //
176 // This value indicates the resolution at which continuous property updates should be sent to
177 // the platform. For example, if resolution is 0.01, the subscribed property value should be
178 // rounded to two decimal places.
179 //
180 // The resolution must be an integer power of 10, (e.g. 0.01, 0.1, 1, 10, etc.).
setResolution(float resolution)181 void setResolution(float resolution) { mResolution = resolution; }
182
183 // Sets whether to enable varialbe update rate.
184 //
185 // Only supported for continuous property. Ignored for non-cotinuous property.
186 //
187 // Only supported for AIDL VHAL client. Ignored for HIDL VHAL client.
188 //
189 // If variable update rate is enabled, for each given areaId, if VHAL supports variable update
190 // rate for the [propId, areaId], VHAL must ignore duplicate property value events
191 // and only sends changed value events (a.k.a treat continuous as an on-change property).
setEnableVariableUpdateRate(bool enableVariableUpdateRate)192 void setEnableVariableUpdateRate(bool enableVariableUpdateRate) {
193 mEnableVariableUpdateRate = enableVariableUpdateRate;
194 }
195
196 // Builds the SubscribeOptions.
build()197 aidl::android::hardware::automotive::vehicle::SubscribeOptions build() {
198 return {
199 .propId = mPropId,
200 .areaIds = mAreaIds,
201 .sampleRate = mSampleRate,
202 .resolution = mResolution,
203 .enableVariableUpdateRate = mEnableVariableUpdateRate,
204 };
205 }
206 };
207
208 // IVhalClient is a thread-safe client for AIDL or HIDL VHAL backend.
209 class IVhalClient {
210 public:
211 // Wait for VHAL service and create a client. Return nullptr if failed to connect to VHAL.
212 static std::shared_ptr<IVhalClient> create();
213
214 // Try to get the VHAL service and create a client. Return nullptr if failed to connect to VHAL.
215 static std::shared_ptr<IVhalClient> tryCreate();
216
217 // Try to create a client based on the AIDL VHAL service descriptor.
218 static std::shared_ptr<IVhalClient> tryCreateAidlClient(const char* descriptor);
219
220 // Try to create a client based on the HIDL VHAL service descriptor.
221 static std::shared_ptr<IVhalClient> tryCreateHidlClient(const char* descriptor);
222
223 // The default timeout for callbacks.
224 constexpr static int64_t DEFAULT_TIMEOUT_IN_SEC = 10;
225
226 virtual ~IVhalClient() = default;
227
228 using GetValueCallbackFunc =
229 std::function<void(VhalClientResult<std::unique_ptr<IHalPropValue>>)>;
230 using SetValueCallbackFunc = std::function<void(VhalClientResult<void>)>;
231 using OnBinderDiedCallbackFunc = std::function<void()>;
232
233 /**
234 * Check whether we are connected to AIDL VHAL backend.
235 *
236 * Returns {@code true} if we are connected to AIDL VHAL backend, {@code false} if we are
237 * connected to HIDL backend.
238 */
239 virtual bool isAidlVhal() = 0;
240
241 /**
242 * Create a new {@code IHalpropValue}.
243 *
244 * @param propId The property ID.
245 * @return The created {@code IHalPropValue}.
246 */
247 virtual std::unique_ptr<IHalPropValue> createHalPropValue(int32_t propId) = 0;
248
249 /**
250 * Create a new {@code IHalpropValue}.
251 *
252 * @param propId The property ID.
253 * @param areaId The area ID for the property.
254 * @return The created {@code IHalPropValue}.
255 */
256 virtual std::unique_ptr<IHalPropValue> createHalPropValue(int32_t propId, int32_t areaId) = 0;
257
258 /**
259 * Get a property value asynchronously.
260 *
261 * @param requestValue The value to request.
262 * @param callback The callback that would be called when the result is ready. The callback
263 * would be called with an okay result with the got value inside on success. The callback
264 * would be called with an error result with error code as the returned status code on
265 * failure.
266 */
267 virtual void getValue(const IHalPropValue& requestValue,
268 std::shared_ptr<GetValueCallbackFunc> callback) = 0;
269
270 /**
271 * Get a property value synchronously.
272 *
273 * @param requestValue the value to request.
274 * @return An okay result with the returned value on success or an error result with returned
275 * status code as error code. For AIDL backend, this would return TRY_AGAIN error on timeout.
276 * For HIDL backend, because HIDL backend is synchronous, timeout does not apply.
277 */
278 virtual VhalClientResult<std::unique_ptr<IHalPropValue>> getValueSync(
279 const IHalPropValue& requestValue);
280
281 /**
282 * Set a property value asynchronously.
283 *
284 * @param requestValue The value to set.
285 * @param callback The callback that would be called when the request is processed. The callback
286 * would be called with an empty okay result on success. The callback would be called with
287 * an error result with error code as the returned status code on failure.
288 */
289 virtual void setValue(const IHalPropValue& requestValue,
290 std::shared_ptr<SetValueCallbackFunc> callback) = 0;
291
292 /**
293 * Set a property value synchronously.
294 *
295 * @param requestValue the value to set.
296 * @return An empty okay result on success or an error result with returned status code as
297 * error code. For AIDL backend, this would return TIMEOUT error on timeout.
298 * For HIDL backend, because HIDL backend is synchronous, timeout does not apply.
299 */
300 virtual VhalClientResult<void> setValueSync(const IHalPropValue& requestValue);
301
302 /**
303 * Add a callback that would be called when the binder connection to VHAL died.
304 *
305 * @param callback The callback that would be called when the binder died.
306 * @return An okay result on success or an error on failure.
307 */
308 virtual VhalClientResult<void> addOnBinderDiedCallback(
309 std::shared_ptr<OnBinderDiedCallbackFunc> callback) = 0;
310
311 /**
312 * Remove a previously added OnBinderDied callback.
313 *
314 * @param callback The callback that would be removed.
315 * @return An okay result on success, or an error if the callback is not added before.
316 */
317 virtual VhalClientResult<void> removeOnBinderDiedCallback(
318 std::shared_ptr<OnBinderDiedCallbackFunc> callback) = 0;
319
320 /**
321 * Get all the property configurations.
322 *
323 * @return An okay result that contains all property configs on success or an error on failure.
324 */
325 virtual VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() = 0;
326
327 /**
328 * Get the configs for specified properties.
329 *
330 * @param propIds A list of property IDs to get configs for.
331 * @return An okay result that contains property configs for specified properties on success or
332 * an error if failed to get any of the property configs.
333 */
334 virtual VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
335 std::vector<int32_t> propIds) = 0;
336
337 /**
338 * Get a {@code ISubscriptionClient} that could be used to subscribe/unsubscribe to properties.
339 *
340 * @param callback The callback that would be called when property event happens.
341 * @return A {@code ISubscriptionClient} used to subscribe/unsubscribe.
342 */
343 virtual std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
344 std::shared_ptr<ISubscriptionCallback> callback) = 0;
345
346 /**
347 * Gets the VHAL interface version used by VHAL.
348 *
349 * This is only useful for AIDL VHAL.
350 */
getRemoteInterfaceVersion()351 virtual int32_t getRemoteInterfaceVersion() { return 0; }
352 };
353
354 } // namespace vhal
355 } // namespace automotive
356 } // namespace frameworks
357 } // namespace android
358
359 #endif // CPP_VHAL_CLIENT_INCLUDE_IVHALCLIENT_H_
360