Merge "Support more types for set property cmd."
This commit is contained in:
commit
dddbe1565c
4 changed files with 422 additions and 116 deletions
|
@ -182,6 +182,7 @@ cc_test {
|
|||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libcutils",
|
||||
],
|
||||
header_libs: ["libbase_headers"],
|
||||
test_suites: ["general-tests"],
|
||||
|
|
|
@ -76,6 +76,9 @@ public:
|
|||
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
|
||||
|
||||
private:
|
||||
// Set unit test class as friend class to test private functions.
|
||||
friend class VehicleHalManagerTestHelper;
|
||||
|
||||
using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr;
|
||||
// Returns true if needs to call again shortly.
|
||||
using RetriableAction = std::function<bool()>;
|
||||
|
@ -105,14 +108,20 @@ public:
|
|||
void cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId);
|
||||
void cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config);
|
||||
|
||||
bool cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options);
|
||||
|
||||
static bool checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options, size_t minSize);
|
||||
static bool checkCallerHasWritePermissions(int fd);
|
||||
static bool safelyParseInt(int fd, int index, std::string s, int* out);
|
||||
template <typename T>
|
||||
static bool safelyParseInt(int fd, int index, const std::string& s, T* out);
|
||||
static bool safelyParseFloat(int fd, int index, const std::string& s, float* out);
|
||||
// Parses "s" as a hex string and populate "*bytes". The hex string must be in the format of
|
||||
// valid hex format, e.g. "0xABCD".
|
||||
static bool parseHexString(int fd, const std::string& s, std::vector<uint8_t>* bytes);
|
||||
void cmdHelp(int fd) const;
|
||||
void cmdListAllProperties(int fd) const;
|
||||
void cmdDumpAllProperties(int fd);
|
||||
void cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options);
|
||||
void cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options);
|
||||
|
||||
static bool isSubscribable(const VehiclePropConfig& config,
|
||||
SubscribeFlags flags);
|
||||
|
@ -120,7 +129,18 @@ public:
|
|||
static float checkSampleRate(const VehiclePropConfig& config,
|
||||
float sampleRate);
|
||||
static ClientId getClientId(const sp<IVehicleCallback>& callback);
|
||||
private:
|
||||
|
||||
// Parses the cmdline options for "--set" command. "*prop" would be populated with the
|
||||
// the properties to be set. Returns true when the cmdline options are valid, false otherwise.
|
||||
static bool parseSetPropOptions(int fd, const hidl_vec<hidl_string>& options,
|
||||
VehiclePropValue* prop);
|
||||
// Parses the options and get the values for the current option specified by "*index". "*index"
|
||||
// would advance to the next option field (e.g., the next "-f"). Returns a list of values for
|
||||
// the current option.
|
||||
static std::vector<std::string> getOptionValues(const hidl_vec<hidl_string>& options,
|
||||
size_t* index);
|
||||
|
||||
private:
|
||||
VehicleHal* mHal;
|
||||
std::unique_ptr<VehiclePropConfigIndex> mConfigIndex;
|
||||
SubscriptionManager mSubscriptionManager;
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <android-base/parsedouble.h>
|
||||
#include <android-base/parseint.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h>
|
||||
|
@ -44,15 +46,34 @@ using ::android::base::EqualsIgnoreCase;
|
|||
using ::android::hardware::hidl_handle;
|
||||
using ::android::hardware::hidl_string;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10);
|
||||
|
||||
const VehiclePropValue kEmptyValue{};
|
||||
|
||||
// A list of supported options for "--set" command.
|
||||
const std::unordered_set<std::string> kSetPropOptions = {
|
||||
// integer.
|
||||
"-i",
|
||||
// 64bit integer.
|
||||
"-i64",
|
||||
// float.
|
||||
"-f",
|
||||
// string.
|
||||
"-s",
|
||||
// bytes in hex format, e.g. 0xDEADBEEF.
|
||||
"-b",
|
||||
// Area id in integer.
|
||||
"-a"};
|
||||
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want
|
||||
* to store in reusable object pool.
|
||||
*/
|
||||
constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20;
|
||||
constexpr auto kMaxHidlVecOfVehiclePropValuePoolSize = 20;
|
||||
|
||||
Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) {
|
||||
ALOGI("getAllPropConfigs called");
|
||||
|
@ -213,6 +234,11 @@ void VehicleHalManager::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
|
|||
} else if (EqualsIgnoreCase(option, "--get")) {
|
||||
cmdDumpSpecificProperties(fd, options);
|
||||
} else if (EqualsIgnoreCase(option, "--set")) {
|
||||
if (!checkCallerHasWritePermissions(fd)) {
|
||||
dprintf(fd, "Caller does not have write permission\n");
|
||||
return;
|
||||
}
|
||||
// Ignore the return value for this.
|
||||
cmdSetOneProperty(fd, options);
|
||||
} else {
|
||||
dprintf(fd, "Invalid option: %s\n", option.c_str());
|
||||
|
@ -239,7 +265,8 @@ bool VehicleHalManager::checkArgumentsSize(int fd, const hidl_vec<hidl_string>&
|
|||
return false;
|
||||
}
|
||||
|
||||
bool VehicleHalManager::safelyParseInt(int fd, int index, std::string s, int* out) {
|
||||
template <typename T>
|
||||
bool VehicleHalManager::safelyParseInt(int fd, int index, const std::string& s, T* out) {
|
||||
if (!android::base::ParseInt(s, out)) {
|
||||
dprintf(fd, "non-integer argument at index %d: %s\n", index, s.c_str());
|
||||
return false;
|
||||
|
@ -247,19 +274,27 @@ bool VehicleHalManager::safelyParseInt(int fd, int index, std::string s, int* ou
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VehicleHalManager::safelyParseFloat(int fd, int index, const std::string& s, float* out) {
|
||||
if (!android::base::ParseFloat(s, out)) {
|
||||
dprintf(fd, "non-float argument at index %d: %s\n", index, s.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VehicleHalManager::cmdHelp(int fd) const {
|
||||
dprintf(fd, "Usage: \n\n");
|
||||
dprintf(fd, "[no args]: dumps (id and value) all supported properties \n");
|
||||
dprintf(fd, "--help: shows this help\n");
|
||||
dprintf(fd, "--list: lists the ids of all supported properties\n");
|
||||
dprintf(fd, "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n");
|
||||
// TODO: support other formats (int64, float, bytes)
|
||||
dprintf(fd,
|
||||
"--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>] [a AREA_ID] : sets the value of "
|
||||
"property PROP, using arbitrary number of key/value parameters (i for int32, "
|
||||
"s for string) and an optional area.\n"
|
||||
"Notice that the string value can be set just once, while the other can have multiple "
|
||||
"values (so they're used in the respective array)\n");
|
||||
"--set <PROP> [-i INT_VALUE [INT_VALUE ...]] [-i64 INT64_VALUE [INT64_VALUE ...]] "
|
||||
"[-f FLOAT_VALUE [FLOAT_VALUE ...]] [-s STR_VALUE] "
|
||||
"[-b BYTES_VALUE] [-a AREA_ID] : sets the value of property PROP. "
|
||||
"Notice that the string, bytes and area value can be set just once, while the other can"
|
||||
" have multiple values (so they're used in the respective array), "
|
||||
"BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n");
|
||||
}
|
||||
|
||||
void VehicleHalManager::cmdListAllProperties(int fd) const {
|
||||
|
@ -337,102 +372,49 @@ void VehicleHalManager::cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId)
|
|||
VehiclePropValue input;
|
||||
input.prop = prop;
|
||||
input.areaId = areaId;
|
||||
auto callback = [&](StatusCode status, const VehiclePropValue& output) {
|
||||
auto callback = [&fd, &prop](StatusCode status, const VehiclePropValue& output) {
|
||||
if (status == StatusCode::OK) {
|
||||
dprintf(fd, "%s\n", toString(output).c_str());
|
||||
} else {
|
||||
dprintf(fd, "Could not get property %d. Error: %s\n", prop, toString(status).c_str());
|
||||
}
|
||||
};
|
||||
get(input, callback);
|
||||
|
||||
StatusCode status;
|
||||
auto value = mHal->get(input, &status);
|
||||
callback(status, value.get() ? *value : kEmptyValue);
|
||||
}
|
||||
|
||||
void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
|
||||
if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return;
|
||||
|
||||
size_t size = options.size();
|
||||
|
||||
// Syntax is --set PROP Type1 Value1 TypeN ValueN, so number of arguments must be even
|
||||
if (size % 2 != 0) {
|
||||
dprintf(fd, "must pass even number of arguments (passed %zu)\n", size);
|
||||
return;
|
||||
bool VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
|
||||
if (!checkArgumentsSize(fd, options, 4)) {
|
||||
dprintf(fd, "Requires at least 4 options, see help\n");
|
||||
return false;
|
||||
}
|
||||
int numberValues = (size - 2) / 2;
|
||||
|
||||
VehiclePropValue prop;
|
||||
if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return;
|
||||
prop.timestamp = elapsedRealtimeNano();
|
||||
prop.status = VehiclePropertyStatus::AVAILABLE;
|
||||
|
||||
// First pass: calculate sizes
|
||||
int sizeInt32 = 0;
|
||||
int stringIndex = 0;
|
||||
int areaIndex = 0;
|
||||
for (int i = 2, kv = 1; kv <= numberValues; kv++) {
|
||||
// iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
|
||||
std::string type = options[i];
|
||||
std::string value = options[i + 1];
|
||||
if (EqualsIgnoreCase(type, "i")) {
|
||||
sizeInt32++;
|
||||
} else if (EqualsIgnoreCase(type, "s")) {
|
||||
if (stringIndex != 0) {
|
||||
dprintf(fd,
|
||||
"defining string value (%s) again at index %d (already defined at %d=%s"
|
||||
")\n",
|
||||
value.c_str(), i, stringIndex, options[stringIndex + 1].c_str());
|
||||
return;
|
||||
}
|
||||
stringIndex = i;
|
||||
} else if (EqualsIgnoreCase(type, "a")) {
|
||||
if (areaIndex != 0) {
|
||||
dprintf(fd,
|
||||
"defining area value (%s) again at index %d (already defined at %d=%s"
|
||||
")\n",
|
||||
value.c_str(), i, areaIndex, options[areaIndex + 1].c_str());
|
||||
return;
|
||||
}
|
||||
areaIndex = i;
|
||||
} else {
|
||||
dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i);
|
||||
return;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
prop.value.int32Values.resize(sizeInt32);
|
||||
|
||||
// Second pass: populate it
|
||||
int indexInt32 = 0;
|
||||
for (int i = 2, kv = 1; kv <= numberValues; kv++) {
|
||||
// iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
|
||||
int valueIndex = i + 1;
|
||||
std::string type = options[i];
|
||||
std::string value = options[valueIndex];
|
||||
if (EqualsIgnoreCase(type, "i")) {
|
||||
int safeInt;
|
||||
if (!safelyParseInt(fd, valueIndex, value, &safeInt)) return;
|
||||
prop.value.int32Values[indexInt32++] = safeInt;
|
||||
} else if (EqualsIgnoreCase(type, "s")) {
|
||||
prop.value.stringValue = value;
|
||||
} else if (EqualsIgnoreCase(type, "a")) {
|
||||
if (!safelyParseInt(fd, valueIndex, value, &prop.areaId)) return;
|
||||
}
|
||||
i += 2;
|
||||
VehiclePropValue prop = {};
|
||||
if (!parseSetPropOptions(fd, options, &prop)) {
|
||||
return false;
|
||||
}
|
||||
ALOGD("Setting prop %s", toString(prop).c_str());
|
||||
auto status = set(prop);
|
||||
|
||||
// Do not use VehicleHalManager::set here because we don't want to check write permission.
|
||||
// Caller should be able to use the debug interface to set read-only properties.
|
||||
handlePropertySetEvent(prop);
|
||||
auto status = mHal->set(prop);
|
||||
|
||||
if (status == StatusCode::OK) {
|
||||
dprintf(fd, "Set property %s\n", toString(prop).c_str());
|
||||
} else {
|
||||
dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(),
|
||||
toString(status).c_str());
|
||||
return true;
|
||||
}
|
||||
dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(),
|
||||
toString(status).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void VehicleHalManager::init() {
|
||||
ALOGI("VehicleHalManager::init");
|
||||
|
||||
mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize);
|
||||
|
||||
mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclePropValuePoolSize);
|
||||
|
||||
mBatchingConsumer.run(&mEventQueue,
|
||||
kHalEventBatchingTimeWindow,
|
||||
|
@ -486,7 +468,7 @@ void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>&
|
|||
for (const HalClientValues& cv : clientValues) {
|
||||
auto vecSize = cv.values.size();
|
||||
hidl_vec<VehiclePropValue> vec;
|
||||
if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) {
|
||||
if (vecSize < kMaxHidlVecOfVehiclePropValuePoolSize) {
|
||||
vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize);
|
||||
} else {
|
||||
vec.resize(vecSize);
|
||||
|
@ -595,6 +577,158 @@ ClientId VehicleHalManager::getClientId(const sp<IVehicleCallback>& callback) {
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> VehicleHalManager::getOptionValues(const hidl_vec<hidl_string>& options,
|
||||
size_t* index) {
|
||||
std::vector<std::string> values;
|
||||
while (*index < options.size()) {
|
||||
std::string option = options[*index];
|
||||
if (kSetPropOptions.find(option) != kSetPropOptions.end()) {
|
||||
return std::move(values);
|
||||
}
|
||||
values.push_back(option);
|
||||
(*index)++;
|
||||
}
|
||||
return std::move(values);
|
||||
}
|
||||
|
||||
bool VehicleHalManager::parseSetPropOptions(int fd, const hidl_vec<hidl_string>& options,
|
||||
VehiclePropValue* prop) {
|
||||
// Options format:
|
||||
// --set PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...] [-b b1 b2...] [-a a]
|
||||
size_t optionIndex = 1;
|
||||
int propValue;
|
||||
if (!safelyParseInt(fd, optionIndex, options[optionIndex], &propValue)) {
|
||||
dprintf(fd, "property value: \"%s\" is not a valid int\n", options[optionIndex].c_str());
|
||||
return false;
|
||||
}
|
||||
prop->prop = propValue;
|
||||
prop->timestamp = elapsedRealtimeNano();
|
||||
prop->status = VehiclePropertyStatus::AVAILABLE;
|
||||
optionIndex++;
|
||||
std::unordered_set<std::string> parsedOptions;
|
||||
|
||||
while (optionIndex < options.size()) {
|
||||
std::string type = options[optionIndex];
|
||||
optionIndex++;
|
||||
size_t currentIndex = optionIndex;
|
||||
std::vector<std::string> values = getOptionValues(options, &optionIndex);
|
||||
if (parsedOptions.find(type) != parsedOptions.end()) {
|
||||
dprintf(fd, "duplicate \"%s\" options\n", type.c_str());
|
||||
return false;
|
||||
}
|
||||
parsedOptions.insert(type);
|
||||
if (EqualsIgnoreCase(type, "-i")) {
|
||||
if (values.size() == 0) {
|
||||
dprintf(fd, "no values specified when using \"-i\"\n");
|
||||
return false;
|
||||
}
|
||||
prop->value.int32Values.resize(values.size());
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
int32_t safeInt;
|
||||
if (!safelyParseInt(fd, currentIndex + i, values[i], &safeInt)) {
|
||||
dprintf(fd, "value: \"%s\" is not a valid int\n", values[i].c_str());
|
||||
return false;
|
||||
}
|
||||
prop->value.int32Values[i] = safeInt;
|
||||
}
|
||||
} else if (EqualsIgnoreCase(type, "-i64")) {
|
||||
if (values.size() == 0) {
|
||||
dprintf(fd, "no values specified when using \"-i64\"\n");
|
||||
return false;
|
||||
}
|
||||
prop->value.int64Values.resize(values.size());
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
int64_t safeInt;
|
||||
if (!safelyParseInt(fd, currentIndex + i, values[i], &safeInt)) {
|
||||
dprintf(fd, "value: \"%s\" is not a valid int64\n", values[i].c_str());
|
||||
return false;
|
||||
}
|
||||
prop->value.int64Values[i] = safeInt;
|
||||
}
|
||||
} else if (EqualsIgnoreCase(type, "-f")) {
|
||||
if (values.size() == 0) {
|
||||
dprintf(fd, "no values specified when using \"-f\"\n");
|
||||
return false;
|
||||
}
|
||||
prop->value.floatValues.resize(values.size());
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
float safeFloat;
|
||||
if (!safelyParseFloat(fd, currentIndex + i, values[i], &safeFloat)) {
|
||||
dprintf(fd, "value: \"%s\" is not a valid float\n", values[i].c_str());
|
||||
return false;
|
||||
}
|
||||
prop->value.floatValues[i] = safeFloat;
|
||||
}
|
||||
} else if (EqualsIgnoreCase(type, "-s")) {
|
||||
if (values.size() != 1) {
|
||||
dprintf(fd, "expect exact one value when using \"-s\"\n");
|
||||
return false;
|
||||
}
|
||||
prop->value.stringValue = values[0];
|
||||
} else if (EqualsIgnoreCase(type, "-b")) {
|
||||
if (values.size() != 1) {
|
||||
dprintf(fd, "expect exact one value when using \"-b\"\n");
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> bytes;
|
||||
if (!parseHexString(fd, values[0], &bytes)) {
|
||||
dprintf(fd, "value: \"%s\" is not a valid hex string\n", values[0].c_str());
|
||||
return false;
|
||||
}
|
||||
prop->value.bytes = bytes;
|
||||
} else if (EqualsIgnoreCase(type, "-a")) {
|
||||
if (values.size() != 1) {
|
||||
dprintf(fd, "expect exact one value when using \"-a\"\n");
|
||||
return false;
|
||||
}
|
||||
if (!safelyParseInt(fd, currentIndex, values[0], &(prop->areaId))) {
|
||||
dprintf(fd, "area ID: \"%s\" is not a valid int\n", values[0].c_str());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
dprintf(fd, "unknown option: %s\n", type.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VehicleHalManager::parseHexString(int fd, const std::string& s, std::vector<uint8_t>* bytes) {
|
||||
if (s.size() % 2 != 0) {
|
||||
dprintf(fd, "invalid hex string: %s, should have even size\n", s.c_str());
|
||||
return false;
|
||||
}
|
||||
if (strncmp(s.substr(0, 2).c_str(), "0x", 2)) {
|
||||
dprintf(fd, "hex string should start with \"0x\", got %s\n", s.c_str());
|
||||
return false;
|
||||
}
|
||||
std::string subs = s.substr(2);
|
||||
std::transform(subs.begin(), subs.end(), subs.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
|
||||
bool highDigit = true;
|
||||
for (size_t i = 0; i < subs.size(); i++) {
|
||||
char c = subs[i];
|
||||
uint8_t v;
|
||||
if (c >= '0' && c <= '9') {
|
||||
v = c - '0';
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
v = c - 'a' + 10;
|
||||
} else {
|
||||
dprintf(fd, "invalid character %c in hex string %s\n", c, subs.c_str());
|
||||
return false;
|
||||
}
|
||||
if (highDigit) {
|
||||
(*bytes).push_back(v * 16);
|
||||
} else {
|
||||
(*bytes)[bytes->size() - 1] += v;
|
||||
}
|
||||
highDigit = !highDigit;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace V2_0
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <android-base/macros.h>
|
||||
#include <cutils/native_handle.h>
|
||||
#include <utils/SystemClock.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
@ -32,6 +33,18 @@ namespace automotive {
|
|||
namespace vehicle {
|
||||
namespace V2_0 {
|
||||
|
||||
// A simple helper class to expose 'cmdSetOneProperty' to the unit tests.
|
||||
class VehicleHalManagerTestHelper {
|
||||
public:
|
||||
VehicleHalManagerTestHelper(VehicleHalManager* manager) { mManager = manager; }
|
||||
bool cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
|
||||
return mManager->cmdSetOneProperty(fd, options);
|
||||
}
|
||||
|
||||
public:
|
||||
VehicleHalManager* mManager;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
@ -57,33 +70,21 @@ public:
|
|||
auto property = static_cast<VehicleProperty>(requestedPropValue.prop);
|
||||
int32_t areaId = requestedPropValue.areaId;
|
||||
|
||||
switch (property) {
|
||||
case VehicleProperty::INFO_MAKE:
|
||||
pValue = getValuePool()->obtainString(kCarMake);
|
||||
break;
|
||||
case VehicleProperty::INFO_FUEL_CAPACITY:
|
||||
if (fuelCapacityAttemptsLeft-- > 0) {
|
||||
// Emulate property not ready yet.
|
||||
*outStatus = StatusCode::TRY_AGAIN;
|
||||
} else {
|
||||
pValue = getValuePool()->obtainFloat(42.42);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (requestedPropValue.prop == kCustomComplexProperty) {
|
||||
pValue = getValuePool()->obtainComplex();
|
||||
pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 };
|
||||
pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 };
|
||||
pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 };
|
||||
pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 };
|
||||
pValue->value.stringValue = kCarMake;
|
||||
break;
|
||||
}
|
||||
auto key = makeKey(toInt(property), areaId);
|
||||
if (mValues.count(key) == 0) {
|
||||
ALOGW("");
|
||||
}
|
||||
pValue = getValuePool()->obtain(mValues[key]);
|
||||
if (property == VehicleProperty::INFO_FUEL_CAPACITY) {
|
||||
if (fuelCapacityAttemptsLeft-- > 0) {
|
||||
// Emulate property not ready yet.
|
||||
*outStatus = StatusCode::TRY_AGAIN;
|
||||
} else {
|
||||
pValue = getValuePool()->obtainFloat(42.42);
|
||||
}
|
||||
} else {
|
||||
auto key = makeKey(requestedPropValue);
|
||||
if (mValues.count(key) == 0) {
|
||||
ALOGW("key not found\n");
|
||||
*outStatus = StatusCode::INVALID_ARG;
|
||||
return pValue;
|
||||
}
|
||||
pValue = getValuePool()->obtain(mValues[key]);
|
||||
}
|
||||
|
||||
if (*outStatus == StatusCode::OK && pValue.get() != nullptr) {
|
||||
|
@ -100,7 +101,6 @@ public:
|
|||
&& mirrorFoldAttemptsLeft-- > 0) {
|
||||
return StatusCode::TRY_AGAIN;
|
||||
}
|
||||
|
||||
mValues[makeKey(propValue)] = propValue;
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
@ -181,6 +181,18 @@ public:
|
|||
actualStatusCode = refStatus;
|
||||
}
|
||||
|
||||
MockedVehicleHal::VehiclePropValuePtr getComplexProperty() {
|
||||
auto pValue = objectPool->obtainComplex();
|
||||
pValue->prop = kCustomComplexProperty;
|
||||
pValue->areaId = 0;
|
||||
pValue->value.int32Values = hidl_vec<int32_t>{10, 20};
|
||||
pValue->value.int64Values = hidl_vec<int64_t>{30, 40};
|
||||
pValue->value.floatValues = hidl_vec<float_t>{1.1, 2.2};
|
||||
pValue->value.bytes = hidl_vec<uint8_t>{1, 2, 3};
|
||||
pValue->value.stringValue = kCarMake;
|
||||
return pValue;
|
||||
}
|
||||
|
||||
public:
|
||||
VehiclePropValue actualValue;
|
||||
StatusCode actualStatusCode;
|
||||
|
@ -308,6 +320,8 @@ TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) {
|
|||
}
|
||||
|
||||
TEST_F(VehicleHalManagerTest, get_Complex) {
|
||||
ASSERT_EQ(StatusCode::OK, hal->set(*getComplexProperty().get()));
|
||||
|
||||
invokeGet(kCustomComplexProperty, 0);
|
||||
|
||||
ASSERT_EQ(StatusCode::OK, actualStatusCode);
|
||||
|
@ -334,6 +348,11 @@ TEST_F(VehicleHalManagerTest, get_Complex) {
|
|||
}
|
||||
|
||||
TEST_F(VehicleHalManagerTest, get_StaticString) {
|
||||
auto pValue = objectPool->obtainString(kCarMake);
|
||||
pValue->prop = toInt(VehicleProperty::INFO_MAKE);
|
||||
pValue->areaId = 0;
|
||||
ASSERT_EQ(StatusCode::OK, hal->set(*pValue.get()));
|
||||
|
||||
invokeGet(toInt(VehicleProperty::INFO_MAKE), 0);
|
||||
|
||||
ASSERT_EQ(StatusCode::OK, actualStatusCode);
|
||||
|
@ -458,6 +477,138 @@ TEST(HalClientVectorTest, basic) {
|
|||
ASSERT_TRUE(clients.isEmpty());
|
||||
}
|
||||
|
||||
TEST_F(VehicleHalManagerTest, debug) {
|
||||
hidl_handle fd = {};
|
||||
fd.setTo(native_handle_create(/*numFds=*/1, /*numInts=*/0), /*shouldOwn=*/true);
|
||||
|
||||
// Because debug function returns void, so no way to check return value.
|
||||
manager->debug(fd, {});
|
||||
manager->debug(fd, {"--help"});
|
||||
manager->debug(fd, {"--list"});
|
||||
manager->debug(fd, {"--get"});
|
||||
manager->debug(fd, {"--set"});
|
||||
manager->debug(fd, {"invalid"});
|
||||
}
|
||||
|
||||
struct SetPropTestCase {
|
||||
std::string test_name;
|
||||
const hidl_vec<hidl_string> configs;
|
||||
bool success;
|
||||
};
|
||||
|
||||
class VehicleHalManagerSetPropTest : public VehicleHalManagerTest,
|
||||
public testing::WithParamInterface<SetPropTestCase> {};
|
||||
|
||||
TEST_P(VehicleHalManagerSetPropTest, cmdSetOneProperty) {
|
||||
const SetPropTestCase& tc = GetParam();
|
||||
VehicleHalManagerTestHelper helper(manager.get());
|
||||
ASSERT_EQ(tc.success, helper.cmdSetOneProperty(STDERR_FILENO, tc.configs));
|
||||
}
|
||||
|
||||
std::vector<SetPropTestCase> GenSetPropParams() {
|
||||
char infoMakeProperty[100] = {};
|
||||
snprintf(infoMakeProperty, sizeof(infoMakeProperty), "%d", toInt(VehicleProperty::INFO_MAKE));
|
||||
return {
|
||||
{"success_set_string", {"--set", infoMakeProperty, "-s", kCarMake}, true},
|
||||
{"success_set_bytes", {"--set", infoMakeProperty, "-b", "0xdeadbeef"}, true},
|
||||
{"success_set_bytes_caps", {"--set", infoMakeProperty, "-b", "0xDEADBEEF"}, true},
|
||||
{"success_set_int", {"--set", infoMakeProperty, "-i", "2147483647"}, true},
|
||||
{"success_set_ints",
|
||||
{"--set", infoMakeProperty, "-i", "2147483647", "0", "-2147483648"},
|
||||
true},
|
||||
{"success_set_int64",
|
||||
{"--set", infoMakeProperty, "-i64", "-9223372036854775808"},
|
||||
true},
|
||||
{"success_set_int64s",
|
||||
{"--set", infoMakeProperty, "-i64", "-9223372036854775808", "0",
|
||||
"9223372036854775807"},
|
||||
true},
|
||||
{"success_set_float", {"--set", infoMakeProperty, "-f", "1.175494351E-38"}, true},
|
||||
{"success_set_floats",
|
||||
{"--set", infoMakeProperty, "-f", "-3.402823466E+38", "0", "3.402823466E+38"},
|
||||
true},
|
||||
{"success_set_area", {"--set", infoMakeProperty, "-a", "2147483647"}, true},
|
||||
{"fail_no_options", {}, false},
|
||||
{"fail_less_than_4_options", {"--set", infoMakeProperty, "-i"}, false},
|
||||
{"fail_unknown_options", {"--set", infoMakeProperty, "-s", kCarMake, "-abcd"}, false},
|
||||
{"fail_invalid_property", {"--set", "not valid", "-s", kCarMake}, false},
|
||||
{"fail_duplicate_string",
|
||||
{"--set", infoMakeProperty, "-s", kCarMake, "-s", kCarMake},
|
||||
false},
|
||||
{"fail_multiple_strings", {"--set", infoMakeProperty, "-s", kCarMake, kCarMake}, false},
|
||||
{"fail_no_string_value", {"--set", infoMakeProperty, "-s", "-a", "1234"}, false},
|
||||
{"fail_duplicate_bytes",
|
||||
{"--set", infoMakeProperty, "-b", "0xdeadbeef", "-b", "0xdeadbeef"},
|
||||
false},
|
||||
{"fail_multiple_bytes",
|
||||
{"--set", infoMakeProperty, "-b", "0xdeadbeef", "0xdeadbeef"},
|
||||
false},
|
||||
{"fail_invalid_bytes", {"--set", infoMakeProperty, "-b", "0xgood"}, false},
|
||||
{"fail_invalid_bytes_no_prefix", {"--set", infoMakeProperty, "-b", "deadbeef"}, false},
|
||||
{"fail_invalid_int", {"--set", infoMakeProperty, "-i", "abc"}, false},
|
||||
{"fail_int_out_of_range", {"--set", infoMakeProperty, "-i", "2147483648"}, false},
|
||||
{"fail_no_int_value", {"--set", infoMakeProperty, "-i", "-s", kCarMake}, false},
|
||||
{"fail_invalid_int64", {"--set", infoMakeProperty, "-i64", "abc"}, false},
|
||||
{"fail_int64_out_of_range",
|
||||
{"--set", infoMakeProperty, "-i64", "-9223372036854775809"},
|
||||
false},
|
||||
{"fail_no_int64_value", {"--set", infoMakeProperty, "-i64", "-s", kCarMake}, false},
|
||||
{"fail_invalid_float", {"--set", infoMakeProperty, "-f", "abc"}, false},
|
||||
{"fail_float_out_of_range",
|
||||
{"--set", infoMakeProperty, "-f", "-3.402823466E+39"},
|
||||
false},
|
||||
{"fail_no_float_value", {"--set", infoMakeProperty, "-f", "-s", kCarMake}, false},
|
||||
{"fail_multiple_areas", {"--set", infoMakeProperty, "-a", "2147483648", "0"}, false},
|
||||
{"fail_invalid_area", {"--set", infoMakeProperty, "-a", "abc"}, false},
|
||||
{"fail_area_out_of_range", {"--set", infoMakeProperty, "-a", "2147483648"}, false},
|
||||
{"fail_no_area_value", {"--set", infoMakeProperty, "-a", "-s", kCarMake}, false},
|
||||
};
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
VehicleHalManagerSetPropTests, VehicleHalManagerSetPropTest,
|
||||
testing::ValuesIn(GenSetPropParams()),
|
||||
[](const testing::TestParamInfo<VehicleHalManagerSetPropTest::ParamType>& info) {
|
||||
return info.param.test_name;
|
||||
});
|
||||
|
||||
TEST_F(VehicleHalManagerTest, SetComplexPropTest) {
|
||||
char infoMakeProperty[100] = {};
|
||||
snprintf(infoMakeProperty, sizeof(infoMakeProperty), "%d", toInt(VehicleProperty::INFO_MAKE));
|
||||
VehicleHalManagerTestHelper helper(manager.get());
|
||||
ASSERT_TRUE(helper.cmdSetOneProperty(
|
||||
STDERR_FILENO, {"--set", infoMakeProperty, "-s", kCarMake,
|
||||
"-b", "0xdeadbeef", "-i", "2147483647",
|
||||
"0", "-2147483648", "-i64", "-9223372036854775808",
|
||||
"0", "9223372036854775807", "-f", "-3.402823466E+38",
|
||||
"0", "3.402823466E+38", "-a", "123"}));
|
||||
StatusCode status = StatusCode::OK;
|
||||
VehiclePropValue requestProp;
|
||||
requestProp.prop = toInt(VehicleProperty::INFO_MAKE);
|
||||
requestProp.areaId = 123;
|
||||
auto value = hal->get(requestProp, &status);
|
||||
ASSERT_EQ(StatusCode::OK, status);
|
||||
ASSERT_EQ(value->prop, toInt(VehicleProperty::INFO_MAKE));
|
||||
ASSERT_EQ(value->areaId, 123);
|
||||
ASSERT_STREQ(kCarMake, value->value.stringValue.c_str());
|
||||
uint8_t bytes[] = {0xde, 0xad, 0xbe, 0xef};
|
||||
ASSERT_FALSE(memcmp(bytes, value->value.bytes.data(), sizeof(bytes)));
|
||||
ASSERT_EQ(3u, value->value.int32Values.size());
|
||||
ASSERT_EQ(2147483647, value->value.int32Values[0]);
|
||||
ASSERT_EQ(0, value->value.int32Values[1]);
|
||||
ASSERT_EQ(-2147483648, value->value.int32Values[2]);
|
||||
ASSERT_EQ(3u, value->value.int64Values.size());
|
||||
// -9223372036854775808 is not a valid literal since '-' and '9223372036854775808' would be two
|
||||
// tokens and the later does not fit in unsigned long long.
|
||||
ASSERT_EQ(-9223372036854775807 - 1, value->value.int64Values[0]);
|
||||
ASSERT_EQ(0, value->value.int64Values[1]);
|
||||
ASSERT_EQ(9223372036854775807, value->value.int64Values[2]);
|
||||
ASSERT_EQ(3u, value->value.floatValues.size());
|
||||
ASSERT_EQ(-3.402823466E+38f, value->value.floatValues[0]);
|
||||
ASSERT_EQ(0.0f, value->value.floatValues[1]);
|
||||
ASSERT_EQ(3.402823466E+38f, value->value.floatValues[2]);
|
||||
}
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
} // namespace V2_0
|
||||
|
|
Loading…
Reference in a new issue