mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:50:18 +00:00
Merge changes from topic "move_conn_lib"
* changes: Move VehicleHalProto out from vhal_v2_0. Support set property in dump. Support debug dump Prevent log spam. Optimize some code path to move instead of copy data.
This commit is contained in:
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package vhal_proto;
|
||||
|
||||
// CMD messages are from workstation --> VHAL
|
||||
// RESP messages are from VHAL --> workstation
|
||||
enum MsgType {
|
||||
GET_CONFIG_CMD = 0;
|
||||
GET_CONFIG_RESP = 1;
|
||||
GET_CONFIG_ALL_CMD = 2;
|
||||
GET_CONFIG_ALL_RESP = 3;
|
||||
GET_PROPERTY_CMD = 4;
|
||||
GET_PROPERTY_RESP = 5;
|
||||
GET_PROPERTY_ALL_CMD = 6;
|
||||
GET_PROPERTY_ALL_RESP = 7;
|
||||
SET_PROPERTY_CMD = 8;
|
||||
SET_PROPERTY_RESP = 9;
|
||||
SET_PROPERTY_ASYNC = 10;
|
||||
DEBUG_CMD = 11;
|
||||
DEBUG_RESP = 12;
|
||||
}
|
||||
enum Status {
|
||||
RESULT_OK = 0;
|
||||
ERROR_UNKNOWN = 1;
|
||||
ERROR_UNIMPLEMENTED_CMD = 2;
|
||||
ERROR_INVALID_PROPERTY = 3;
|
||||
ERROR_INVALID_AREA_ID = 4;
|
||||
ERROR_PROPERTY_UNINITIALIZED = 5;
|
||||
ERROR_WRITE_ONLY_PROPERTY = 6;
|
||||
ERROR_MEMORY_ALLOC_FAILED = 7;
|
||||
ERROR_INVALID_OPERATION = 8;
|
||||
}
|
||||
|
||||
enum VehiclePropStatus {
|
||||
AVAILABLE = 0;
|
||||
UNAVAILABLE = 1;
|
||||
ERROR = 2;
|
||||
}
|
||||
|
||||
message VehicleAreaConfig {
|
||||
required int32 area_id = 1;
|
||||
optional sint32 min_int32_value = 2;
|
||||
optional sint32 max_int32_value = 3;
|
||||
optional sint64 min_int64_value = 4;
|
||||
optional sint64 max_int64_value = 5;
|
||||
optional float min_float_value = 6;
|
||||
optional float max_float_value = 7;
|
||||
}
|
||||
|
||||
message VehiclePropConfig {
|
||||
required int32 prop = 1;
|
||||
optional int32 access = 2;
|
||||
optional int32 change_mode = 3;
|
||||
optional int32 value_type = 4;
|
||||
optional int32 supported_areas = 5; // Deprecated - DO NOT USE
|
||||
repeated VehicleAreaConfig area_configs = 6;
|
||||
optional int32 config_flags = 7;
|
||||
repeated int32 config_array = 8;
|
||||
optional string config_string = 9;
|
||||
optional float min_sample_rate = 10;
|
||||
optional float max_sample_rate = 11;
|
||||
};
|
||||
|
||||
message VehiclePropValue {
|
||||
// common data
|
||||
required int32 prop = 1;
|
||||
optional int32 value_type = 2;
|
||||
optional int64 timestamp = 3; // required for valid data from HAL, skipped for set
|
||||
optional VehiclePropStatus status = 10; // required for valid data from HAL, skipped for set
|
||||
|
||||
// values
|
||||
optional int32 area_id = 4;
|
||||
repeated sint32 int32_values = 5; // this also covers boolean value.
|
||||
repeated sint64 int64_values = 6;
|
||||
repeated float float_values = 7;
|
||||
optional string string_value = 8;
|
||||
optional bytes bytes_value = 9;
|
||||
};
|
||||
|
||||
// This structure is used to notify what values to get from the Vehicle HAL
|
||||
message VehiclePropGet {
|
||||
required int32 prop = 1;
|
||||
optional int32 area_id = 2;
|
||||
};
|
||||
|
||||
message EmulatorMessage {
|
||||
required MsgType msg_type = 1;
|
||||
optional Status status = 2; // Only for RESP messages
|
||||
repeated VehiclePropGet prop = 3; // Provided for getConfig, getProperty commands
|
||||
repeated VehiclePropConfig config = 4;
|
||||
repeated VehiclePropValue value = 5;
|
||||
repeated string debug_commands = 6; // Required for debug command
|
||||
optional string debug_result = 7; // Required for debug RESP messages
|
||||
};
|
||||
@@ -23,7 +23,9 @@
|
||||
#include <IVehicleHardware.h>
|
||||
#include <VehicleHalTypes.h>
|
||||
#include <VehiclePropertyStore.h>
|
||||
#include <android-base/parseint.h>
|
||||
#include <android-base/result.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/thread_annotations.h>
|
||||
|
||||
#include <map>
|
||||
@@ -37,7 +39,7 @@ namespace automotive {
|
||||
namespace vehicle {
|
||||
namespace fake {
|
||||
|
||||
class FakeVehicleHardware final : public IVehicleHardware {
|
||||
class FakeVehicleHardware : public IVehicleHardware {
|
||||
public:
|
||||
FakeVehicleHardware();
|
||||
|
||||
@@ -78,13 +80,15 @@ class FakeVehicleHardware final : public IVehicleHardware {
|
||||
void registerOnPropertySetErrorEvent(
|
||||
std::unique_ptr<const PropertySetErrorCallback> callback) override;
|
||||
|
||||
protected:
|
||||
// mValuePool is also used in mServerSidePropStore.
|
||||
const std::shared_ptr<VehiclePropValuePool> mValuePool;
|
||||
const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
|
||||
|
||||
private:
|
||||
// Expose private methods to unit test.
|
||||
friend class FakeVehicleHardwareTestHelper;
|
||||
|
||||
// mValuePool is also used in mServerSidePropStore.
|
||||
const std::shared_ptr<VehiclePropValuePool> mValuePool;
|
||||
const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
|
||||
const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
|
||||
const std::unique_ptr<FakeUserHal> mFakeUserHal;
|
||||
std::mutex mCallbackLock;
|
||||
@@ -120,6 +124,35 @@ class FakeVehicleHardware final : public IVehicleHardware {
|
||||
::android::base::Result<VehiclePropValuePool::RecyclableType> getUserHalProp(
|
||||
const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
|
||||
bool isHvacPropAndHvacNotAvailable(int32_t propId);
|
||||
|
||||
std::string dumpAllProperties();
|
||||
std::string dumpOnePropertyByConfig(
|
||||
int rowNumber,
|
||||
const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config);
|
||||
std::string dumpOnePropertyById(int32_t propId, int32_t areaId);
|
||||
std::string dumpHelp();
|
||||
std::string dumpListProperties();
|
||||
std::string dumpSpecificProperty(const std::vector<std::string>& options);
|
||||
std::string dumpSetProperties(const std::vector<std::string>& options);
|
||||
|
||||
template <typename T>
|
||||
::android::base::Result<T> safelyParseInt(int index, const std::string& s) {
|
||||
T out;
|
||||
if (!::android::base::ParseInt(s, &out)) {
|
||||
return ::android::base::Error() << ::android::base::StringPrintf(
|
||||
"non-integer argument at index %d: %s\n", index, s.c_str());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
::android::base::Result<float> safelyParseFloat(int index, const std::string& s);
|
||||
std::vector<std::string> getOptionValues(const std::vector<std::string>& options,
|
||||
size_t* index);
|
||||
::android::base::Result<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>
|
||||
parseSetPropOptions(const std::vector<std::string>& options);
|
||||
::android::base::Result<std::vector<uint8_t>> parseHexString(const std::string& s);
|
||||
|
||||
::android::base::Result<void> checkArgumentsSize(const std::vector<std::string>& options,
|
||||
size_t minSize);
|
||||
};
|
||||
|
||||
} // namespace fake
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "FakeVehicleHardware"
|
||||
#define FAKE_VEHICLEHARDWARE_DEBUG false // STOPSHIP if true.
|
||||
|
||||
#include "FakeVehicleHardware.h"
|
||||
|
||||
#include <DefaultConfig.h>
|
||||
@@ -22,7 +25,9 @@
|
||||
#include <PropertyUtils.h>
|
||||
#include <VehicleHalTypes.h>
|
||||
#include <VehicleUtils.h>
|
||||
#include <android-base/parsedouble.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/SystemClock.h>
|
||||
|
||||
@@ -56,12 +61,31 @@ using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
|
||||
|
||||
using ::android::base::EqualsIgnoreCase;
|
||||
using ::android::base::Error;
|
||||
using ::android::base::ParseFloat;
|
||||
using ::android::base::Result;
|
||||
using ::android::base::StartsWith;
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
|
||||
const char* OVERRIDE_PROPERTY = "persist.vendor.vhal_init_value_override";
|
||||
|
||||
// A list of supported options for "--set" command.
|
||||
const std::unordered_set<std::string> SET_PROP_OPTIONS = {
|
||||
// integer.
|
||||
"-i",
|
||||
// 64bit integer.
|
||||
"-i64",
|
||||
// float.
|
||||
"-f",
|
||||
// string.
|
||||
"-s",
|
||||
// bytes in hex format, e.g. 0xDEADBEEF.
|
||||
"-b",
|
||||
// Area id in integer.
|
||||
"-a"};
|
||||
|
||||
} // namespace
|
||||
|
||||
void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDeclaration& config) {
|
||||
@@ -387,7 +411,9 @@ StatusCode FakeVehicleHardware::setValues(std::shared_ptr<const SetValuesCallbac
|
||||
const VehiclePropValue& value = request.value;
|
||||
int propId = value.prop;
|
||||
|
||||
ALOGD("Set value for property ID: %d", propId);
|
||||
if (FAKE_VEHICLEHARDWARE_DEBUG) {
|
||||
ALOGD("Set value for property ID: %d", propId);
|
||||
}
|
||||
|
||||
SetValueResult setValueResult;
|
||||
setValueResult.requestId = request.requestId;
|
||||
@@ -434,7 +460,10 @@ StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallbac
|
||||
std::vector<GetValueResult> results;
|
||||
for (auto& request : requests) {
|
||||
const VehiclePropValue& value = request.prop;
|
||||
ALOGD("getValues(%d)", value.prop);
|
||||
|
||||
if (FAKE_VEHICLEHARDWARE_DEBUG) {
|
||||
ALOGD("getValues(%d)", value.prop);
|
||||
}
|
||||
|
||||
GetValueResult getValueResult;
|
||||
getValueResult.requestId = request.requestId;
|
||||
@@ -476,14 +505,290 @@ StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallbac
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
DumpResult FakeVehicleHardware::dump(const std::vector<std::string>&) {
|
||||
DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
|
||||
DumpResult result;
|
||||
// TODO(b/201830716): Implement this.
|
||||
result.callerShouldDumpState = false;
|
||||
if (options.size() == 0) {
|
||||
// We only want caller to dump default state when there is no options.
|
||||
result.callerShouldDumpState = true;
|
||||
result.buffer = dumpAllProperties();
|
||||
return result;
|
||||
}
|
||||
std::string option = options[0];
|
||||
if (EqualsIgnoreCase(option, "--help")) {
|
||||
result.buffer = dumpHelp();
|
||||
return result;
|
||||
} else if (EqualsIgnoreCase(option, "--list")) {
|
||||
result.buffer = dumpListProperties();
|
||||
} else if (EqualsIgnoreCase(option, "--get")) {
|
||||
result.buffer = dumpSpecificProperty(options);
|
||||
} else if (EqualsIgnoreCase(option, "--set")) {
|
||||
result.buffer = dumpSetProperties(options);
|
||||
} else {
|
||||
result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string FakeVehicleHardware::dumpHelp() {
|
||||
return "Usage: \n\n"
|
||||
"[no args]: dumps (id and value) all supported properties \n"
|
||||
"--help: shows this help\n"
|
||||
"--list: lists the ids of all supported properties\n"
|
||||
"--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \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";
|
||||
}
|
||||
|
||||
std::string FakeVehicleHardware::dumpAllProperties() {
|
||||
auto configs = mServerSidePropStore->getAllConfigs();
|
||||
if (configs.size() == 0) {
|
||||
return "no properties to dump\n";
|
||||
}
|
||||
std::string msg = StringPrintf("dumping %zu properties\n", configs.size());
|
||||
int rowNumber = 1;
|
||||
for (const VehiclePropConfig& config : configs) {
|
||||
msg += dumpOnePropertyByConfig(rowNumber++, config);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::string FakeVehicleHardware::dumpOnePropertyByConfig(int rowNumber,
|
||||
const VehiclePropConfig& config) {
|
||||
size_t numberAreas = config.areaConfigs.size();
|
||||
std::string msg = "";
|
||||
if (numberAreas == 0) {
|
||||
msg += StringPrintf("%d: ", rowNumber);
|
||||
msg += dumpOnePropertyById(config.prop, /* areaId= */ 0);
|
||||
return msg;
|
||||
}
|
||||
for (size_t j = 0; j < numberAreas; ++j) {
|
||||
if (numberAreas > 1) {
|
||||
msg += StringPrintf("%d-%zu: ", rowNumber, j);
|
||||
} else {
|
||||
msg += StringPrintf("%d: ", rowNumber);
|
||||
}
|
||||
msg += dumpOnePropertyById(config.prop, config.areaConfigs[j].areaId);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::string FakeVehicleHardware::dumpOnePropertyById(int32_t propId, int32_t areaId) {
|
||||
VehiclePropValue value = {
|
||||
.prop = propId,
|
||||
.areaId = areaId,
|
||||
};
|
||||
bool isSpecialValue = false;
|
||||
auto result = maybeGetSpecialValue(value, &isSpecialValue);
|
||||
if (!isSpecialValue) {
|
||||
result = mServerSidePropStore->readValue(value);
|
||||
}
|
||||
if (!result.ok()) {
|
||||
return StringPrintf("failed to read property value: %d, error: %s, code: %d\n", propId,
|
||||
getErrorMsg(result).c_str(), getIntErrorCode(result));
|
||||
|
||||
} else {
|
||||
return result.value()->toString() + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::string FakeVehicleHardware::dumpListProperties() {
|
||||
auto configs = mServerSidePropStore->getAllConfigs();
|
||||
if (configs.size() == 0) {
|
||||
return "no properties to list\n";
|
||||
}
|
||||
int rowNumber = 1;
|
||||
std::string msg = StringPrintf("listing %zu properties\n", configs.size());
|
||||
for (const auto& config : configs) {
|
||||
msg += StringPrintf("%d: %d\n", rowNumber++, config.prop);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
Result<void> FakeVehicleHardware::checkArgumentsSize(const std::vector<std::string>& options,
|
||||
size_t minSize) {
|
||||
size_t size = options.size();
|
||||
if (size >= minSize) {
|
||||
return {};
|
||||
}
|
||||
return Error() << StringPrintf("Invalid number of arguments: required at least %zu, got %zu\n",
|
||||
minSize, size);
|
||||
}
|
||||
|
||||
std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector<std::string>& options) {
|
||||
if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
|
||||
return getErrorMsg(result);
|
||||
}
|
||||
|
||||
// options[0] is the command itself...
|
||||
int rowNumber = 1;
|
||||
size_t size = options.size();
|
||||
std::string msg = "";
|
||||
for (size_t i = 1; i < size; ++i) {
|
||||
auto propResult = safelyParseInt<int32_t>(i, options[i]);
|
||||
if (!propResult.ok()) {
|
||||
msg += getErrorMsg(propResult);
|
||||
continue;
|
||||
}
|
||||
int32_t prop = propResult.value();
|
||||
auto result = mServerSidePropStore->getConfig(prop);
|
||||
if (!result.ok()) {
|
||||
msg += StringPrintf("No property %d\n", prop);
|
||||
continue;
|
||||
}
|
||||
msg += dumpOnePropertyByConfig(rowNumber++, *result.value());
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::vector<std::string> FakeVehicleHardware::getOptionValues(
|
||||
const std::vector<std::string>& options, size_t* index) {
|
||||
std::vector<std::string> values;
|
||||
while (*index < options.size()) {
|
||||
std::string option = options[*index];
|
||||
if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) {
|
||||
return std::move(values);
|
||||
}
|
||||
values.push_back(option);
|
||||
(*index)++;
|
||||
}
|
||||
return std::move(values);
|
||||
}
|
||||
|
||||
Result<VehiclePropValue> FakeVehicleHardware::parseSetPropOptions(
|
||||
const std::vector<std::string>& options) {
|
||||
// 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;
|
||||
auto result = safelyParseInt<int32_t>(optionIndex, options[optionIndex]);
|
||||
if (!result.ok()) {
|
||||
return Error() << StringPrintf("Property value: \"%s\" is not a valid int: %s\n",
|
||||
options[optionIndex].c_str(), getErrorMsg(result).c_str());
|
||||
}
|
||||
VehiclePropValue prop = {};
|
||||
prop.prop = result.value();
|
||||
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()) {
|
||||
return Error() << StringPrintf("Duplicate \"%s\" options\n", type.c_str());
|
||||
}
|
||||
parsedOptions.insert(type);
|
||||
if (EqualsIgnoreCase(type, "-i")) {
|
||||
if (values.size() == 0) {
|
||||
return Error() << "No values specified when using \"-i\"\n";
|
||||
}
|
||||
prop.value.int32Values.resize(values.size());
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
auto int32Result = safelyParseInt<int32_t>(currentIndex + i, values[i]);
|
||||
if (!int32Result.ok()) {
|
||||
return Error()
|
||||
<< StringPrintf("Value: \"%s\" is not a valid int: %s\n",
|
||||
values[i].c_str(), getErrorMsg(int32Result).c_str());
|
||||
}
|
||||
prop.value.int32Values[i] = int32Result.value();
|
||||
}
|
||||
} else if (EqualsIgnoreCase(type, "-i64")) {
|
||||
if (values.size() == 0) {
|
||||
return Error() << "No values specified when using \"-i64\"\n";
|
||||
}
|
||||
prop.value.int64Values.resize(values.size());
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
auto int64Result = safelyParseInt<int64_t>(currentIndex + i, values[i]);
|
||||
if (!int64Result.ok()) {
|
||||
return Error()
|
||||
<< StringPrintf("Value: \"%s\" is not a valid int64: %s\n",
|
||||
values[i].c_str(), getErrorMsg(int64Result).c_str());
|
||||
}
|
||||
prop.value.int64Values[i] = int64Result.value();
|
||||
}
|
||||
} else if (EqualsIgnoreCase(type, "-f")) {
|
||||
if (values.size() == 0) {
|
||||
return Error() << "No values specified when using \"-f\"\n";
|
||||
}
|
||||
prop.value.floatValues.resize(values.size());
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
auto floatResult = safelyParseFloat(currentIndex + i, values[i]);
|
||||
if (!floatResult.ok()) {
|
||||
return Error()
|
||||
<< StringPrintf("Value: \"%s\" is not a valid float: %s\n",
|
||||
values[i].c_str(), getErrorMsg(floatResult).c_str());
|
||||
}
|
||||
prop.value.floatValues[i] = floatResult.value();
|
||||
}
|
||||
} else if (EqualsIgnoreCase(type, "-s")) {
|
||||
if (values.size() != 1) {
|
||||
return Error() << "Expect exact one value when using \"-s\"\n";
|
||||
}
|
||||
prop.value.stringValue = values[0];
|
||||
} else if (EqualsIgnoreCase(type, "-b")) {
|
||||
if (values.size() != 1) {
|
||||
return Error() << "Expect exact one value when using \"-b\"\n";
|
||||
}
|
||||
auto bytesResult = parseHexString(values[0]);
|
||||
if (!bytesResult.ok()) {
|
||||
return Error() << StringPrintf("value: \"%s\" is not a valid hex string: %s\n",
|
||||
values[0].c_str(), getErrorMsg(bytesResult).c_str());
|
||||
}
|
||||
prop.value.byteValues = std::move(bytesResult.value());
|
||||
} else if (EqualsIgnoreCase(type, "-a")) {
|
||||
if (values.size() != 1) {
|
||||
return Error() << "Expect exact one value when using \"-a\"\n";
|
||||
}
|
||||
auto int32Result = safelyParseInt<int32_t>(currentIndex, values[0]);
|
||||
if (!int32Result.ok()) {
|
||||
return Error() << StringPrintf("Area ID: \"%s\" is not a valid int: %s\n",
|
||||
values[0].c_str(), getErrorMsg(int32Result).c_str());
|
||||
}
|
||||
prop.areaId = int32Result.value();
|
||||
} else {
|
||||
return Error() << StringPrintf("Unknown option: %s\n", type.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
std::string FakeVehicleHardware::dumpSetProperties(const std::vector<std::string>& options) {
|
||||
if (auto result = checkArgumentsSize(options, 3); !result.ok()) {
|
||||
return getErrorMsg(result);
|
||||
}
|
||||
|
||||
auto parseResult = parseSetPropOptions(options);
|
||||
if (!parseResult.ok()) {
|
||||
return getErrorMsg(parseResult);
|
||||
}
|
||||
VehiclePropValue prop = std::move(parseResult.value());
|
||||
ALOGD("Dump: Setting property: %s", prop.toString().c_str());
|
||||
|
||||
bool isSpecialValue = false;
|
||||
auto setResult = maybeSetSpecialValue(prop, &isSpecialValue);
|
||||
|
||||
if (!isSpecialValue) {
|
||||
auto updatedValue = mValuePool->obtain(prop);
|
||||
updatedValue->timestamp = elapsedRealtimeNano();
|
||||
setResult = mServerSidePropStore->writeValue(std::move(updatedValue));
|
||||
}
|
||||
|
||||
if (setResult.ok()) {
|
||||
return StringPrintf("Set property: %s\n", prop.toString().c_str());
|
||||
}
|
||||
return StringPrintf("failed to set property: %s, error: %s\n", prop.toString().c_str(),
|
||||
getErrorMsg(setResult).c_str());
|
||||
}
|
||||
|
||||
StatusCode FakeVehicleHardware::checkHealth() {
|
||||
// TODO(b/201830716): Implement this.
|
||||
// Always return OK for checkHealth.
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
@@ -544,6 +849,49 @@ void FakeVehicleHardware::overrideProperties(const char* overrideDir) {
|
||||
}
|
||||
}
|
||||
|
||||
Result<float> FakeVehicleHardware::safelyParseFloat(int index, const std::string& s) {
|
||||
float out;
|
||||
if (!ParseFloat(s, &out)) {
|
||||
return Error() << StringPrintf("non-float argument at index %d: %s\n", index, s.c_str());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Result<std::vector<uint8_t>> FakeVehicleHardware::parseHexString(const std::string& s) {
|
||||
std::vector<uint8_t> bytes;
|
||||
if (s.size() % 2 != 0) {
|
||||
return Error() << StringPrintf("invalid hex string: %s, should have even size\n",
|
||||
s.c_str());
|
||||
}
|
||||
if (!StartsWith(s, "0x")) {
|
||||
return Error() << StringPrintf("hex string should start with \"0x\", got %s\n", s.c_str());
|
||||
}
|
||||
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 {
|
||||
return Error() << StringPrintf("invalid character %c in hex string %s\n", c,
|
||||
subs.c_str());
|
||||
}
|
||||
if (highDigit) {
|
||||
bytes.push_back(v * 16);
|
||||
} else {
|
||||
bytes[bytes.size() - 1] += v;
|
||||
}
|
||||
highDigit = !highDigit;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
} // namespace fake
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <android-base/expected.h>
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <utils/Log.h>
|
||||
@@ -52,13 +53,16 @@ using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
|
||||
using ::android::base::expected;
|
||||
using ::android::base::StringPrintf;
|
||||
using ::android::base::unexpected;
|
||||
using ::testing::ContainerEq;
|
||||
using ::testing::ContainsRegex;
|
||||
using ::testing::Eq;
|
||||
using ::testing::IsSubsetOf;
|
||||
using ::testing::WhenSortedBy;
|
||||
|
||||
constexpr int INVALID_PROP_ID = 0;
|
||||
constexpr char CAR_MAKE[] = "Default Car";
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1203,6 +1207,261 @@ TEST_F(FakeVehicleHardwareTest, testInitialUserInfo) {
|
||||
}));
|
||||
}
|
||||
|
||||
TEST_F(FakeVehicleHardwareTest, testDumpAllProperties) {
|
||||
std::vector<std::string> options;
|
||||
DumpResult result = getHardware()->dump(options);
|
||||
ASSERT_TRUE(result.callerShouldDumpState);
|
||||
ASSERT_NE(result.buffer, "");
|
||||
ASSERT_THAT(result.buffer, ContainsRegex("dumping .+ properties"));
|
||||
}
|
||||
|
||||
TEST_F(FakeVehicleHardwareTest, testDumpHelp) {
|
||||
std::vector<std::string> options;
|
||||
options.push_back("--help");
|
||||
DumpResult result = getHardware()->dump(options);
|
||||
ASSERT_FALSE(result.callerShouldDumpState);
|
||||
ASSERT_NE(result.buffer, "");
|
||||
ASSERT_THAT(result.buffer, ContainsRegex("Usage: "));
|
||||
}
|
||||
|
||||
TEST_F(FakeVehicleHardwareTest, testDumpListProperties) {
|
||||
std::vector<std::string> options;
|
||||
options.push_back("--list");
|
||||
DumpResult result = getHardware()->dump(options);
|
||||
ASSERT_FALSE(result.callerShouldDumpState);
|
||||
ASSERT_NE(result.buffer, "");
|
||||
ASSERT_THAT(result.buffer, ContainsRegex("listing .+ properties"));
|
||||
}
|
||||
|
||||
TEST_F(FakeVehicleHardwareTest, testDumpSpecificProperties) {
|
||||
std::vector<std::string> options;
|
||||
options.push_back("--get");
|
||||
std::string prop1 = std::to_string(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
|
||||
std::string prop2 = std::to_string(toInt(VehicleProperty::TIRE_PRESSURE));
|
||||
options.push_back(prop1);
|
||||
options.push_back(prop2);
|
||||
DumpResult result = getHardware()->dump(options);
|
||||
ASSERT_FALSE(result.callerShouldDumpState);
|
||||
ASSERT_NE(result.buffer, "");
|
||||
ASSERT_THAT(result.buffer,
|
||||
ContainsRegex(StringPrintf("1:.*prop: %s.*\n2-0:.*prop: %s.*\n2-1:.*prop: %s.*\n",
|
||||
prop1.c_str(), prop2.c_str(), prop2.c_str())));
|
||||
}
|
||||
|
||||
TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesInvalidProp) {
|
||||
std::vector<std::string> options;
|
||||
options.push_back("--get");
|
||||
std::string prop1 = std::to_string(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
|
||||
std::string prop2 = std::to_string(INVALID_PROP_ID);
|
||||
options.push_back(prop1);
|
||||
options.push_back(prop2);
|
||||
DumpResult result = getHardware()->dump(options);
|
||||
ASSERT_FALSE(result.callerShouldDumpState);
|
||||
ASSERT_NE(result.buffer, "");
|
||||
ASSERT_THAT(result.buffer, ContainsRegex(StringPrintf("1:.*prop: %s.*\nNo property %d\n",
|
||||
prop1.c_str(), INVALID_PROP_ID)));
|
||||
}
|
||||
|
||||
TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesNoArg) {
|
||||
std::vector<std::string> options;
|
||||
options.push_back("--get");
|
||||
|
||||
// No arguments.
|
||||
DumpResult result = getHardware()->dump(options);
|
||||
ASSERT_FALSE(result.callerShouldDumpState);
|
||||
ASSERT_NE(result.buffer, "");
|
||||
ASSERT_THAT(result.buffer, ContainsRegex("Invalid number of arguments"));
|
||||
}
|
||||
|
||||
TEST_F(FakeVehicleHardwareTest, testDumpInvalidOptions) {
|
||||
std::vector<std::string> options;
|
||||
options.push_back("--invalid");
|
||||
|
||||
DumpResult result = getHardware()->dump(options);
|
||||
ASSERT_FALSE(result.callerShouldDumpState);
|
||||
ASSERT_NE(result.buffer, "");
|
||||
ASSERT_THAT(result.buffer, ContainsRegex("Invalid option: --invalid"));
|
||||
}
|
||||
|
||||
struct SetPropTestCase {
|
||||
std::string test_name;
|
||||
std::vector<std::string> options;
|
||||
bool success;
|
||||
std::string errorMsg = "";
|
||||
};
|
||||
|
||||
class FakeVehicleHardwareSetPropTest : public FakeVehicleHardwareTest,
|
||||
public testing::WithParamInterface<SetPropTestCase> {};
|
||||
|
||||
TEST_P(FakeVehicleHardwareSetPropTest, cmdSetOneProperty) {
|
||||
const SetPropTestCase& tc = GetParam();
|
||||
|
||||
DumpResult result = getHardware()->dump(tc.options);
|
||||
ASSERT_FALSE(result.callerShouldDumpState);
|
||||
ASSERT_NE(result.buffer, "");
|
||||
if (tc.success) {
|
||||
ASSERT_THAT(result.buffer, ContainsRegex("Set property:"));
|
||||
} else {
|
||||
ASSERT_THAT(result.buffer, ContainsRegex(tc.errorMsg));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SetPropTestCase> GenSetPropParams() {
|
||||
std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
|
||||
return {
|
||||
{"success_set_string", {"--set", infoMakeProperty, "-s", CAR_MAKE}, 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", {"--set", infoMakeProperty}, false, "Invalid number of arguments"},
|
||||
{"fail_less_than_4_options",
|
||||
{"--set", infoMakeProperty, "-i"},
|
||||
false,
|
||||
"No values specified"},
|
||||
{"fail_unknown_options", {"--set", infoMakeProperty, "-abcd"}, false, "Unknown option"},
|
||||
{"fail_invalid_property",
|
||||
{"--set", "not valid", "-s", CAR_MAKE},
|
||||
false,
|
||||
"not a valid int"},
|
||||
{"fail_duplicate_string",
|
||||
{"--set", infoMakeProperty, "-s", CAR_MAKE, "-s", CAR_MAKE},
|
||||
false,
|
||||
"Duplicate \"-s\" options"},
|
||||
{"fail_multiple_strings",
|
||||
{"--set", infoMakeProperty, "-s", CAR_MAKE, CAR_MAKE},
|
||||
false,
|
||||
"Expect exact one value"},
|
||||
{"fail_no_string_value",
|
||||
{"--set", infoMakeProperty, "-s", "-a", "1234"},
|
||||
false,
|
||||
"Expect exact one value"},
|
||||
{"fail_duplicate_bytes",
|
||||
{"--set", infoMakeProperty, "-b", "0xdeadbeef", "-b", "0xdeadbeef"},
|
||||
false,
|
||||
"Duplicate \"-b\" options"},
|
||||
{"fail_multiple_bytes",
|
||||
{"--set", infoMakeProperty, "-b", "0xdeadbeef", "0xdeadbeef"},
|
||||
false,
|
||||
"Expect exact one value"},
|
||||
{"fail_invalid_bytes",
|
||||
{"--set", infoMakeProperty, "-b", "0xgood"},
|
||||
false,
|
||||
"not a valid hex string"},
|
||||
{"fail_invalid_bytes_no_prefix",
|
||||
{"--set", infoMakeProperty, "-b", "deadbeef"},
|
||||
false,
|
||||
"not a valid hex string"},
|
||||
{"fail_invalid_int",
|
||||
{"--set", infoMakeProperty, "-i", "abc"},
|
||||
false,
|
||||
"not a valid int"},
|
||||
{"fail_int_out_of_range",
|
||||
{"--set", infoMakeProperty, "-i", "2147483648"},
|
||||
false,
|
||||
"not a valid int"},
|
||||
{"fail_no_int_value",
|
||||
{"--set", infoMakeProperty, "-i", "-s", CAR_MAKE},
|
||||
false,
|
||||
"No values specified"},
|
||||
{"fail_invalid_int64",
|
||||
{"--set", infoMakeProperty, "-i64", "abc"},
|
||||
false,
|
||||
"not a valid int64"},
|
||||
{"fail_int64_out_of_range",
|
||||
{"--set", infoMakeProperty, "-i64", "-9223372036854775809"},
|
||||
false,
|
||||
"not a valid int64"},
|
||||
{"fail_no_int64_value",
|
||||
{"--set", infoMakeProperty, "-i64", "-s", CAR_MAKE},
|
||||
false,
|
||||
"No values specified"},
|
||||
{"fail_invalid_float",
|
||||
{"--set", infoMakeProperty, "-f", "abc"},
|
||||
false,
|
||||
"not a valid float"},
|
||||
{"fail_float_out_of_range",
|
||||
{"--set", infoMakeProperty, "-f", "-3.402823466E+39"},
|
||||
false,
|
||||
"not a valid float"},
|
||||
{"fail_no_float_value",
|
||||
{"--set", infoMakeProperty, "-f", "-s", CAR_MAKE},
|
||||
false,
|
||||
"No values specified"},
|
||||
{"fail_multiple_areas",
|
||||
{"--set", infoMakeProperty, "-a", "2147483648", "0"},
|
||||
false,
|
||||
"Expect exact one value"},
|
||||
{"fail_invalid_area",
|
||||
{"--set", infoMakeProperty, "-a", "abc"},
|
||||
false,
|
||||
"not a valid int"},
|
||||
{"fail_area_out_of_range",
|
||||
{"--set", infoMakeProperty, "-a", "2147483648"},
|
||||
false,
|
||||
"not a valid int"},
|
||||
{"fail_no_area_value",
|
||||
{"--set", infoMakeProperty, "-a", "-s", CAR_MAKE},
|
||||
false,
|
||||
"Expect exact one value"},
|
||||
};
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
FakeVehicleHardwareSetPropTests, FakeVehicleHardwareSetPropTest,
|
||||
testing::ValuesIn(GenSetPropParams()),
|
||||
[](const testing::TestParamInfo<FakeVehicleHardwareSetPropTest::ParamType>& info) {
|
||||
return info.param.test_name;
|
||||
});
|
||||
|
||||
TEST_F(FakeVehicleHardwareTest, SetComplexPropTest) {
|
||||
std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
|
||||
getHardware()->dump({"--set", infoMakeProperty, "-s", CAR_MAKE,
|
||||
"-b", "0xdeadbeef", "-i", "2147483647",
|
||||
"0", "-2147483648", "-i64", "-9223372036854775808",
|
||||
"0", "9223372036854775807", "-f", "-3.402823466E+38",
|
||||
"0", "3.402823466E+38", "-a", "123"});
|
||||
VehiclePropValue requestProp;
|
||||
requestProp.prop = toInt(VehicleProperty::INFO_MAKE);
|
||||
requestProp.areaId = 123;
|
||||
auto result = getValue(requestProp);
|
||||
ASSERT_TRUE(result.ok());
|
||||
VehiclePropValue value = result.value();
|
||||
ASSERT_EQ(value.prop, toInt(VehicleProperty::INFO_MAKE));
|
||||
ASSERT_EQ(value.areaId, 123);
|
||||
ASSERT_STREQ(CAR_MAKE, value.value.stringValue.c_str());
|
||||
uint8_t bytes[] = {0xde, 0xad, 0xbe, 0xef};
|
||||
ASSERT_FALSE(memcmp(bytes, value.value.byteValues.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 fake
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
|
||||
@@ -79,7 +79,7 @@ class GetSetValuesClient final : public ConnectedClient {
|
||||
GetSetValuesClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);
|
||||
|
||||
// Sends the results to this client.
|
||||
void sendResults(const std::vector<ResultType>& results);
|
||||
void sendResults(std::vector<ResultType>&& results);
|
||||
|
||||
// Sends each result separately to this client. Each result would be sent through one callback
|
||||
// invocation.
|
||||
|
||||
@@ -39,13 +39,6 @@ namespace hardware {
|
||||
namespace automotive {
|
||||
namespace vehicle {
|
||||
|
||||
// private namespace
|
||||
namespace defaultvehiclehal_impl {
|
||||
|
||||
constexpr int INVALID_MEMORY_FD = -1;
|
||||
|
||||
} // namespace defaultvehiclehal_impl
|
||||
|
||||
class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::vehicle::BnVehicle {
|
||||
public:
|
||||
using CallbackType =
|
||||
@@ -79,6 +72,7 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve
|
||||
const std::vector<int32_t>& propIds) override;
|
||||
::ndk::ScopedAStatus returnSharedMemory(const CallbackType& callback,
|
||||
int64_t sharedMemoryId) override;
|
||||
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
|
||||
|
||||
IVehicleHardware* getHardware();
|
||||
|
||||
@@ -215,6 +209,8 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve
|
||||
|
||||
void monitorBinderLifeCycle(const CallbackType& callback);
|
||||
|
||||
bool checkDumpPermission();
|
||||
|
||||
template <class T>
|
||||
static std::shared_ptr<T> getOrCreateClient(
|
||||
std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
|
||||
|
||||
@@ -29,6 +29,9 @@ namespace hardware {
|
||||
namespace automotive {
|
||||
namespace vehicle {
|
||||
|
||||
// Turns the values into a stable large parcelable that could be sent via binder.
|
||||
// If values is small enough, it would be put into output.payloads, otherwise a shared memory file
|
||||
// would be created and output.sharedMemoryFd would be filled in.
|
||||
template <class T1, class T2>
|
||||
::ndk::ScopedAStatus vectorToStableLargeParcelable(std::vector<T1>&& values, T2* output) {
|
||||
output->payloads = std::move(values);
|
||||
@@ -44,6 +47,9 @@ template <class T1, class T2>
|
||||
// 'sharedMemoryFd' field.
|
||||
output->payloads.clear();
|
||||
output->sharedMemoryFd = std::move(*fd);
|
||||
} else {
|
||||
output->sharedMemoryFd = ::ndk::ScopedFileDescriptor();
|
||||
// Do not modify payloads.
|
||||
}
|
||||
return ::ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
@@ -84,9 +84,9 @@ void sendGetOrSetValueResultsSeparately(std::shared_ptr<IVehicleCallback> callba
|
||||
// Send all the GetValue/SetValue results through callback in a single callback invocation.
|
||||
template <class ResultType, class ResultsType>
|
||||
void sendGetOrSetValueResults(std::shared_ptr<IVehicleCallback> callback,
|
||||
const std::vector<ResultType>& results) {
|
||||
std::vector<ResultType>&& results) {
|
||||
ResultsType parcelableResults;
|
||||
ScopedAStatus status = vectorToStableLargeParcelable(results, &parcelableResults);
|
||||
ScopedAStatus status = vectorToStableLargeParcelable(std::move(results), &parcelableResults);
|
||||
if (status.isOk()) {
|
||||
if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults);
|
||||
!callbackStatus.isOk()) {
|
||||
@@ -99,7 +99,8 @@ void sendGetOrSetValueResults(std::shared_ptr<IVehicleCallback> callback,
|
||||
ALOGE("failed to marshal result into large parcelable, error: "
|
||||
"%s, code: %d",
|
||||
status.getMessage(), statusCode);
|
||||
sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(callback, results);
|
||||
sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(callback,
|
||||
parcelableResults.payloads);
|
||||
}
|
||||
|
||||
// The timeout callback for GetValues/SetValues.
|
||||
@@ -115,7 +116,7 @@ void onTimeout(
|
||||
.status = StatusCode::TRY_AGAIN,
|
||||
});
|
||||
}
|
||||
sendGetOrSetValueResults<ResultType, ResultsType>(callback, timeoutResults);
|
||||
sendGetOrSetValueResults<ResultType, ResultsType>(callback, std::move(timeoutResults));
|
||||
}
|
||||
|
||||
// The on-results callback for GetValues/SetValues.
|
||||
@@ -123,7 +124,7 @@ template <class ResultType, class ResultsType>
|
||||
void getOrSetValuesCallback(
|
||||
const void* clientId,
|
||||
std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
|
||||
std::vector<ResultType> results, std::shared_ptr<PendingRequestPool> requestPool) {
|
||||
std::vector<ResultType>&& results, std::shared_ptr<PendingRequestPool> requestPool) {
|
||||
std::unordered_set<int64_t> requestIds;
|
||||
for (const auto& result : results) {
|
||||
requestIds.insert(result.requestId);
|
||||
@@ -145,7 +146,7 @@ void getOrSetValuesCallback(
|
||||
}
|
||||
|
||||
if (!results.empty()) {
|
||||
sendGetOrSetValueResults<ResultType, ResultsType>(callback, results);
|
||||
sendGetOrSetValueResults<ResultType, ResultsType>(callback, std::move(results));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,9 +157,9 @@ template void sendGetOrSetValueResult<SetValueResult, SetValueResults>(
|
||||
std::shared_ptr<IVehicleCallback> callback, const SetValueResult& result);
|
||||
|
||||
template void sendGetOrSetValueResults<GetValueResult, GetValueResults>(
|
||||
std::shared_ptr<IVehicleCallback> callback, const std::vector<GetValueResult>& results);
|
||||
std::shared_ptr<IVehicleCallback> callback, std::vector<GetValueResult>&& results);
|
||||
template void sendGetOrSetValueResults<SetValueResult, SetValueResults>(
|
||||
std::shared_ptr<IVehicleCallback> callback, const std::vector<SetValueResult>& results);
|
||||
std::shared_ptr<IVehicleCallback> callback, std::vector<SetValueResult>&& results);
|
||||
|
||||
template void sendGetOrSetValueResultsSeparately<GetValueResult, GetValueResults>(
|
||||
std::shared_ptr<IVehicleCallback> callback, const std::vector<GetValueResult>& results);
|
||||
@@ -175,11 +176,11 @@ template void onTimeout<SetValueResult, SetValueResults>(
|
||||
template void getOrSetValuesCallback<GetValueResult, GetValueResults>(
|
||||
const void* clientId,
|
||||
std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
|
||||
std::vector<GetValueResult> results, std::shared_ptr<PendingRequestPool> requestPool);
|
||||
std::vector<GetValueResult>&& results, std::shared_ptr<PendingRequestPool> requestPool);
|
||||
template void getOrSetValuesCallback<SetValueResult, SetValueResults>(
|
||||
const void* clientId,
|
||||
std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback,
|
||||
std::vector<SetValueResult> results, std::shared_ptr<PendingRequestPool> requestPool);
|
||||
std::vector<SetValueResult>&& results, std::shared_ptr<PendingRequestPool> requestPool);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -230,9 +231,8 @@ GetSetValuesClient<ResultType, ResultsType>::getTimeoutCallback() {
|
||||
}
|
||||
|
||||
template <class ResultType, class ResultsType>
|
||||
void GetSetValuesClient<ResultType, ResultsType>::sendResults(
|
||||
const std::vector<ResultType>& results) {
|
||||
return sendGetOrSetValueResults<ResultType, ResultsType>(mCallback, results);
|
||||
void GetSetValuesClient<ResultType, ResultsType>::sendResults(std::vector<ResultType>&& results) {
|
||||
return sendGetOrSetValueResults<ResultType, ResultsType>(mCallback, std::move(results));
|
||||
}
|
||||
|
||||
template <class ResultType, class ResultsType>
|
||||
@@ -283,7 +283,8 @@ void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> cal
|
||||
// TODO(b/205189110): Use memory pool here and fill in sharedMemoryId.
|
||||
VehiclePropValues vehiclePropValues;
|
||||
int32_t sharedMemoryFileCount = 0;
|
||||
ScopedAStatus status = vectorToStableLargeParcelable(updatedValues, &vehiclePropValues);
|
||||
ScopedAStatus status =
|
||||
vectorToStableLargeParcelable(std::move(updatedValues), &vehiclePropValues);
|
||||
if (!status.isOk()) {
|
||||
int statusCode = status.getServiceSpecificError();
|
||||
ALOGE("subscribe: failed to marshal result into large parcelable, error: "
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#include <android-base/result.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android/binder_ibinder.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/SystemClock.h>
|
||||
|
||||
@@ -387,7 +389,7 @@ ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback,
|
||||
|
||||
if (!failedResults.empty()) {
|
||||
// First send the failed results we already know back to the client.
|
||||
client->sendResults(failedResults);
|
||||
client->sendResults(std::move(failedResults));
|
||||
}
|
||||
|
||||
if (hardwareRequests.empty()) {
|
||||
@@ -476,7 +478,7 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback,
|
||||
|
||||
if (!failedResults.empty()) {
|
||||
// First send the failed results we already know back to the client.
|
||||
client->sendResults(failedResults);
|
||||
client->sendResults(std::move(failedResults));
|
||||
}
|
||||
|
||||
if (hardwareRequests.empty()) {
|
||||
@@ -718,6 +720,39 @@ void DefaultVehicleHal::setLinkToDeathImpl(std::unique_ptr<ILinkToDeath> impl) {
|
||||
mLinkToDeathImpl = std::move(impl);
|
||||
}
|
||||
|
||||
bool DefaultVehicleHal::checkDumpPermission() {
|
||||
uid_t uid = AIBinder_getCallingUid();
|
||||
return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
|
||||
}
|
||||
|
||||
binder_status_t DefaultVehicleHal::dump(int fd, const char** args, uint32_t numArgs) {
|
||||
if (!checkDumpPermission()) {
|
||||
dprintf(fd, "Caller must be root, system or shell");
|
||||
return STATUS_PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
std::vector<std::string> options;
|
||||
for (uint32_t i = 0; i < numArgs; i++) {
|
||||
options.push_back(args[i]);
|
||||
}
|
||||
DumpResult result = mVehicleHardware->dump(options);
|
||||
dprintf(fd, "%s", (result.buffer + "\n").c_str());
|
||||
if (!result.callerShouldDumpState) {
|
||||
dprintf(fd, "Skip dumping Vehicle HAL State.\n");
|
||||
return STATUS_OK;
|
||||
}
|
||||
dprintf(fd, "Vehicle HAL State: \n");
|
||||
{
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
|
||||
dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
|
||||
dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
|
||||
dprintf(fd, "Currently have %zu subscription clients\n",
|
||||
mSubscriptionClients->countClients());
|
||||
}
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
} // namespace hardware
|
||||
|
||||
@@ -80,7 +80,8 @@ TEST_F(ConnectedClientTest, testSendGetValueResults) {
|
||||
|
||||
GetValuesClient client(getPool(), getCallbackClient());
|
||||
|
||||
client.sendResults(results);
|
||||
auto resultsCopy = results;
|
||||
client.sendResults(std::move(resultsCopy));
|
||||
|
||||
auto maybeGetValueResults = getCallback()->nextGetValueResults();
|
||||
ASSERT_TRUE(maybeGetValueResults.has_value());
|
||||
@@ -160,7 +161,8 @@ TEST_F(ConnectedClientTest, testSendSetValueResults) {
|
||||
|
||||
SetValuesClient client(getPool(), getCallbackClient());
|
||||
|
||||
client.sendResults(results);
|
||||
auto resultsCopy = results;
|
||||
client.sendResults(std::move(resultsCopy));
|
||||
|
||||
auto maybeSetValueResults = getCallback()->nextSetValueResults();
|
||||
ASSERT_TRUE(maybeSetValueResults.has_value());
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <android-base/thread_annotations.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <sys/mman.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/SystemClock.h>
|
||||
|
||||
@@ -75,6 +76,7 @@ using ::ndk::ScopedAStatus;
|
||||
using ::ndk::ScopedFileDescriptor;
|
||||
using ::ndk::SpAIBinder;
|
||||
|
||||
using ::testing::ContainsRegex;
|
||||
using ::testing::Eq;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using ::testing::UnorderedElementsAreArray;
|
||||
@@ -371,7 +373,7 @@ class DefaultVehicleHalTest : public ::testing::Test {
|
||||
return mVhal->mOnBinderDiedContexts[clientId].get();
|
||||
}
|
||||
|
||||
bool countOnBinderDiedContexts() {
|
||||
size_t countOnBinderDiedContexts() {
|
||||
std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
|
||||
return mVhal->mOnBinderDiedContexts.size();
|
||||
}
|
||||
@@ -444,6 +446,7 @@ class DefaultVehicleHalTest : public ::testing::Test {
|
||||
if (result.value() != nullptr) {
|
||||
requests.payloads.clear();
|
||||
requests.sharedMemoryFd = std::move(*result.value());
|
||||
requests.payloads.clear();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -1544,6 +1547,45 @@ TEST_F(DefaultVehicleHalTest, testOnBinderDiedUnlinked) {
|
||||
<< "expect OnBinderDied context to be deleted when binder is unlinked";
|
||||
}
|
||||
|
||||
TEST_F(DefaultVehicleHalTest, testDumpCallerShouldDump) {
|
||||
std::string buffer = "Dump from hardware";
|
||||
getHardware()->setDumpResult({
|
||||
.callerShouldDumpState = true,
|
||||
.buffer = buffer,
|
||||
});
|
||||
int fd = memfd_create("memfile", 0);
|
||||
getClient()->dump(fd, nullptr, 0);
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
char buf[10240] = {};
|
||||
read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
|
||||
std::string msg(buf);
|
||||
|
||||
ASSERT_THAT(msg, ContainsRegex(buffer + "\nVehicle HAL State: \n"));
|
||||
}
|
||||
|
||||
TEST_F(DefaultVehicleHalTest, testDumpCallerShouldNotDump) {
|
||||
std::string buffer = "Dump from hardware";
|
||||
getHardware()->setDumpResult({
|
||||
.callerShouldDumpState = false,
|
||||
.buffer = buffer,
|
||||
});
|
||||
int fd = memfd_create("memfile", 0);
|
||||
getClient()->dump(fd, nullptr, 0);
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
char buf[10240] = {};
|
||||
read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
|
||||
std::string msg(buf);
|
||||
|
||||
ASSERT_THAT(msg, ContainsRegex(buffer));
|
||||
ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
|
||||
}
|
||||
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
} // namespace hardware
|
||||
|
||||
@@ -71,13 +71,15 @@ StatusCode MockVehicleHardware::getValues(std::shared_ptr<const GetValuesCallbac
|
||||
&mGetValueResponses);
|
||||
}
|
||||
|
||||
void MockVehicleHardware::setDumpResult(DumpResult result) {
|
||||
mDumpResult = result;
|
||||
}
|
||||
|
||||
DumpResult MockVehicleHardware::dump(const std::vector<std::string>&) {
|
||||
// TODO(b/200737967): mock this.
|
||||
return DumpResult{};
|
||||
return mDumpResult;
|
||||
}
|
||||
|
||||
StatusCode MockVehicleHardware::checkHealth() {
|
||||
// TODO(b/200737967): mock this.
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ class MockVehicleHardware final : public IVehicleHardware {
|
||||
void setStatus(const char* functionName,
|
||||
::aidl::android::hardware::automotive::vehicle::StatusCode status);
|
||||
void setSleepTime(int64_t timeInNano);
|
||||
void setDumpResult(DumpResult result);
|
||||
|
||||
private:
|
||||
mutable std::mutex mLock;
|
||||
@@ -114,6 +115,8 @@ class MockVehicleHardware final : public IVehicleHardware {
|
||||
const std::vector<RequestType>& requests,
|
||||
std::list<std::vector<RequestType>>* storedRequests,
|
||||
std::list<std::vector<ResultType>>* storedResponses) const REQUIRES(mLock);
|
||||
|
||||
DumpResult mDumpResult;
|
||||
};
|
||||
|
||||
} // namespace vehicle
|
||||
|
||||
@@ -25,8 +25,8 @@ package {
|
||||
cc_library_static {
|
||||
name: "android.hardware.automotive.vehicle@2.0-libproto-native",
|
||||
visibility: [
|
||||
"//hardware/interfaces/automotive/vehicle/2.0/default:__subpackages__",
|
||||
"//device/generic/car/emulator/vhal_v2_0:__subpackages__",
|
||||
"//hardware/interfaces/automotive/vehicle:__subpackages__",
|
||||
"//device/generic/car/emulator:__subpackages__",
|
||||
],
|
||||
vendor: true,
|
||||
host_supported: true,
|
||||
110
automotive/vehicle/proto/VehicleHalProto.proto
Normal file
110
automotive/vehicle/proto/VehicleHalProto.proto
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package vhal_proto;
|
||||
|
||||
// CMD messages are from workstation --> VHAL
|
||||
// RESP messages are from VHAL --> workstation
|
||||
enum MsgType {
|
||||
GET_CONFIG_CMD = 0;
|
||||
GET_CONFIG_RESP = 1;
|
||||
GET_CONFIG_ALL_CMD = 2;
|
||||
GET_CONFIG_ALL_RESP = 3;
|
||||
GET_PROPERTY_CMD = 4;
|
||||
GET_PROPERTY_RESP = 5;
|
||||
GET_PROPERTY_ALL_CMD = 6;
|
||||
GET_PROPERTY_ALL_RESP = 7;
|
||||
SET_PROPERTY_CMD = 8;
|
||||
SET_PROPERTY_RESP = 9;
|
||||
SET_PROPERTY_ASYNC = 10;
|
||||
DEBUG_CMD = 11;
|
||||
DEBUG_RESP = 12;
|
||||
}
|
||||
enum Status {
|
||||
RESULT_OK = 0;
|
||||
ERROR_UNKNOWN = 1;
|
||||
ERROR_UNIMPLEMENTED_CMD = 2;
|
||||
ERROR_INVALID_PROPERTY = 3;
|
||||
ERROR_INVALID_AREA_ID = 4;
|
||||
ERROR_PROPERTY_UNINITIALIZED = 5;
|
||||
ERROR_WRITE_ONLY_PROPERTY = 6;
|
||||
ERROR_MEMORY_ALLOC_FAILED = 7;
|
||||
ERROR_INVALID_OPERATION = 8;
|
||||
}
|
||||
|
||||
enum VehiclePropStatus {
|
||||
AVAILABLE = 0;
|
||||
UNAVAILABLE = 1;
|
||||
ERROR = 2;
|
||||
}
|
||||
|
||||
message VehicleAreaConfig {
|
||||
required int32 area_id = 1;
|
||||
optional sint32 min_int32_value = 2;
|
||||
optional sint32 max_int32_value = 3;
|
||||
optional sint64 min_int64_value = 4;
|
||||
optional sint64 max_int64_value = 5;
|
||||
optional float min_float_value = 6;
|
||||
optional float max_float_value = 7;
|
||||
}
|
||||
|
||||
message VehiclePropConfig {
|
||||
required int32 prop = 1;
|
||||
optional int32 access = 2;
|
||||
optional int32 change_mode = 3;
|
||||
optional int32 value_type = 4;
|
||||
optional int32 supported_areas = 5; // Deprecated - DO NOT USE
|
||||
repeated VehicleAreaConfig area_configs = 6;
|
||||
optional int32 config_flags = 7;
|
||||
repeated int32 config_array = 8;
|
||||
optional string config_string = 9;
|
||||
optional float min_sample_rate = 10;
|
||||
optional float max_sample_rate = 11;
|
||||
};
|
||||
|
||||
message VehiclePropValue {
|
||||
// common data
|
||||
required int32 prop = 1;
|
||||
optional int32 value_type = 2;
|
||||
optional int64 timestamp = 3; // required for valid data from HAL, skipped for set
|
||||
optional VehiclePropStatus status = 10; // required for valid data from HAL, skipped for set
|
||||
|
||||
// values
|
||||
optional int32 area_id = 4;
|
||||
repeated sint32 int32_values = 5; // this also covers boolean value.
|
||||
repeated sint64 int64_values = 6;
|
||||
repeated float float_values = 7;
|
||||
optional string string_value = 8;
|
||||
optional bytes bytes_value = 9;
|
||||
};
|
||||
|
||||
// This structure is used to notify what values to get from the Vehicle HAL
|
||||
message VehiclePropGet {
|
||||
required int32 prop = 1;
|
||||
optional int32 area_id = 2;
|
||||
};
|
||||
|
||||
message EmulatorMessage {
|
||||
required MsgType msg_type = 1;
|
||||
optional Status status = 2; // Only for RESP messages
|
||||
repeated VehiclePropGet prop = 3; // Provided for getConfig, getProperty commands
|
||||
repeated VehiclePropConfig config = 4;
|
||||
repeated VehiclePropValue value = 5;
|
||||
repeated string debug_commands = 6; // Required for debug command
|
||||
optional string debug_result = 7; // Required for debug RESP messages
|
||||
};
|
||||
Reference in New Issue
Block a user