diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto deleted file mode 100644 index 58daca619c..0000000000 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto +++ /dev/null @@ -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 -}; diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h index cab184bb49..1c452710d8 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include #include #include @@ -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 callback) override; + protected: + // mValuePool is also used in mServerSidePropStore. + const std::shared_ptr mValuePool; + const std::shared_ptr mServerSidePropStore; + private: // Expose private methods to unit test. friend class FakeVehicleHardwareTestHelper; - // mValuePool is also used in mServerSidePropStore. - const std::shared_ptr mValuePool; - const std::shared_ptr mServerSidePropStore; const std::unique_ptr mFakeObd2Frame; const std::unique_ptr mFakeUserHal; std::mutex mCallbackLock; @@ -120,6 +124,35 @@ class FakeVehicleHardware final : public IVehicleHardware { ::android::base::Result 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& options); + std::string dumpSetProperties(const std::vector& options); + + template + ::android::base::Result 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 safelyParseFloat(int index, const std::string& s); + std::vector getOptionValues(const std::vector& options, + size_t* index); + ::android::base::Result<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> + parseSetPropOptions(const std::vector& options); + ::android::base::Result> parseHexString(const std::string& s); + + ::android::base::Result checkArgumentsSize(const std::vector& options, + size_t minSize); }; } // namespace fake diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp index e75f0e7c2c..96607937b8 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#define LOG_TAG "FakeVehicleHardware" +#define FAKE_VEHICLEHARDWARE_DEBUG false // STOPSHIP if true. + #include "FakeVehicleHardware.h" #include @@ -22,7 +25,9 @@ #include #include #include +#include #include +#include #include #include @@ -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 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 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&) { +DumpResult FakeVehicleHardware::dump(const std::vector& 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 [PROP2] [PROPN]: dumps the value of specific properties \n" + "--set [-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 FakeVehicleHardware::checkArgumentsSize(const std::vector& 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& 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(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 FakeVehicleHardware::getOptionValues( + const std::vector& options, size_t* index) { + std::vector 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 FakeVehicleHardware::parseSetPropOptions( + const std::vector& 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(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 parsedOptions; + + while (optionIndex < options.size()) { + std::string type = options[optionIndex]; + optionIndex++; + size_t currentIndex = optionIndex; + std::vector 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(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(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(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& 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 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> FakeVehicleHardware::parseHexString(const std::string& s) { + std::vector 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 diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp index 970d044d43..0812c2a062 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -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 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 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 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 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 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 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 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 options; + bool success; + std::string errorMsg = ""; +}; + +class FakeVehicleHardwareSetPropTest : public FakeVehicleHardwareTest, + public testing::WithParamInterface {}; + +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 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& 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 diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h index 833707a580..15a6278f38 100644 --- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h +++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h @@ -79,7 +79,7 @@ class GetSetValuesClient final : public ConnectedClient { GetSetValuesClient(std::shared_ptr requestPool, CallbackType callback); // Sends the results to this client. - void sendResults(const std::vector& results); + void sendResults(std::vector&& results); // Sends each result separately to this client. Each result would be sent through one callback // invocation. diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h index 62b2627691..5e7adfca6d 100644 --- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h +++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h @@ -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& 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 static std::shared_ptr getOrCreateClient( std::unordered_map>* clients, diff --git a/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h b/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h index 4b7c2f3221..7b2111b96b 100644 --- a/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h +++ b/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h @@ -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 ::ndk::ScopedAStatus vectorToStableLargeParcelable(std::vector&& values, T2* output) { output->payloads = std::move(values); @@ -44,6 +47,9 @@ template // 'sharedMemoryFd' field. output->payloads.clear(); output->sharedMemoryFd = std::move(*fd); + } else { + output->sharedMemoryFd = ::ndk::ScopedFileDescriptor(); + // Do not modify payloads. } return ::ndk::ScopedAStatus::ok(); } diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp index 5ccef55a29..098bfee1bb 100644 --- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp +++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp @@ -84,9 +84,9 @@ void sendGetOrSetValueResultsSeparately(std::shared_ptr callba // Send all the GetValue/SetValue results through callback in a single callback invocation. template void sendGetOrSetValueResults(std::shared_ptr callback, - const std::vector& results) { + std::vector&& 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 callback, ALOGE("failed to marshal result into large parcelable, error: " "%s, code: %d", status.getMessage(), statusCode); - sendGetOrSetValueResultsSeparately(callback, results); + sendGetOrSetValueResultsSeparately(callback, + parcelableResults.payloads); } // The timeout callback for GetValues/SetValues. @@ -115,7 +116,7 @@ void onTimeout( .status = StatusCode::TRY_AGAIN, }); } - sendGetOrSetValueResults(callback, timeoutResults); + sendGetOrSetValueResults(callback, std::move(timeoutResults)); } // The on-results callback for GetValues/SetValues. @@ -123,7 +124,7 @@ template void getOrSetValuesCallback( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, - std::vector results, std::shared_ptr requestPool) { + std::vector&& results, std::shared_ptr requestPool) { std::unordered_set requestIds; for (const auto& result : results) { requestIds.insert(result.requestId); @@ -145,7 +146,7 @@ void getOrSetValuesCallback( } if (!results.empty()) { - sendGetOrSetValueResults(callback, results); + sendGetOrSetValueResults(callback, std::move(results)); } } @@ -156,9 +157,9 @@ template void sendGetOrSetValueResult( std::shared_ptr callback, const SetValueResult& result); template void sendGetOrSetValueResults( - std::shared_ptr callback, const std::vector& results); + std::shared_ptr callback, std::vector&& results); template void sendGetOrSetValueResults( - std::shared_ptr callback, const std::vector& results); + std::shared_ptr callback, std::vector&& results); template void sendGetOrSetValueResultsSeparately( std::shared_ptr callback, const std::vector& results); @@ -175,11 +176,11 @@ template void onTimeout( template void getOrSetValuesCallback( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, - std::vector results, std::shared_ptr requestPool); + std::vector&& results, std::shared_ptr requestPool); template void getOrSetValuesCallback( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, - std::vector results, std::shared_ptr requestPool); + std::vector&& results, std::shared_ptr requestPool); } // namespace @@ -230,9 +231,8 @@ GetSetValuesClient::getTimeoutCallback() { } template -void GetSetValuesClient::sendResults( - const std::vector& results) { - return sendGetOrSetValueResults(mCallback, results); +void GetSetValuesClient::sendResults(std::vector&& results) { + return sendGetOrSetValueResults(mCallback, std::move(results)); } template @@ -283,7 +283,8 @@ void SubscriptionClient::sendUpdatedValues(std::shared_ptr 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: " diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp index 3e088c5ee8..c0a66daf75 100644 --- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp +++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp @@ -24,6 +24,8 @@ #include #include +#include +#include #include #include @@ -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 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 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 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 diff --git a/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp index bd4a565df3..bdb0d31cdb 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp +++ b/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp @@ -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()); diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp index ff355c33e1..7443d5bc6d 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp +++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -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 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 diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp index eec32ddfc2..66aef7c2da 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp @@ -71,13 +71,15 @@ StatusCode MockVehicleHardware::getValues(std::shared_ptr&) { - // TODO(b/200737967): mock this. - return DumpResult{}; + return mDumpResult; } StatusCode MockVehicleHardware::checkHealth() { - // TODO(b/200737967): mock this. return StatusCode::OK; } diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h index 0844de1ab3..74d4fae337 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h @@ -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& requests, std::list>* storedRequests, std::list>* storedResponses) const REQUIRES(mLock); + + DumpResult mDumpResult; }; } // namespace vehicle diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp b/automotive/vehicle/proto/Android.bp similarity index 94% rename from automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp rename to automotive/vehicle/proto/Android.bp index 3307bd62a3..683f1281c4 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp +++ b/automotive/vehicle/proto/Android.bp @@ -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, diff --git a/automotive/vehicle/proto/VehicleHalProto.proto b/automotive/vehicle/proto/VehicleHalProto.proto new file mode 100644 index 0000000000..0dafe8c4a6 --- /dev/null +++ b/automotive/vehicle/proto/VehicleHalProto.proto @@ -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 +};