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 struct PropIdAreaId {
314 int32_t propId;
315 int32_t areaId;
316
317 inline bool operator==(const PropIdAreaId& other) const {
318 return areaId == other.areaId && propId == other.propId;
319 }
320 };
321
322 struct PropIdAreaIdHash {
operatorPropIdAreaIdHash323 inline size_t operator()(const PropIdAreaId& propIdAreaId) const {
324 size_t res = 0;
325 hashCombine(res, propIdAreaId.propId);
326 hashCombine(res, propIdAreaId.areaId);
327 return res;
328 }
329 };
330
331 // This is for debug purpose only.
propIdToString(int32_t propId)332 inline std::string propIdToString(int32_t propId) {
333 return toString(
334 static_cast<aidl::android::hardware::automotive::vehicle::VehicleProperty>(propId));
335 }
336
337 // This is for debug purpose only.
338 android::base::Result<int32_t> stringToPropId(const std::string& propName);
339
340 template <typename T>
roundToNearestResolution(std::vector<T> & arrayToSanitize,float resolution)341 void roundToNearestResolution(std::vector<T>& arrayToSanitize, float resolution) {
342 if (resolution == 0) {
343 return;
344 }
345 for (size_t i = 0; i < arrayToSanitize.size(); i++) {
346 arrayToSanitize[i] = (T)((std::round(arrayToSanitize[i] / resolution)) * resolution);
347 }
348 }
349
sanitizeByResolution(aidl::android::hardware::automotive::vehicle::RawPropValues * value,float resolution)350 inline void sanitizeByResolution(aidl::android::hardware::automotive::vehicle::RawPropValues* value,
351 float resolution) {
352 roundToNearestResolution(value->int32Values, resolution);
353 roundToNearestResolution(value->floatValues, resolution);
354 roundToNearestResolution(value->int64Values, resolution);
355 }
356
357 } // namespace vehicle
358 } // namespace automotive
359 } // namespace hardware
360 } // namespace android
361
362 #endif // android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleUtils_H_
363