• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "VehicleUtils.h"
18 
19 #include <unordered_map>
20 
21 namespace android {
22 namespace hardware {
23 namespace automotive {
24 namespace vehicle {
25 
26 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
27 using ::aidl::android::hardware::automotive::vehicle::toString;
28 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
29 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
30 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaDoor;
31 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror;
32 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaSeat;
33 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWheel;
34 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
35 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
36 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
37 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
38 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
39 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
40 using ::android::base::Error;
41 using ::android::base::Result;
42 using ::ndk::ScopedAStatus;
43 
44 namespace {
45 
46 class PropertyIdByNameSingleton {
47   public:
getInstance()48     static PropertyIdByNameSingleton& getInstance() {
49         static PropertyIdByNameSingleton instance;
50         return instance;
51     }
52 
getPropertyId(const std::string & name) const53     Result<int32_t> getPropertyId(const std::string& name) const {
54         auto it = mPropertyIdByName.find(name);
55         if (it == mPropertyIdByName.end()) {
56             return Error();
57         }
58         return it->second;
59     }
60 
61     PropertyIdByNameSingleton(PropertyIdByNameSingleton const&) = delete;
62     void operator=(PropertyIdByNameSingleton const&) = delete;
63 
64   private:
65     std::unordered_map<std::string, int32_t> mPropertyIdByName;
66 
PropertyIdByNameSingleton()67     PropertyIdByNameSingleton() {
68         constexpr auto values = ndk::internal::enum_values<VehicleProperty>;
69         for (unsigned int i = 0; i < values.size(); i++) {
70             mPropertyIdByName.emplace(toString(values[i]), toInt(values[i]));
71         }
72     }
73 };
74 
75 class AreaByNameSingleton {
76   public:
getInstance()77     static AreaByNameSingleton& getInstance() {
78         static AreaByNameSingleton instance;
79         return instance;
80     }
81 
getArea(const std::string & name,int32_t propId) const82     Result<int32_t> getArea(const std::string& name, int32_t propId) const {
83         VehicleArea areaType = getPropArea(propId);
84 
85         auto mapIt = mAreaByNameByAreaType.find(areaType);
86         if (mapIt == mAreaByNameByAreaType.end()) {
87             return Error() << "Invalid area type for property ID: " << propIdToString(propId);
88         }
89 
90         const auto& areaByName = mapIt->second;
91         auto it = areaByName.find(name);
92         if (it == areaByName.end()) {
93             return Error() << "Invalid area name for property " << propIdToString(propId) << ": "
94                            << name;
95         }
96         return it->second;
97     }
98 
99     AreaByNameSingleton(AreaByNameSingleton const&) = delete;
100     void operator=(AreaByNameSingleton const&) = delete;
101 
102   private:
103     std::unordered_map<VehicleArea, std::unordered_map<std::string, int32_t>> mAreaByNameByAreaType;
104 
AreaByNameSingleton()105     AreaByNameSingleton() {
106         populateMap(VehicleArea::WINDOW, ndk::internal::enum_values<VehicleAreaWindow>);
107         populateMap(VehicleArea::MIRROR, ndk::internal::enum_values<VehicleAreaMirror>);
108         populateMap(VehicleArea::SEAT, ndk::internal::enum_values<VehicleAreaSeat>);
109         populateMap(VehicleArea::DOOR, ndk::internal::enum_values<VehicleAreaDoor>);
110         populateMap(VehicleArea::WHEEL, ndk::internal::enum_values<VehicleAreaWheel>);
111     }
112 
113     template <class T, std::size_t N>
populateMap(VehicleArea areaType,std::array<T,N> values)114     void populateMap(VehicleArea areaType, std::array<T, N> values) {
115         for (unsigned int i = 0; i < values.size(); i++) {
116             mAreaByNameByAreaType[areaType].emplace(toString(values[i]), toInt(values[i]));
117         }
118     }
119 };
120 
121 }  // namespace
122 
checkPropValue(const VehiclePropValue & value,const VehiclePropConfig * config)123 Result<void> checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) {
124     int32_t property = value.prop;
125     VehiclePropertyType type = getPropType(property);
126     switch (type) {
127         case VehiclePropertyType::BOOLEAN:
128             [[fallthrough]];
129         case VehiclePropertyType::INT32:
130             if (value.value.int32Values.size() != 1) {
131                 return Error() << "expect 1 int32Values for INT32 type";
132             }
133             break;
134         case VehiclePropertyType::INT32_VEC:
135             if (value.value.int32Values.size() < 1) {
136                 return Error() << "expect >=1 int32Values for INT32_VEC type";
137             }
138             break;
139         case VehiclePropertyType::INT64:
140             if (value.value.int64Values.size() != 1) {
141                 return Error() << "expect 1 int64Values for INT64 type";
142             }
143             break;
144         case VehiclePropertyType::INT64_VEC:
145             if (value.value.int64Values.size() < 1) {
146                 return Error() << "expect >=1 int64Values for INT64_VEC type";
147             }
148             break;
149         case VehiclePropertyType::FLOAT:
150             if (value.value.floatValues.size() != 1) {
151                 return Error() << "expect 1 floatValues for FLOAT type";
152             }
153             break;
154         case VehiclePropertyType::FLOAT_VEC:
155             if (value.value.floatValues.size() < 1) {
156                 return Error() << "expect >=1 floatValues for FLOAT_VEC type";
157             }
158             break;
159         case VehiclePropertyType::BYTES:
160             // We allow setting an empty bytes array.
161             break;
162         case VehiclePropertyType::STRING:
163             // We allow setting an empty string.
164             break;
165         case VehiclePropertyType::MIXED:
166             if (getPropGroup(property) == VehiclePropertyGroup::VENDOR) {
167                 // We only checks vendor mixed properties.
168                 return checkVendorMixedPropValue(value, config);
169             }
170             break;
171         default:
172             return Error() << "unknown property type: " << toInt(type);
173     }
174     return {};
175 }
176 
checkVendorMixedPropValue(const VehiclePropValue & value,const VehiclePropConfig * config)177 Result<void> checkVendorMixedPropValue(const VehiclePropValue& value,
178                                        const VehiclePropConfig* config) {
179     auto configArray = config->configArray;
180     // configArray[0], 1 indicates the property has a String value, we allow the string value to
181     // be empty.
182 
183     size_t int32Count = 0;
184     // configArray[1], 1 indicates the property has a Boolean value.
185     if (configArray[1] == 1) {
186         int32Count++;
187     }
188     // configArray[2], 1 indicates the property has an Integer value.
189     if (configArray[2] == 1) {
190         int32Count++;
191     }
192     // configArray[3], the number indicates the size of Integer[] in the property.
193     int32Count += static_cast<size_t>(configArray[3]);
194     size_t int32Size = value.value.int32Values.size();
195     if (int32Size != int32Count) {
196         return Error() << "invalid mixed property, got " << int32Size << " int32Values, expect "
197                        << int32Count;
198     }
199 
200     size_t int64Count = 0;
201     // configArray[4], 1 indicates the property has a Long value.
202     if (configArray[4] == 1) {
203         int64Count++;
204     }
205     // configArray[5], the number indicates the size of Long[] in the property.
206     int64Count += static_cast<size_t>(configArray[5]);
207     size_t int64Size = value.value.int64Values.size();
208     if (int64Size != int64Count) {
209         return Error() << "invalid mixed property, got " << int64Size << " int64Values, expect "
210                        << int64Count;
211     }
212 
213     size_t floatCount = 0;
214     // configArray[6], 1 indicates the property has a Float value.
215     if (configArray[6] == 1) {
216         floatCount++;
217     }
218     // configArray[7], the number indicates the size of Float[] in the property.
219     floatCount += static_cast<size_t>(configArray[7]);
220     size_t floatSize = value.value.floatValues.size();
221     if (floatSize != floatCount) {
222         return Error() << "invalid mixed property, got " << floatSize << " floatValues, expect "
223                        << floatCount;
224     }
225 
226     // configArray[8], the number indicates the size of byte[] in the property.
227     size_t byteSize = value.value.byteValues.size();
228     size_t byteCount = static_cast<size_t>(configArray[8]);
229     if (byteCount != 0 && byteSize != byteCount) {
230         return Error() << "invalid mixed property, got " << byteSize << " byteValues, expect "
231                        << byteCount;
232     }
233     return {};
234 }
235 
checkValueRange(const VehiclePropValue & value,const VehicleAreaConfig * areaConfig)236 Result<void> checkValueRange(const VehiclePropValue& value, const VehicleAreaConfig* areaConfig) {
237     if (areaConfig == nullptr) {
238         return {};
239     }
240     int32_t property = value.prop;
241     VehiclePropertyType type = getPropType(property);
242     switch (type) {
243         case VehiclePropertyType::INT32:
244             [[fallthrough]];
245         case VehiclePropertyType::INT32_VEC:
246             if (areaConfig->minInt32Value == 0 && areaConfig->maxInt32Value == 0) {
247                 break;
248             }
249             for (int32_t int32Value : value.value.int32Values) {
250                 if (int32Value < areaConfig->minInt32Value ||
251                     int32Value > areaConfig->maxInt32Value) {
252                     return Error() << "int32Value: " << int32Value
253                                    << " out of range, min: " << areaConfig->minInt32Value
254                                    << " max: " << areaConfig->maxInt32Value;
255                 }
256             }
257             break;
258         case VehiclePropertyType::INT64:
259             [[fallthrough]];
260         case VehiclePropertyType::INT64_VEC:
261             if (areaConfig->minInt64Value == 0 && areaConfig->maxInt64Value == 0) {
262                 break;
263             }
264             for (int64_t int64Value : value.value.int64Values) {
265                 if (int64Value < areaConfig->minInt64Value ||
266                     int64Value > areaConfig->maxInt64Value) {
267                     return Error() << "int64Value: " << int64Value
268                                    << " out of range, min: " << areaConfig->minInt64Value
269                                    << " max: " << areaConfig->maxInt64Value;
270                 }
271             }
272             break;
273         case VehiclePropertyType::FLOAT:
274             [[fallthrough]];
275         case VehiclePropertyType::FLOAT_VEC:
276             if (areaConfig->minFloatValue == 0.f && areaConfig->maxFloatValue == 0.f) {
277                 break;
278             }
279             for (float floatValue : value.value.floatValues) {
280                 if (floatValue < areaConfig->minFloatValue ||
281                     floatValue > areaConfig->maxFloatValue) {
282                     return Error() << "floatValue: " << floatValue
283                                    << " out of range, min: " << areaConfig->minFloatValue
284                                    << " max: " << areaConfig->maxFloatValue;
285                 }
286             }
287             break;
288         default:
289             // We don't check the rest of property types. Additional logic needs to be added if
290             // required in VehicleHardware, e.g. you might want to check the range for mixed
291             // property.
292             break;
293     }
294     return {};
295 }
296 
value() const297 StatusCode VhalError::value() const {
298     return mCode;
299 }
300 
print() const301 std::string VhalError::print() const {
302     return aidl::android::hardware::automotive::vehicle::toString(mCode);
303 }
304 
stringToPropId(const std::string & propName)305 Result<int32_t> stringToPropId(const std::string& propName) {
306     return PropertyIdByNameSingleton::getInstance().getPropertyId(propName);
307 }
308 
stringToArea(const std::string & areaName,int32_t propId)309 Result<int32_t> stringToArea(const std::string& areaName, int32_t propId) {
310     return AreaByNameSingleton::getInstance().getArea(areaName, propId);
311 }
312 
313 }  // namespace vehicle
314 }  // namespace automotive
315 }  // namespace hardware
316 }  // namespace android
317