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