1 /*
2  * Copyright (C) 2016 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 #define LOG_TAG "automotive.vehicle@2.0-impl"
18 
19 #include "VehicleHalManager.h"
20 
21 #include <cmath>
22 #include <fstream>
23 #include <unordered_set>
24 
25 #include <android-base/parsedouble.h>
26 #include <android-base/parseint.h>
27 #include <android-base/strings.h>
28 #include <android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h>
29 #include <android/log.h>
30 
31 #include <hwbinder/IPCThreadState.h>
32 #include <private/android_filesystem_config.h>
33 #include <utils/SystemClock.h>
34 
35 #include "VehicleUtils.h"
36 
37 namespace android {
38 namespace hardware {
39 namespace automotive {
40 namespace vehicle {
41 namespace V2_0 {
42 
43 using namespace std::placeholders;
44 
45 using ::android::base::EqualsIgnoreCase;
46 using ::android::hardware::hidl_handle;
47 using ::android::hardware::hidl_string;
48 
49 namespace {
50 
51 constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10);
52 
53 const VehiclePropValue kEmptyValue{};
54 
55 // A list of supported options for "--set" command.
56 const std::unordered_set<std::string> kSetPropOptions = {
57         // integer.
58         "-i",
59         // 64bit integer.
60         "-i64",
61         // float.
62         "-f",
63         // string.
64         "-s",
65         // bytes in hex format, e.g. 0xDEADBEEF.
66         "-b",
67         // Area id in integer.
68         "-a"};
69 
70 }  // namespace
71 
72 /**
73  * Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want
74  * to store in reusable object pool.
75  */
76 constexpr auto kMaxHidlVecOfVehiclePropValuePoolSize = 20;
77 
getAllPropConfigs(getAllPropConfigs_cb _hidl_cb)78 Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) {
79     ALOGI("getAllPropConfigs called");
80     hidl_vec<VehiclePropConfig> hidlConfigs;
81     auto& halConfig = mConfigIndex->getAllConfigs();
82 
83     hidlConfigs.setToExternal(
84             const_cast<VehiclePropConfig *>(halConfig.data()),
85             halConfig.size());
86 
87     _hidl_cb(hidlConfigs);
88 
89     return Void();
90 }
91 
getPropConfigs(const hidl_vec<int32_t> & properties,getPropConfigs_cb _hidl_cb)92 Return<void> VehicleHalManager::getPropConfigs(const hidl_vec<int32_t> &properties,
93                                                getPropConfigs_cb _hidl_cb) {
94     std::vector<VehiclePropConfig> configs;
95     for (size_t i = 0; i < properties.size(); i++) {
96         auto prop = properties[i];
97         if (mConfigIndex->hasConfig(prop)) {
98             configs.push_back(mConfigIndex->getConfig(prop));
99         } else {
100             ALOGW("Requested config for undefined property: 0x%x", prop);
101             _hidl_cb(StatusCode::INVALID_ARG, hidl_vec<VehiclePropConfig>());
102             return Void();
103         }
104     }
105 
106     _hidl_cb(StatusCode::OK, configs);
107 
108     return Void();
109 }
110 
get(const VehiclePropValue & requestedPropValue,get_cb _hidl_cb)111 Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
112     const auto* config = getPropConfigOrNull(requestedPropValue.prop);
113     if (config == nullptr) {
114         ALOGE("Failed to get value: config not found, property: 0x%x",
115               requestedPropValue.prop);
116         _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue);
117         return Void();
118     }
119 
120     if (!checkReadPermission(*config)) {
121         _hidl_cb(StatusCode::ACCESS_DENIED, kEmptyValue);
122         return Void();
123     }
124 
125     StatusCode status;
126     auto value = mHal->get(requestedPropValue, &status);
127     _hidl_cb(status, value.get() ? *value : kEmptyValue);
128 
129 
130     return Void();
131 }
132 
set(const VehiclePropValue & value)133 Return<StatusCode> VehicleHalManager::set(const VehiclePropValue &value) {
134     auto prop = value.prop;
135     const auto* config = getPropConfigOrNull(prop);
136     if (config == nullptr) {
137         ALOGE("Failed to set value: config not found, property: 0x%x", prop);
138         return StatusCode::INVALID_ARG;
139     }
140 
141     if (!checkWritePermission(*config)) {
142         return StatusCode::ACCESS_DENIED;
143     }
144 
145     handlePropertySetEvent(value);
146 
147     auto status = mHal->set(value);
148 
149     return Return<StatusCode>(status);
150 }
151 
subscribe(const sp<IVehicleCallback> & callback,const hidl_vec<SubscribeOptions> & options)152 Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback,
153                                                 const hidl_vec<SubscribeOptions> &options) {
154     hidl_vec<SubscribeOptions> verifiedOptions(options);
155     for (size_t i = 0; i < verifiedOptions.size(); i++) {
156         SubscribeOptions& ops = verifiedOptions[i];
157         auto prop = ops.propId;
158 
159         const auto* config = getPropConfigOrNull(prop);
160         if (config == nullptr) {
161             ALOGE("Failed to subscribe: config not found, property: 0x%x",
162                   prop);
163             return StatusCode::INVALID_ARG;
164         }
165 
166         if (ops.flags == SubscribeFlags::UNDEFINED) {
167             ALOGE("Failed to subscribe: undefined flag in options provided");
168             return StatusCode::INVALID_ARG;
169         }
170 
171         if (!isSubscribable(*config, ops.flags)) {
172             ALOGE("Failed to subscribe: property 0x%x is not subscribable",
173                   prop);
174             return StatusCode::INVALID_ARG;
175         }
176 
177         ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
178     }
179 
180     std::list<SubscribeOptions> updatedOptions;
181     auto res = mSubscriptionManager.addOrUpdateSubscription(getClientId(callback),
182                                                             callback, verifiedOptions,
183                                                             &updatedOptions);
184     if (StatusCode::OK != res) {
185         ALOGW("%s failed to subscribe, error code: %d", __func__, res);
186         return res;
187     }
188 
189     for (auto opt : updatedOptions) {
190         mHal->subscribe(opt.propId, opt.sampleRate);
191     }
192 
193     return StatusCode::OK;
194 }
195 
unsubscribe(const sp<IVehicleCallback> & callback,int32_t propId)196 Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback,
197                                                   int32_t propId) {
198     mSubscriptionManager.unsubscribe(getClientId(callback), propId);
199     return StatusCode::OK;
200 }
201 
debugDump(IVehicle::debugDump_cb _hidl_cb)202 Return<void> VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) {
203     _hidl_cb("");
204     return Void();
205 }
206 
debug(const hidl_handle & fd,const hidl_vec<hidl_string> & options)207 Return<void> VehicleHalManager::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
208     if (fd.getNativeHandle() == nullptr || fd->numFds == 0) {
209         ALOGE("Invalid parameters passed to debug()");
210         return Void();
211     }
212 
213     bool shouldContinue = mHal->dump(fd, options);
214     if (!shouldContinue) {
215         ALOGI("Dumped HAL only");
216         return Void();
217     }
218 
219     // Do our dump
220     cmdDump(fd->data[0], options);
221     return Void();
222 }
223 
cmdDump(int fd,const hidl_vec<hidl_string> & options)224 void VehicleHalManager::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
225     if (options.size() == 0) {
226         cmdDumpAllProperties(fd);
227         return;
228     }
229     std::string option = options[0];
230     if (EqualsIgnoreCase(option, "--help")) {
231         cmdHelp(fd);
232     } else if (EqualsIgnoreCase(option, "--list")) {
233         cmdListAllProperties(fd);
234     } else if (EqualsIgnoreCase(option, "--get")) {
235         cmdDumpSpecificProperties(fd, options);
236     } else if (EqualsIgnoreCase(option, "--set")) {
237         if (!checkCallerHasWritePermissions(fd)) {
238             dprintf(fd, "Caller does not have write permission\n");
239             return;
240         }
241         // Ignore the return value for this.
242         cmdSetOneProperty(fd, options);
243     } else {
244         dprintf(fd, "Invalid option: %s\n", option.c_str());
245     }
246 }
247 
checkCallerHasWritePermissions(int fd)248 bool VehicleHalManager::checkCallerHasWritePermissions(int fd) {
249     // Double check that's only called by root - it should be be blocked at the HIDL debug() level,
250     // but it doesn't hurt to make sure...
251     if (hardware::IPCThreadState::self()->getCallingUid() != AID_ROOT) {
252         dprintf(fd, "Must be root\n");
253         return false;
254     }
255     return true;
256 }
257 
checkArgumentsSize(int fd,const hidl_vec<hidl_string> & options,size_t minSize)258 bool VehicleHalManager::checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options,
259                                            size_t minSize) {
260     size_t size = options.size();
261     if (size >= minSize) {
262         return true;
263     }
264     dprintf(fd, "Invalid number of arguments: required at least %zu, got %zu\n", minSize, size);
265     return false;
266 }
267 
268 template <typename T>
safelyParseInt(int fd,int index,const std::string & s,T * out)269 bool VehicleHalManager::safelyParseInt(int fd, int index, const std::string& s, T* out) {
270     if (!android::base::ParseInt(s, out)) {
271         dprintf(fd, "non-integer argument at index %d: %s\n", index, s.c_str());
272         return false;
273     }
274     return true;
275 }
276 
safelyParseFloat(int fd,int index,const std::string & s,float * out)277 bool VehicleHalManager::safelyParseFloat(int fd, int index, const std::string& s, float* out) {
278     if (!android::base::ParseFloat(s, out)) {
279         dprintf(fd, "non-float argument at index %d: %s\n", index, s.c_str());
280         return false;
281     }
282     return true;
283 }
284 
cmdHelp(int fd) const285 void VehicleHalManager::cmdHelp(int fd) const {
286     dprintf(fd, "Usage: \n\n");
287     dprintf(fd, "[no args]: dumps (id and value) all supported properties \n");
288     dprintf(fd, "--help: shows this help\n");
289     dprintf(fd, "--list: lists the ids of all supported properties\n");
290     dprintf(fd, "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n");
291     dprintf(fd,
292             "--set <PROP> [-i INT_VALUE [INT_VALUE ...]] [-i64 INT64_VALUE [INT64_VALUE ...]] "
293             "[-f FLOAT_VALUE [FLOAT_VALUE ...]] [-s STR_VALUE] "
294             "[-b BYTES_VALUE] [-a AREA_ID] : sets the value of property PROP. "
295             "Notice that the string, bytes and area value can be set just once, while the other can"
296             " have multiple values (so they're used in the respective array), "
297             "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n");
298 }
299 
cmdListAllProperties(int fd) const300 void VehicleHalManager::cmdListAllProperties(int fd) const {
301     auto& halConfig = mConfigIndex->getAllConfigs();
302     size_t size = halConfig.size();
303     if (size == 0) {
304         dprintf(fd, "no properties to list\n");
305         return;
306     }
307     int i = 0;
308     dprintf(fd, "listing %zu properties\n", size);
309     for (const auto& config : halConfig) {
310         dprintf(fd, "%d: %d\n", ++i, config.prop);
311     }
312 }
313 
cmdDumpAllProperties(int fd)314 void VehicleHalManager::cmdDumpAllProperties(int fd) {
315     auto& halConfig = mConfigIndex->getAllConfigs();
316     size_t size = halConfig.size();
317     if (size == 0) {
318         dprintf(fd, "no properties to dump\n");
319         return;
320     }
321     int rowNumber = 0;
322     dprintf(fd, "dumping %zu properties\n", size);
323     for (auto& config : halConfig) {
324         cmdDumpOneProperty(fd, ++rowNumber, config);
325     }
326 }
327 
cmdDumpOneProperty(int fd,int rowNumber,const VehiclePropConfig & config)328 void VehicleHalManager::cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config) {
329     size_t numberAreas = config.areaConfigs.size();
330     if (numberAreas == 0) {
331         if (rowNumber > 0) {
332             dprintf(fd, "%d: ", rowNumber);
333         }
334         cmdDumpOneProperty(fd, config.prop, /* areaId= */ 0);
335         return;
336     }
337     for (size_t j = 0; j < numberAreas; ++j) {
338         if (rowNumber > 0) {
339             if (numberAreas > 1) {
340                 dprintf(fd, "%d/%zu: ", rowNumber, j);
341             } else {
342                 dprintf(fd, "%d: ", rowNumber);
343             }
344         }
345         cmdDumpOneProperty(fd, config.prop, config.areaConfigs[j].areaId);
346     }
347 }
348 
cmdDumpSpecificProperties(int fd,const hidl_vec<hidl_string> & options)349 void VehicleHalManager::cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options) {
350     if (!checkArgumentsSize(fd, options, 2)) return;
351 
352     // options[0] is the command itself...
353     int rowNumber = 0;
354     size_t size = options.size();
355     for (size_t i = 1; i < size; ++i) {
356         int prop;
357         if (!safelyParseInt(fd, i, options[i], &prop)) return;
358         const auto* config = getPropConfigOrNull(prop);
359         if (config == nullptr) {
360             dprintf(fd, "No property %d\n", prop);
361             continue;
362         }
363         if (size > 2) {
364             // Only show row number if there's more than 1
365             rowNumber++;
366         }
367         cmdDumpOneProperty(fd, rowNumber, *config);
368     }
369 }
370 
cmdDumpOneProperty(int fd,int32_t prop,int32_t areaId)371 void VehicleHalManager::cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId) {
372     VehiclePropValue input;
373     input.prop = prop;
374     input.areaId = areaId;
375     auto callback = [&fd, &prop](StatusCode status, const VehiclePropValue& output) {
376         if (status == StatusCode::OK) {
377             dprintf(fd, "%s\n", toString(output).c_str());
378         } else {
379             dprintf(fd, "Could not get property %d. Error: %s\n", prop, toString(status).c_str());
380         }
381     };
382 
383     StatusCode status;
384     auto value = mHal->get(input, &status);
385     callback(status, value.get() ? *value : kEmptyValue);
386 }
387 
cmdSetOneProperty(int fd,const hidl_vec<hidl_string> & options)388 bool VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
389     if (!checkArgumentsSize(fd, options, 4)) {
390         dprintf(fd, "Requires at least 4 options, see help\n");
391         return false;
392     }
393 
394     VehiclePropValue prop = {};
395     if (!parseSetPropOptions(fd, options, &prop)) {
396         return false;
397     }
398     ALOGD("Setting prop %s", toString(prop).c_str());
399 
400     // Do not use VehicleHalManager::set here because we don't want to check write permission.
401     // Caller should be able to use the debug interface to set read-only properties.
402     handlePropertySetEvent(prop);
403     auto status = mHal->set(prop);
404 
405     if (status == StatusCode::OK) {
406         dprintf(fd, "Set property %s\n", toString(prop).c_str());
407         return true;
408     }
409     dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(),
410             toString(status).c_str());
411     return false;
412 }
413 
init()414 void VehicleHalManager::init() {
415     ALOGI("VehicleHalManager::init");
416 
417     mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclePropValuePoolSize);
418 
419     mBatchingConsumer.run(&mEventQueue,
420                           kHalEventBatchingTimeWindow,
421                           std::bind(&VehicleHalManager::onBatchHalEvent,
422                                     this, _1));
423 
424     mHal->init(&mValueObjectPool,
425                std::bind(&VehicleHalManager::onHalEvent, this, _1),
426                std::bind(&VehicleHalManager::onHalPropertySetError, this,
427                          _1, _2, _3));
428 
429     // Initialize index with vehicle configurations received from VehicleHal.
430     auto supportedPropConfigs = mHal->listProperties();
431     mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs));
432 
433     std::vector<int32_t> supportedProperties(
434         supportedPropConfigs.size());
435     for (const auto& config : supportedPropConfigs) {
436         supportedProperties.push_back(config.prop);
437     }
438 }
439 
~VehicleHalManager()440 VehicleHalManager::~VehicleHalManager() {
441     mBatchingConsumer.requestStop();
442     mEventQueue.deactivate();
443     // We have to wait until consumer thread is fully stopped because it may
444     // be in a state of running callback (onBatchHalEvent).
445     mBatchingConsumer.waitStopped();
446     ALOGI("VehicleHalManager::dtor");
447 }
448 
onHalEvent(VehiclePropValuePtr v)449 void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) {
450     mEventQueue.push(std::move(v));
451 }
452 
onHalPropertySetError(StatusCode errorCode,int32_t property,int32_t areaId)453 void VehicleHalManager::onHalPropertySetError(StatusCode errorCode,
454                                               int32_t property,
455                                               int32_t areaId) {
456     const auto& clients =
457         mSubscriptionManager.getSubscribedClients(property, SubscribeFlags::EVENTS_FROM_CAR);
458 
459     for (const auto& client : clients) {
460         client->getCallback()->onPropertySetError(errorCode, property, areaId);
461     }
462 }
463 
onBatchHalEvent(const std::vector<VehiclePropValuePtr> & values)464 void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) {
465     const auto& clientValues =
466         mSubscriptionManager.distributeValuesToClients(values, SubscribeFlags::EVENTS_FROM_CAR);
467 
468     for (const HalClientValues& cv : clientValues) {
469         auto vecSize = cv.values.size();
470         hidl_vec<VehiclePropValue> vec;
471         if (vecSize < kMaxHidlVecOfVehiclePropValuePoolSize) {
472             vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize);
473         } else {
474             vec.resize(vecSize);
475         }
476 
477         int i = 0;
478         for (VehiclePropValue* pValue : cv.values) {
479             shallowCopy(&(vec)[i++], *pValue);
480         }
481         auto status = cv.client->getCallback()->onPropertyEvent(vec);
482         if (!status.isOk()) {
483             ALOGE("Failed to notify client %s, err: %s",
484                   toString(cv.client->getCallback()).c_str(),
485                   status.description().c_str());
486         }
487     }
488 }
489 
isSampleRateFixed(VehiclePropertyChangeMode mode)490 bool VehicleHalManager::isSampleRateFixed(VehiclePropertyChangeMode mode) {
491     return (mode & VehiclePropertyChangeMode::ON_CHANGE);
492 }
493 
checkSampleRate(const VehiclePropConfig & config,float sampleRate)494 float VehicleHalManager::checkSampleRate(const VehiclePropConfig &config,
495                                          float sampleRate) {
496     if (isSampleRateFixed(config.changeMode)) {
497         if (std::abs(sampleRate) > std::numeric_limits<float>::epsilon()) {
498             ALOGW("Sample rate is greater than zero for on change type. "
499                       "Ignoring it.");
500         }
501         return 0.0;
502     } else {
503         if (sampleRate > config.maxSampleRate) {
504             ALOGW("Sample rate %f is higher than max %f. Setting sampling rate "
505                       "to max.", sampleRate, config.maxSampleRate);
506             return config.maxSampleRate;
507         }
508         if (sampleRate < config.minSampleRate) {
509             ALOGW("Sample rate %f is lower than min %f. Setting sampling rate "
510                       "to min.", sampleRate, config.minSampleRate);
511             return config.minSampleRate;
512         }
513     }
514     return sampleRate;  // Provided sample rate was good, no changes.
515 }
516 
isSubscribable(const VehiclePropConfig & config,SubscribeFlags flags)517 bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config,
518                                        SubscribeFlags flags) {
519     bool isReadable = config.access & VehiclePropertyAccess::READ;
520 
521     if (!isReadable && (SubscribeFlags::EVENTS_FROM_CAR & flags)) {
522         ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop);
523         return false;
524     }
525     if (config.changeMode == VehiclePropertyChangeMode::STATIC) {
526         ALOGW("Cannot subscribe, property 0x%x is static", config.prop);
527         return false;
528     }
529     return true;
530 }
531 
checkWritePermission(const VehiclePropConfig & config) const532 bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config) const {
533     if (!(config.access & VehiclePropertyAccess::WRITE)) {
534         ALOGW("Property 0%x has no write access", config.prop);
535         return false;
536     } else {
537         return true;
538     }
539 }
540 
checkReadPermission(const VehiclePropConfig & config) const541 bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config) const {
542     if (!(config.access & VehiclePropertyAccess::READ)) {
543         ALOGW("Property 0%x has no read access", config.prop);
544         return false;
545     } else {
546         return true;
547     }
548 }
549 
handlePropertySetEvent(const VehiclePropValue & value)550 void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
551     auto clients =
552         mSubscriptionManager.getSubscribedClients(value.prop, SubscribeFlags::EVENTS_FROM_ANDROID);
553     for (const auto& client : clients) {
554         client->getCallback()->onPropertySet(value);
555     }
556 }
557 
getPropConfigOrNull(int32_t prop) const558 const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull(
559         int32_t prop) const {
560     return mConfigIndex->hasConfig(prop)
561            ? &mConfigIndex->getConfig(prop) : nullptr;
562 }
563 
onAllClientsUnsubscribed(int32_t propertyId)564 void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) {
565     mHal->unsubscribe(propertyId);
566 }
567 
getClientId(const sp<IVehicleCallback> & callback)568 ClientId VehicleHalManager::getClientId(const sp<IVehicleCallback>& callback) {
569     //TODO(b/32172906): rework this to get some kind of unique id for callback interface when this
570     // feature is ready in HIDL.
571 
572     if (callback->isRemote()) {
573         BpHwVehicleCallback* hwCallback = static_cast<BpHwVehicleCallback*>(callback.get());
574         return static_cast<ClientId>(reinterpret_cast<intptr_t>(hwCallback->onAsBinder()));
575     } else {
576         return static_cast<ClientId>(reinterpret_cast<intptr_t>(callback.get()));
577     }
578 }
579 
getOptionValues(const hidl_vec<hidl_string> & options,size_t * index)580 std::vector<std::string> VehicleHalManager::getOptionValues(const hidl_vec<hidl_string>& options,
581                                                             size_t* index) {
582     std::vector<std::string> values;
583     while (*index < options.size()) {
584         std::string option = options[*index];
585         if (kSetPropOptions.find(option) != kSetPropOptions.end()) {
586             return std::move(values);
587         }
588         values.push_back(option);
589         (*index)++;
590     }
591     return std::move(values);
592 }
593 
parseSetPropOptions(int fd,const hidl_vec<hidl_string> & options,VehiclePropValue * prop)594 bool VehicleHalManager::parseSetPropOptions(int fd, const hidl_vec<hidl_string>& options,
595                                             VehiclePropValue* prop) {
596     // Options format:
597     // --set PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...] [-b b1 b2...] [-a a]
598     size_t optionIndex = 1;
599     int propValue;
600     if (!safelyParseInt(fd, optionIndex, options[optionIndex], &propValue)) {
601         dprintf(fd, "property value: \"%s\" is not a valid int\n", options[optionIndex].c_str());
602         return false;
603     }
604     prop->prop = propValue;
605     prop->timestamp = elapsedRealtimeNano();
606     prop->status = VehiclePropertyStatus::AVAILABLE;
607     optionIndex++;
608     std::unordered_set<std::string> parsedOptions;
609 
610     while (optionIndex < options.size()) {
611         std::string type = options[optionIndex];
612         optionIndex++;
613         size_t currentIndex = optionIndex;
614         std::vector<std::string> values = getOptionValues(options, &optionIndex);
615         if (parsedOptions.find(type) != parsedOptions.end()) {
616             dprintf(fd, "duplicate \"%s\" options\n", type.c_str());
617             return false;
618         }
619         parsedOptions.insert(type);
620         if (EqualsIgnoreCase(type, "-i")) {
621             if (values.size() == 0) {
622                 dprintf(fd, "no values specified when using \"-i\"\n");
623                 return false;
624             }
625             prop->value.int32Values.resize(values.size());
626             for (size_t i = 0; i < values.size(); i++) {
627                 int32_t safeInt;
628                 if (!safelyParseInt(fd, currentIndex + i, values[i], &safeInt)) {
629                     dprintf(fd, "value: \"%s\" is not a valid int\n", values[i].c_str());
630                     return false;
631                 }
632                 prop->value.int32Values[i] = safeInt;
633             }
634         } else if (EqualsIgnoreCase(type, "-i64")) {
635             if (values.size() == 0) {
636                 dprintf(fd, "no values specified when using \"-i64\"\n");
637                 return false;
638             }
639             prop->value.int64Values.resize(values.size());
640             for (size_t i = 0; i < values.size(); i++) {
641                 int64_t safeInt;
642                 if (!safelyParseInt(fd, currentIndex + i, values[i], &safeInt)) {
643                     dprintf(fd, "value: \"%s\" is not a valid int64\n", values[i].c_str());
644                     return false;
645                 }
646                 prop->value.int64Values[i] = safeInt;
647             }
648         } else if (EqualsIgnoreCase(type, "-f")) {
649             if (values.size() == 0) {
650                 dprintf(fd, "no values specified when using \"-f\"\n");
651                 return false;
652             }
653             prop->value.floatValues.resize(values.size());
654             for (size_t i = 0; i < values.size(); i++) {
655                 float safeFloat;
656                 if (!safelyParseFloat(fd, currentIndex + i, values[i], &safeFloat)) {
657                     dprintf(fd, "value: \"%s\" is not a valid float\n", values[i].c_str());
658                     return false;
659                 }
660                 prop->value.floatValues[i] = safeFloat;
661             }
662         } else if (EqualsIgnoreCase(type, "-s")) {
663             if (values.size() != 1) {
664                 dprintf(fd, "expect exact one value when using \"-s\"\n");
665                 return false;
666             }
667             prop->value.stringValue = values[0];
668         } else if (EqualsIgnoreCase(type, "-b")) {
669             if (values.size() != 1) {
670                 dprintf(fd, "expect exact one value when using \"-b\"\n");
671                 return false;
672             }
673             std::vector<uint8_t> bytes;
674             if (!parseHexString(fd, values[0], &bytes)) {
675                 dprintf(fd, "value: \"%s\" is not a valid hex string\n", values[0].c_str());
676                 return false;
677             }
678             prop->value.bytes = bytes;
679         } else if (EqualsIgnoreCase(type, "-a")) {
680             if (values.size() != 1) {
681                 dprintf(fd, "expect exact one value when using \"-a\"\n");
682                 return false;
683             }
684             if (!safelyParseInt(fd, currentIndex, values[0], &(prop->areaId))) {
685                 dprintf(fd, "area ID: \"%s\" is not a valid int\n", values[0].c_str());
686                 return false;
687             }
688         } else {
689             dprintf(fd, "unknown option: %s\n", type.c_str());
690             return false;
691         }
692     }
693 
694     return true;
695 }
696 
parseHexString(int fd,const std::string & s,std::vector<uint8_t> * bytes)697 bool VehicleHalManager::parseHexString(int fd, const std::string& s, std::vector<uint8_t>* bytes) {
698     if (s.size() % 2 != 0) {
699         dprintf(fd, "invalid hex string: %s, should have even size\n", s.c_str());
700         return false;
701     }
702     if (strncmp(s.substr(0, 2).c_str(), "0x", 2)) {
703         dprintf(fd, "hex string should start with \"0x\", got %s\n", s.c_str());
704         return false;
705     }
706     std::string subs = s.substr(2);
707     std::transform(subs.begin(), subs.end(), subs.begin(),
708                    [](unsigned char c) { return std::tolower(c); });
709 
710     bool highDigit = true;
711     for (size_t i = 0; i < subs.size(); i++) {
712         char c = subs[i];
713         uint8_t v;
714         if (c >= '0' && c <= '9') {
715             v = c - '0';
716         } else if (c >= 'a' && c <= 'f') {
717             v = c - 'a' + 10;
718         } else {
719             dprintf(fd, "invalid character %c in hex string %s\n", c, subs.c_str());
720             return false;
721         }
722         if (highDigit) {
723             (*bytes).push_back(v * 16);
724         } else {
725             (*bytes)[bytes->size() - 1] += v;
726         }
727         highDigit = !highDigit;
728     }
729     return true;
730 }
731 
732 }  // namespace V2_0
733 }  // namespace vehicle
734 }  // namespace automotive
735 }  // namespace hardware
736 }  // namespace android
737