• 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::VehicleAreaConfig;
29 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
30 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
31 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
32 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
33 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
34 using ::android::base::Error;
35 using ::android::base::Result;
36 using ::ndk::ScopedAStatus;
37 
38 namespace {
39 
40 class PropertyIdByNameSingleton {
41   public:
getInstance()42     static PropertyIdByNameSingleton& getInstance() {
43         static PropertyIdByNameSingleton instance;
44         return instance;
45     }
46 
getPropertyId(const std::string & name)47     Result<int32_t> getPropertyId(const std::string& name) {
48         auto it = mPropertyIdByName.find(name);
49         if (it == mPropertyIdByName.end()) {
50             return Error();
51         }
52         return it->second;
53     }
54 
55     PropertyIdByNameSingleton(PropertyIdByNameSingleton const&) = delete;
56     void operator=(PropertyIdByNameSingleton const&) = delete;
57 
58   private:
59     std::unordered_map<std::string, int32_t> mPropertyIdByName;
60 
PropertyIdByNameSingleton()61     PropertyIdByNameSingleton() {
62         constexpr auto values = ndk::internal::enum_values<VehicleProperty>;
63         for (unsigned int i = 0; i < values.size(); i++) {
64             mPropertyIdByName.emplace(toString(values[i]), toInt(values[i]));
65         }
66     }
67 };
68 
69 }  // namespace
70 
checkPropValue(const VehiclePropValue & value,const VehiclePropConfig * config)71 Result<void> checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) {
72     int32_t property = value.prop;
73     VehiclePropertyType type = getPropType(property);
74     switch (type) {
75         case VehiclePropertyType::BOOLEAN:
76             [[fallthrough]];
77         case VehiclePropertyType::INT32:
78             if (value.value.int32Values.size() != 1) {
79                 return Error() << "expect 1 int32Values for INT32 type";
80             }
81             break;
82         case VehiclePropertyType::INT32_VEC:
83             if (value.value.int32Values.size() < 1) {
84                 return Error() << "expect >=1 int32Values for INT32_VEC type";
85             }
86             break;
87         case VehiclePropertyType::INT64:
88             if (value.value.int64Values.size() != 1) {
89                 return Error() << "expect 1 int64Values for INT64 type";
90             }
91             break;
92         case VehiclePropertyType::INT64_VEC:
93             if (value.value.int64Values.size() < 1) {
94                 return Error() << "expect >=1 int64Values for INT64_VEC type";
95             }
96             break;
97         case VehiclePropertyType::FLOAT:
98             if (value.value.floatValues.size() != 1) {
99                 return Error() << "expect 1 floatValues for FLOAT type";
100             }
101             break;
102         case VehiclePropertyType::FLOAT_VEC:
103             if (value.value.floatValues.size() < 1) {
104                 return Error() << "expect >=1 floatValues for FLOAT_VEC type";
105             }
106             break;
107         case VehiclePropertyType::BYTES:
108             // We allow setting an empty bytes array.
109             break;
110         case VehiclePropertyType::STRING:
111             // We allow setting an empty string.
112             break;
113         case VehiclePropertyType::MIXED:
114             if (getPropGroup(property) == VehiclePropertyGroup::VENDOR) {
115                 // We only checks vendor mixed properties.
116                 return checkVendorMixedPropValue(value, config);
117             }
118             break;
119         default:
120             return Error() << "unknown property type: " << toInt(type);
121     }
122     return {};
123 }
124 
checkVendorMixedPropValue(const VehiclePropValue & value,const VehiclePropConfig * config)125 Result<void> checkVendorMixedPropValue(const VehiclePropValue& value,
126                                        const VehiclePropConfig* config) {
127     auto configArray = config->configArray;
128     // configArray[0], 1 indicates the property has a String value, we allow the string value to
129     // be empty.
130 
131     size_t int32Count = 0;
132     // configArray[1], 1 indicates the property has a Boolean value.
133     if (configArray[1] == 1) {
134         int32Count++;
135     }
136     // configArray[2], 1 indicates the property has an Integer value.
137     if (configArray[2] == 1) {
138         int32Count++;
139     }
140     // configArray[3], the number indicates the size of Integer[] in the property.
141     int32Count += static_cast<size_t>(configArray[3]);
142     size_t int32Size = value.value.int32Values.size();
143     if (int32Size != int32Count) {
144         return Error() << "invalid mixed property, got " << int32Size << " int32Values, expect "
145                        << int32Count;
146     }
147 
148     size_t int64Count = 0;
149     // configArray[4], 1 indicates the property has a Long value.
150     if (configArray[4] == 1) {
151         int64Count++;
152     }
153     // configArray[5], the number indicates the size of Long[] in the property.
154     int64Count += static_cast<size_t>(configArray[5]);
155     size_t int64Size = value.value.int64Values.size();
156     if (int64Size != int64Count) {
157         return Error() << "invalid mixed property, got " << int64Size << " int64Values, expect "
158                        << int64Count;
159     }
160 
161     size_t floatCount = 0;
162     // configArray[6], 1 indicates the property has a Float value.
163     if (configArray[6] == 1) {
164         floatCount++;
165     }
166     // configArray[7], the number indicates the size of Float[] in the property.
167     floatCount += static_cast<size_t>(configArray[7]);
168     size_t floatSize = value.value.floatValues.size();
169     if (floatSize != floatCount) {
170         return Error() << "invalid mixed property, got " << floatSize << " floatValues, expect "
171                        << floatCount;
172     }
173 
174     // configArray[8], the number indicates the size of byte[] in the property.
175     size_t byteSize = value.value.byteValues.size();
176     size_t byteCount = static_cast<size_t>(configArray[8]);
177     if (byteCount != 0 && byteSize != byteCount) {
178         return Error() << "invalid mixed property, got " << byteSize << " byteValues, expect "
179                        << byteCount;
180     }
181     return {};
182 }
183 
checkValueRange(const VehiclePropValue & value,const VehicleAreaConfig * areaConfig)184 Result<void> checkValueRange(const VehiclePropValue& value, const VehicleAreaConfig* areaConfig) {
185     if (areaConfig == nullptr) {
186         return {};
187     }
188     int32_t property = value.prop;
189     VehiclePropertyType type = getPropType(property);
190     switch (type) {
191         case VehiclePropertyType::INT32:
192             [[fallthrough]];
193         case VehiclePropertyType::INT32_VEC:
194             if (areaConfig->minInt32Value == 0 && areaConfig->maxInt32Value == 0) {
195                 break;
196             }
197             for (int32_t int32Value : value.value.int32Values) {
198                 if (int32Value < areaConfig->minInt32Value ||
199                     int32Value > areaConfig->maxInt32Value) {
200                     return Error() << "int32Value: " << int32Value
201                                    << " out of range, min: " << areaConfig->minInt32Value
202                                    << " max: " << areaConfig->maxInt32Value;
203                 }
204             }
205             break;
206         case VehiclePropertyType::INT64:
207             [[fallthrough]];
208         case VehiclePropertyType::INT64_VEC:
209             if (areaConfig->minInt64Value == 0 && areaConfig->maxInt64Value == 0) {
210                 break;
211             }
212             for (int64_t int64Value : value.value.int64Values) {
213                 if (int64Value < areaConfig->minInt64Value ||
214                     int64Value > areaConfig->maxInt64Value) {
215                     return Error() << "int64Value: " << int64Value
216                                    << " out of range, min: " << areaConfig->minInt64Value
217                                    << " max: " << areaConfig->maxInt64Value;
218                 }
219             }
220             break;
221         case VehiclePropertyType::FLOAT:
222             [[fallthrough]];
223         case VehiclePropertyType::FLOAT_VEC:
224             if (areaConfig->minFloatValue == 0.f && areaConfig->maxFloatValue == 0.f) {
225                 break;
226             }
227             for (float floatValue : value.value.floatValues) {
228                 if (floatValue < areaConfig->minFloatValue ||
229                     floatValue > areaConfig->maxFloatValue) {
230                     return Error() << "floatValue: " << floatValue
231                                    << " out of range, min: " << areaConfig->minFloatValue
232                                    << " max: " << areaConfig->maxFloatValue;
233                 }
234             }
235             break;
236         default:
237             // We don't check the rest of property types. Additional logic needs to be added if
238             // required in VehicleHardware, e.g. you might want to check the range for mixed
239             // property.
240             break;
241     }
242     return {};
243 }
244 
value() const245 StatusCode VhalError::value() const {
246     return mCode;
247 }
248 
print() const249 std::string VhalError::print() const {
250     return aidl::android::hardware::automotive::vehicle::toString(mCode);
251 }
252 
stringToPropId(const std::string & propName)253 Result<int32_t> stringToPropId(const std::string& propName) {
254     return PropertyIdByNameSingleton::getInstance().getPropertyId(propName);
255 }
256 
257 }  // namespace vehicle
258 }  // namespace automotive
259 }  // namespace hardware
260 }  // namespace android
261