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 #ifndef android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleUtils_H_
18 #define android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleUtils_H_
19
20 #include <VehicleHalTypes.h>
21
22 #include <android-base/format.h>
23 #include <android-base/result.h>
24 #include <math/HashCombine.h>
25 #include <utils/Log.h>
26
27 namespace android {
28 namespace hardware {
29 namespace automotive {
30 namespace vehicle {
31
32 // Represents all supported areas for a property.
33 constexpr int32_t kAllSupportedAreas = 0;
34
35 // Returns underlying (integer) value for given enum.
36 template <typename ENUM, typename U = typename std::underlying_type<ENUM>::type>
toInt(ENUM const value)37 inline constexpr U toInt(ENUM const value) {
38 return static_cast<U>(value);
39 }
40
getPropType(int32_t prop)41 inline constexpr aidl::android::hardware::automotive::vehicle::VehiclePropertyType getPropType(
42 int32_t prop) {
43 return static_cast<aidl::android::hardware::automotive::vehicle::VehiclePropertyType>(
44 prop & toInt(aidl::android::hardware::automotive::vehicle::VehiclePropertyType::MASK));
45 }
46
getPropGroup(int32_t prop)47 inline constexpr aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup getPropGroup(
48 int32_t prop) {
49 return static_cast<aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup>(
50 prop & toInt(aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup::MASK));
51 }
52
getPropArea(int32_t prop)53 inline constexpr aidl::android::hardware::automotive::vehicle::VehicleArea getPropArea(
54 int32_t prop) {
55 return static_cast<aidl::android::hardware::automotive::vehicle::VehicleArea>(
56 prop & toInt(aidl::android::hardware::automotive::vehicle::VehicleArea::MASK));
57 }
58
isGlobalProp(int32_t prop)59 inline constexpr bool isGlobalProp(int32_t prop) {
60 return getPropArea(prop) == aidl::android::hardware::automotive::vehicle::VehicleArea::GLOBAL;
61 }
62
isSystemProp(int32_t prop)63 inline constexpr bool isSystemProp(int32_t prop) {
64 return aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup::SYSTEM ==
65 getPropGroup(prop);
66 }
67
getAreaConfig(int32_t propId,int32_t areaId,const aidl::android::hardware::automotive::vehicle::VehiclePropConfig & config)68 inline const aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
69 int32_t propId, int32_t areaId,
70 const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
71 if (config.areaConfigs.size() == 0) {
72 return nullptr;
73 }
74
75 if (isGlobalProp(propId)) {
76 return &(config.areaConfigs[0]);
77 }
78
79 for (const auto& c : config.areaConfigs) {
80 if (c.areaId == areaId) {
81 return &c;
82 }
83 }
84 return nullptr;
85 }
86
getAreaConfig(const aidl::android::hardware::automotive::vehicle::VehiclePropValue & propValue,const aidl::android::hardware::automotive::vehicle::VehiclePropConfig & config)87 inline const aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
88 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
89 const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
90 return getAreaConfig(propValue.prop, propValue.areaId, config);
91 }
92
93 inline std::unique_ptr<aidl::android::hardware::automotive::vehicle::VehiclePropValue>
createVehiclePropValueVec(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,size_t vecSize)94 createVehiclePropValueVec(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,
95 size_t vecSize) {
96 auto val = std::unique_ptr<aidl::android::hardware::automotive::vehicle::VehiclePropValue>(
97 new aidl::android::hardware::automotive::vehicle::VehiclePropValue);
98 switch (type) {
99 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT32:
100 [[fallthrough]];
101 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::BOOLEAN:
102 vecSize = 1;
103 [[fallthrough]];
104 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT32_VEC:
105 val->value.int32Values.resize(vecSize);
106 break;
107 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::FLOAT:
108 vecSize = 1;
109 [[fallthrough]];
110 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::FLOAT_VEC:
111 val->value.floatValues.resize(vecSize);
112 break;
113 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT64:
114 vecSize = 1;
115 [[fallthrough]];
116 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT64_VEC:
117 val->value.int64Values.resize(vecSize);
118 break;
119 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::BYTES:
120 val->value.byteValues.resize(vecSize);
121 break;
122 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::STRING:
123 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::MIXED:
124 break; // Valid, but nothing to do.
125 default:
126 ALOGE("createVehiclePropValue: unknown type: %d", toInt(type));
127 }
128 return val;
129 }
130
131 inline std::unique_ptr<aidl::android::hardware::automotive::vehicle::VehiclePropValue>
createVehiclePropValue(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type)132 createVehiclePropValue(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type) {
133 return createVehiclePropValueVec(type, 1);
134 }
135
getVehicleRawValueVectorSize(const aidl::android::hardware::automotive::vehicle::RawPropValues & value,aidl::android::hardware::automotive::vehicle::VehiclePropertyType type)136 inline size_t getVehicleRawValueVectorSize(
137 const aidl::android::hardware::automotive::vehicle::RawPropValues& value,
138 aidl::android::hardware::automotive::vehicle::VehiclePropertyType type) {
139 switch (type) {
140 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT32:
141 [[fallthrough]];
142 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::BOOLEAN:
143 return std::min(value.int32Values.size(), static_cast<size_t>(1));
144 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::FLOAT:
145 return std::min(value.floatValues.size(), static_cast<size_t>(1));
146 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT64:
147 return std::min(value.int64Values.size(), static_cast<size_t>(1));
148 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT32_VEC:
149 return value.int32Values.size();
150 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::FLOAT_VEC:
151 return value.floatValues.size();
152 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT64_VEC:
153 return value.int64Values.size();
154 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::BYTES:
155 return value.byteValues.size();
156 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::STRING:
157 [[fallthrough]];
158 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::MIXED:
159 return 0;
160 default:
161 ALOGE("getVehicleRawValueVectorSize: unknown type: %d", toInt(type));
162 return 0;
163 }
164 }
165
copyVehicleRawValue(aidl::android::hardware::automotive::vehicle::RawPropValues * dest,const aidl::android::hardware::automotive::vehicle::RawPropValues & src)166 inline void copyVehicleRawValue(
167 aidl::android::hardware::automotive::vehicle::RawPropValues* dest,
168 const aidl::android::hardware::automotive::vehicle::RawPropValues& src) {
169 dest->int32Values = src.int32Values;
170 dest->floatValues = src.floatValues;
171 dest->int64Values = src.int64Values;
172 dest->byteValues = src.byteValues;
173 dest->stringValue = src.stringValue;
174 }
175
176 // getVehiclePropValueSize returns approximately how much memory 'value' would take. This should
177 // only be used in a limited-size memory pool to set an upper bound for memory consumption.
getVehiclePropValueSize(const aidl::android::hardware::automotive::vehicle::VehiclePropValue & prop)178 inline size_t getVehiclePropValueSize(
179 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& prop) {
180 size_t size = 0;
181 size += sizeof(prop.timestamp);
182 size += sizeof(prop.areaId);
183 size += sizeof(prop.prop);
184 size += sizeof(prop.status);
185 size += prop.value.int32Values.size() * sizeof(int32_t);
186 size += prop.value.int64Values.size() * sizeof(int64_t);
187 size += prop.value.floatValues.size() * sizeof(float);
188 size += prop.value.byteValues.size() * sizeof(uint8_t);
189 size += prop.value.stringValue.size();
190 return size;
191 }
192
193 // Check whether the value is valid according to config.
194 // We check for the following:
195 // * If the type is INT32, {@code value.int32Values} must contain one element.
196 // * If the type is INT32_VEC, {@code value.int32Values} must contain at least one element.
197 // * If the type is INT64, {@code value.int64Values} must contain one element.
198 // * If the type is INT64_VEC, {@code value.int64Values} must contain at least one element.
199 // * If the type is FLOAT, {@code value.floatValues} must contain one element.
200 // * If the type is FLOAT_VEC, {@code value.floatValues} must contain at least one element.
201 // * If the type is MIXED, see checkVendorMixedPropValue.
202 android::base::Result<void> checkPropValue(
203 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
204 const aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
205
206 // Check whether the Mixed type value is valid according to config.
207 // We check for the following:
208 // * configArray[1] + configArray[2] + configArray[3] must be equal to the number of
209 // {@code value.int32Values} elements.
210 // * configArray[4] + configArray[5] must be equal to the number of {@code value.int64Values}
211 // elements.
212 // * configArray[6] + configArray[7] must be equal to the number of {@code value.floatValues}
213 // elements.
214 // * configArray[8] must be equal to the number of {@code value.byteValues} elements.
215 android::base::Result<void> checkVendorMixedPropValue(
216 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
217 const aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
218
219 // Check whether the value is within the configured range.
220 // We check for the following types:
221 // * If type is INT32 or INT32_VEC, all {@code value.int32Values} elements must be within
222 // {@code minInt32Value} and {@code maxInt32Value} if either of them is not 0.
223 // * If type is INT64 or INT64_VEC, all {@code value.int64Values} elements must be within
224 // {@code minInt64Value} and {@code maxInt64Value} if either of them is not 0.
225 // * If type is FLOAT or FLOAT_VEC, all {@code value.floatValues} elements must be within
226 // {@code minFloatValues} and {@code maxFloatValues} if either of them is not 0.
227 // We don't check other types. If more checks are required, they should be added in VehicleHardware
228 // implementation.
229 android::base::Result<void> checkValueRange(
230 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
231 const aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* config);
232
233 // VhalError is a wrapper class for {@code StatusCode} that could act as E in {@code Result<T,E>}.
234 class VhalError final {
235 public:
VhalError()236 VhalError() : mCode(aidl::android::hardware::automotive::vehicle::StatusCode::OK) {}
237
VhalError(aidl::android::hardware::automotive::vehicle::StatusCode && code)238 VhalError(aidl::android::hardware::automotive::vehicle::StatusCode&& code) : mCode(code) {}
239
VhalError(const aidl::android::hardware::automotive::vehicle::StatusCode & code)240 VhalError(const aidl::android::hardware::automotive::vehicle::StatusCode& code) : mCode(code) {}
241
242 aidl::android::hardware::automotive::vehicle::StatusCode value() const;
243
StatusCode()244 inline operator aidl::android::hardware::automotive::vehicle::StatusCode() const {
245 return value();
246 }
247
248 std::string print() const;
249
250 private:
251 aidl::android::hardware::automotive::vehicle::StatusCode mCode;
252 };
253
254 // VhalResult is a {@code Result} that contains {@code StatusCode} as error type.
255 template <class T>
256 using VhalResult = android::base::Result<T, VhalError>;
257
258 // StatusError could be cast to {@code ResultError} with a {@code StatusCode} and should be used
259 // as error type for {@VhalResult}.
260 using StatusError = android::base::Error<VhalError>;
261
262 template <class T>
getErrorCode(const VhalResult<T> & result)263 aidl::android::hardware::automotive::vehicle::StatusCode getErrorCode(const VhalResult<T>& result) {
264 if (result.ok()) {
265 return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
266 }
267 return result.error().code();
268 }
269
270 template <class T>
getIntErrorCode(const VhalResult<T> & result)271 int getIntErrorCode(const VhalResult<T>& result) {
272 return toInt(getErrorCode(result));
273 }
274
275 template <class T, class E>
getErrorMsg(const android::base::Result<T,E> & result)276 std::string getErrorMsg(const android::base::Result<T, E>& result) {
277 if (result.ok()) {
278 return "";
279 }
280 return result.error().message();
281 }
282
283 template <class T, class E>
toScopedAStatus(const android::base::Result<T,E> & result,aidl::android::hardware::automotive::vehicle::StatusCode status,const std::string & additionalErrorMsg)284 ndk::ScopedAStatus toScopedAStatus(const android::base::Result<T, E>& result,
285 aidl::android::hardware::automotive::vehicle::StatusCode status,
286 const std::string& additionalErrorMsg) {
287 if (result.ok()) {
288 return ndk::ScopedAStatus::ok();
289 }
290 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
291 toInt(status),
292 fmt::format("{}, error: {}", additionalErrorMsg, getErrorMsg(result)).c_str());
293 }
294
295 template <class T, class E>
toScopedAStatus(const android::base::Result<T,E> & result,aidl::android::hardware::automotive::vehicle::StatusCode status)296 ndk::ScopedAStatus toScopedAStatus(
297 const android::base::Result<T, E>& result,
298 aidl::android::hardware::automotive::vehicle::StatusCode status) {
299 return toScopedAStatus(result, status, "");
300 }
301
302 template <class T>
toScopedAStatus(const VhalResult<T> & result)303 ndk::ScopedAStatus toScopedAStatus(const VhalResult<T>& result) {
304 return toScopedAStatus(result, getErrorCode(result));
305 }
306
307 template <class T>
toScopedAStatus(const VhalResult<T> & result,const std::string & additionalErrorMsg)308 ndk::ScopedAStatus toScopedAStatus(const VhalResult<T>& result,
309 const std::string& additionalErrorMsg) {
310 return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
311 }
312
313 // This is for debug purpose only.
propIdToString(int32_t propId)314 inline std::string propIdToString(int32_t propId) {
315 return toString(
316 static_cast<aidl::android::hardware::automotive::vehicle::VehicleProperty>(propId));
317 }
318
319 struct PropIdAreaId {
320 int32_t propId;
321 int32_t areaId;
322
323 inline bool operator==(const PropIdAreaId& other) const {
324 return areaId == other.areaId && propId == other.propId;
325 }
326
327 // This is for debug purpose only.
toStringPropIdAreaId328 inline std::string toString() const {
329 return fmt::format("{{propId: {}, areaId: {}}}", propIdToString(propId), areaId);
330 }
331 };
332
333 struct PropIdAreaIdHash {
operatorPropIdAreaIdHash334 inline size_t operator()(const PropIdAreaId& propIdAreaId) const {
335 size_t res = 0;
336 hashCombine(res, propIdAreaId.propId);
337 hashCombine(res, propIdAreaId.areaId);
338 return res;
339 }
340 };
341
342 // This is for debug purpose only.
343 android::base::Result<int32_t> stringToPropId(const std::string& propName);
344
345 // This is for debug purpose only. Converts an area's name to its enum definition.
346 android::base::Result<int32_t> stringToArea(const std::string& areaName, int32_t propId);
347
348 template <typename T>
roundToNearestResolution(std::vector<T> & arrayToSanitize,float resolution)349 void roundToNearestResolution(std::vector<T>& arrayToSanitize, float resolution) {
350 if (resolution == 0) {
351 return;
352 }
353 for (size_t i = 0; i < arrayToSanitize.size(); i++) {
354 arrayToSanitize[i] = (T)((std::round(arrayToSanitize[i] / resolution)) * resolution);
355 }
356 }
357
sanitizeByResolution(aidl::android::hardware::automotive::vehicle::RawPropValues * value,float resolution)358 inline void sanitizeByResolution(aidl::android::hardware::automotive::vehicle::RawPropValues* value,
359 float resolution) {
360 roundToNearestResolution(value->int32Values, resolution);
361 roundToNearestResolution(value->floatValues, resolution);
362 roundToNearestResolution(value->int64Values, resolution);
363 }
364
365 } // namespace vehicle
366 } // namespace automotive
367 } // namespace hardware
368 } // namespace android
369
370 // Formatter must not be defined inside our namespace.
371 template <>
372 struct fmt::formatter<android::hardware::automotive::vehicle::PropIdAreaId> {
373 template <typename ParseContext>
374 constexpr auto parse(ParseContext& ctx) {
375 return ctx.begin();
376 }
377
378 template <typename FormatContext>
379 auto format(const android::hardware::automotive::vehicle::PropIdAreaId& p,
380 FormatContext& ctx) const {
381 return fmt::format_to(ctx.out(), "{{propId: {}, areaId: {}}}",
382 android::hardware::automotive::vehicle::propIdToString(p.propId),
383 p.areaId);
384 }
385 };
386
387 #endif // android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleUtils_H_
388