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 val.reset(nullptr);
128 }
129 return val;
130 }
131
132 inline std::unique_ptr<aidl::android::hardware::automotive::vehicle::VehiclePropValue>
createVehiclePropValue(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type)133 createVehiclePropValue(aidl::android::hardware::automotive::vehicle::VehiclePropertyType type) {
134 return createVehiclePropValueVec(type, 1);
135 }
136
getVehicleRawValueVectorSize(const aidl::android::hardware::automotive::vehicle::RawPropValues & value,aidl::android::hardware::automotive::vehicle::VehiclePropertyType type)137 inline size_t getVehicleRawValueVectorSize(
138 const aidl::android::hardware::automotive::vehicle::RawPropValues& value,
139 aidl::android::hardware::automotive::vehicle::VehiclePropertyType type) {
140 switch (type) {
141 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT32:
142 [[fallthrough]];
143 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::BOOLEAN:
144 return std::min(value.int32Values.size(), static_cast<size_t>(1));
145 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::FLOAT:
146 return std::min(value.floatValues.size(), static_cast<size_t>(1));
147 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT64:
148 return std::min(value.int64Values.size(), static_cast<size_t>(1));
149 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT32_VEC:
150 return value.int32Values.size();
151 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::FLOAT_VEC:
152 return value.floatValues.size();
153 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::INT64_VEC:
154 return value.int64Values.size();
155 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::BYTES:
156 return value.byteValues.size();
157 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::STRING:
158 [[fallthrough]];
159 case aidl::android::hardware::automotive::vehicle::VehiclePropertyType::MIXED:
160 return 0;
161 default:
162 ALOGE("getVehicleRawValueVectorSize: unknown type: %d", toInt(type));
163 return 0;
164 }
165 }
166
copyVehicleRawValue(aidl::android::hardware::automotive::vehicle::RawPropValues * dest,const aidl::android::hardware::automotive::vehicle::RawPropValues & src)167 inline void copyVehicleRawValue(
168 aidl::android::hardware::automotive::vehicle::RawPropValues* dest,
169 const aidl::android::hardware::automotive::vehicle::RawPropValues& src) {
170 dest->int32Values = src.int32Values;
171 dest->floatValues = src.floatValues;
172 dest->int64Values = src.int64Values;
173 dest->byteValues = src.byteValues;
174 dest->stringValue = src.stringValue;
175 }
176
177 // getVehiclePropValueSize returns approximately how much memory 'value' would take. This should
178 // 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)179 inline size_t getVehiclePropValueSize(
180 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& prop) {
181 size_t size = 0;
182 size += sizeof(prop.timestamp);
183 size += sizeof(prop.areaId);
184 size += sizeof(prop.prop);
185 size += sizeof(prop.status);
186 size += prop.value.int32Values.size() * sizeof(int32_t);
187 size += prop.value.int64Values.size() * sizeof(int64_t);
188 size += prop.value.floatValues.size() * sizeof(float);
189 size += prop.value.byteValues.size() * sizeof(uint8_t);
190 size += prop.value.stringValue.size();
191 return size;
192 }
193
194 // Check whether the value is valid according to config.
195 // We check for the following:
196 // * If the type is INT32, {@code value.int32Values} must contain one element.
197 // * If the type is INT32_VEC, {@code value.int32Values} must contain at least one element.
198 // * If the type is INT64, {@code value.int64Values} must contain one element.
199 // * If the type is INT64_VEC, {@code value.int64Values} must contain at least one element.
200 // * If the type is FLOAT, {@code value.floatValues} must contain one element.
201 // * If the type is FLOAT_VEC, {@code value.floatValues} must contain at least one element.
202 // * If the type is MIXED, see checkVendorMixedPropValue.
203 android::base::Result<void> checkPropValue(
204 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
205 const aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
206
207 // Check whether the Mixed type value is valid according to config.
208 // We check for the following:
209 // * configArray[1] + configArray[2] + configArray[3] must be equal to the number of
210 // {@code value.int32Values} elements.
211 // * configArray[4] + configArray[5] must be equal to the number of {@code value.int64Values}
212 // elements.
213 // * configArray[6] + configArray[7] must be equal to the number of {@code value.floatValues}
214 // elements.
215 // * configArray[8] must be equal to the number of {@code value.byteValues} elements.
216 android::base::Result<void> checkVendorMixedPropValue(
217 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
218 const aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
219
220 // Check whether the value is within the configured range.
221 // We check for the following types:
222 // * If type is INT32 or INT32_VEC, all {@code value.int32Values} elements must be within
223 // {@code minInt32Value} and {@code maxInt32Value} if either of them is not 0.
224 // * If type is INT64 or INT64_VEC, all {@code value.int64Values} elements must be within
225 // {@code minInt64Value} and {@code maxInt64Value} if either of them is not 0.
226 // * If type is FLOAT or FLOAT_VEC, all {@code value.floatValues} elements must be within
227 // {@code minFloatValues} and {@code maxFloatValues} if either of them is not 0.
228 // We don't check other types. If more checks are required, they should be added in VehicleHardware
229 // implementation.
230 android::base::Result<void> checkValueRange(
231 const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
232 const aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* config);
233
234 // VhalError is a wrapper class for {@code StatusCode} that could act as E in {@code Result<T,E>}.
235 class VhalError final {
236 public:
VhalError()237 VhalError() : mCode(aidl::android::hardware::automotive::vehicle::StatusCode::OK) {}
238
VhalError(aidl::android::hardware::automotive::vehicle::StatusCode && code)239 VhalError(aidl::android::hardware::automotive::vehicle::StatusCode&& code) : mCode(code) {}
240
VhalError(const aidl::android::hardware::automotive::vehicle::StatusCode & code)241 VhalError(const aidl::android::hardware::automotive::vehicle::StatusCode& code) : mCode(code) {}
242
243 aidl::android::hardware::automotive::vehicle::StatusCode value() const;
244
StatusCode()245 inline operator aidl::android::hardware::automotive::vehicle::StatusCode() const {
246 return value();
247 }
248
249 std::string print() const;
250
251 private:
252 aidl::android::hardware::automotive::vehicle::StatusCode mCode;
253 };
254
255 // VhalResult is a {@code Result} that contains {@code StatusCode} as error type.
256 template <class T>
257 using VhalResult = android::base::Result<T, VhalError>;
258
259 // StatusError could be cast to {@code ResultError} with a {@code StatusCode} and should be used
260 // as error type for {@VhalResult}.
261 using StatusError = android::base::Error<VhalError>;
262
263 template <class T>
getErrorCode(const VhalResult<T> & result)264 aidl::android::hardware::automotive::vehicle::StatusCode getErrorCode(const VhalResult<T>& result) {
265 if (result.ok()) {
266 return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
267 }
268 return result.error().code();
269 }
270
271 template <class T>
getIntErrorCode(const VhalResult<T> & result)272 int getIntErrorCode(const VhalResult<T>& result) {
273 return toInt(getErrorCode(result));
274 }
275
276 template <class T, class E>
getErrorMsg(const android::base::Result<T,E> & result)277 std::string getErrorMsg(const android::base::Result<T, E>& result) {
278 if (result.ok()) {
279 return "";
280 }
281 return result.error().message();
282 }
283
284 template <class T, class E>
toScopedAStatus(const android::base::Result<T,E> & result,aidl::android::hardware::automotive::vehicle::StatusCode status,const std::string & additionalErrorMsg)285 ndk::ScopedAStatus toScopedAStatus(const android::base::Result<T, E>& result,
286 aidl::android::hardware::automotive::vehicle::StatusCode status,
287 const std::string& additionalErrorMsg) {
288 if (result.ok()) {
289 return ndk::ScopedAStatus::ok();
290 }
291 return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
292 toInt(status),
293 fmt::format("{}, error: {}", additionalErrorMsg, getErrorMsg(result)).c_str());
294 }
295
296 template <class T, class E>
toScopedAStatus(const android::base::Result<T,E> & result,aidl::android::hardware::automotive::vehicle::StatusCode status)297 ndk::ScopedAStatus toScopedAStatus(
298 const android::base::Result<T, E>& result,
299 aidl::android::hardware::automotive::vehicle::StatusCode status) {
300 return toScopedAStatus(result, status, "");
301 }
302
303 template <class T>
toScopedAStatus(const VhalResult<T> & result)304 ndk::ScopedAStatus toScopedAStatus(const VhalResult<T>& result) {
305 return toScopedAStatus(result, getErrorCode(result));
306 }
307
308 template <class T>
toScopedAStatus(const VhalResult<T> & result,const std::string & additionalErrorMsg)309 ndk::ScopedAStatus toScopedAStatus(const VhalResult<T>& result,
310 const std::string& additionalErrorMsg) {
311 return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
312 }
313
314 struct PropIdAreaId {
315 int32_t propId;
316 int32_t areaId;
317
318 inline bool operator==(const PropIdAreaId& other) const {
319 return areaId == other.areaId && propId == other.propId;
320 }
321 };
322
323 struct PropIdAreaIdHash {
operatorPropIdAreaIdHash324 inline size_t operator()(const PropIdAreaId& propIdAreaId) const {
325 size_t res = 0;
326 hashCombine(res, propIdAreaId.propId);
327 hashCombine(res, propIdAreaId.areaId);
328 return res;
329 }
330 };
331
332 } // namespace vehicle
333 } // namespace automotive
334 } // namespace hardware
335 } // namespace android
336
337 #endif // android_hardware_automotive_vehicle_aidl_impl_utils_common_include_VehicleUtils_H_
338