From 3b0b9b26c0f448453110d9d2ad202f5ee3a9c4e8 Mon Sep 17 00:00:00 2001 From: Yu Shan Date: Fri, 21 Jun 2024 18:53:07 -0700 Subject: [PATCH] Allow using area name in debug command. Allow using area name instead of area ID in debug commands. Also support AREA_1 | AREA_2 syntax. We will check the area according to the area type specified for the property ID. Flag: EXEMPT HAL Test: atest FakeVehicleHardwareTest Bug: 328316981 Change-Id: I646b76b302e58c2d0ec0ff66740da3394df62b2a --- .../hardware/include/FakeVehicleHardware.h | 2 + .../hardware/src/FakeVehicleHardware.cpp | 51 +++++++++-- .../hardware/test/FakeVehicleHardwareTest.cpp | 91 +++++++++++++++++++ .../impl/utils/common/include/VehicleUtils.h | 3 + .../impl/utils/common/src/VehicleUtils.cpp | 58 +++++++++++- 5 files changed, 197 insertions(+), 8 deletions(-) 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 79d3e77f84..ec69894cd0 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h @@ -327,6 +327,8 @@ class FakeVehicleHardware : public IVehicleHardware { static android::base::Result safelyParseFloat(int index, const std::string& s); static android::base::Result parsePropId(const std::vector& options, size_t index); + static android::base::Result parseAreaId(const std::vector& options, + size_t index, int32_t propId); }; } // 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 200e3d3964..237a4c4967 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp @@ -1902,6 +1902,37 @@ Result FakeVehicleHardware::parsePropId(const std::vector& return safelyParseInt(index, propIdStr); } +// Parses areaId option ("-a"). It can be an Integer or a string in the form of "AREA_1" or +// "AREA_1 | AREA_2 | ..." +Result FakeVehicleHardware::parseAreaId(const std::vector& options, + size_t index, int32_t propId) { + const std::string& areaIdStr = options[index]; + auto result = safelyParseInt(index, areaIdStr); + if (result.ok()) { + return result; + } + + // Check for pattern matching "AREA_1 | AREA_2 | AREA_3". + std::regex pattern(R"(^\w+(?:( )?\|( )?\w+)*$)"); + std::smatch match; + int32_t areaId = 0; + if (!std::regex_match(areaIdStr, match, pattern)) { + return result; + } + pattern = R"(\w+)"; + + std::sregex_iterator end; + for (std::sregex_iterator it(areaIdStr.begin(), areaIdStr.end(), pattern); it != end; it++) { + // Parse each areas contained in this areaId. + auto result = stringToArea(it->str(), propId); + if (!result.ok()) { + return result; + } + areaId |= result.value(); + } + return areaId; +} + std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector& options) { if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) { return getErrorMsg(result); @@ -1958,6 +1989,7 @@ Result FakeVehicleHardware::parsePropOptions( prop.status = VehiclePropertyStatus::AVAILABLE; optionIndex++; std::unordered_set parsedOptions; + int32_t areaIdIndex = -1; while (optionIndex < options.size()) { std::string argType = options[optionIndex]; @@ -2032,13 +2064,7 @@ Result FakeVehicleHardware::parsePropOptions( if (argValuesSize != 1) { return Error() << "Expect exact one value when using \"-a\"\n"; } - auto int32Result = safelyParseInt(currentIndex, argValues[0]); - if (!int32Result.ok()) { - return Error() << StringPrintf("Area ID: \"%s\" is not a valid int: %s\n", - argValues[0].c_str(), - getErrorMsg(int32Result).c_str()); - } - prop.areaId = int32Result.value(); + areaIdIndex = currentIndex; } else if (EqualsIgnoreCase(argType, "-t")) { if (argValuesSize != 1) { return Error() << "Expect exact one value when using \"-t\"\n"; @@ -2055,6 +2081,17 @@ Result FakeVehicleHardware::parsePropOptions( } } + if (areaIdIndex != -1) { + auto int32Result = parseAreaId(options, areaIdIndex, prop.prop); + if (!int32Result.ok()) { + return Error() << StringPrintf( + "Area ID: \"%s\" is not a valid int or " + "one or more area names: %s\n", + options[areaIdIndex].c_str(), getErrorMsg(int32Result).c_str()); + } + prop.areaId = int32Result.value(); + } + return prop; } 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 0924360b9f..8dbba1993d 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp @@ -77,6 +77,7 @@ using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport; using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq; using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateShutdownParam; using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror; +using ::aidl::android::hardware::automotive::vehicle::VehicleAreaSeat; using ::aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction; using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig; using ::aidl::android::hardware::automotive::vehicle::VehicleProperty; @@ -2781,6 +2782,8 @@ TEST_P(FakeVehicleHardwareSetPropTest, cmdSetOneProperty) { std::vector GenSetPropParams() { std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE)); + std::string testVendorProperty = + std::to_string(toInt(TestVendorProperty::VENDOR_EXTENSION_FLOAT_PROPERTY)); return { {"success_set_string", {"--set", infoMakeProperty, "-s", CAR_MAKE}, true}, {"success_set_with_name", {"--set", "INFO_MAKE", "-s", CAR_MAKE}, true}, @@ -2889,6 +2892,14 @@ std::vector GenSetPropParams() { {"--set", infoMakeProperty, "-a", "-s", CAR_MAKE}, false, "Expect exact one value"}, + {"fail_invalid_area_name", + {"--set", testVendorProperty, "-a", "ROW_1_LEFT|NO_SUCH_AREA", "-f", "1.234"}, + false, + "not a valid int or one or more area names"}, + {"fail_invalid_area_format", + {"--set", testVendorProperty, "-a", "ROW_1_LEFT|||ROW_2_LEFT", "-f", "1.234"}, + false, + "not a valid int or one or more area names"}, }; } @@ -2933,6 +2944,86 @@ TEST_F(FakeVehicleHardwareTest, SetComplexPropTest) { ASSERT_EQ(3.402823466E+38f, value.value.floatValues[2]); } +TEST_F(FakeVehicleHardwareTest, SetPropertyWithPropertyNameAreaId) { + int32_t areaId = toInt(VehicleAreaSeat::ROW_1_LEFT); + getHardware()->dump( + {"--set", "HVAC_TEMPERATURE_SET", "-a", std::to_string(areaId), "-f", "22.345"}); + + VehiclePropValue requestProp; + requestProp.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET); + requestProp.areaId = areaId; + auto result = getValue(requestProp); + + ASSERT_TRUE(result.ok()); + VehiclePropValue value = result.value(); + ASSERT_EQ(value.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); + ASSERT_EQ(value.areaId, areaId); + ASSERT_EQ(1u, value.value.floatValues.size()); + ASSERT_EQ(22.345f, value.value.floatValues[0]); +} + +TEST_F(FakeVehicleHardwareTest, SetPropertyWithPropertyNameAreaName) { + int32_t areaId = toInt(VehicleAreaSeat::ROW_1_LEFT); + getHardware()->dump({"--set", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT", "-f", "22.345"}); + + VehiclePropValue requestProp; + requestProp.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET); + requestProp.areaId = areaId; + auto result = getValue(requestProp); + + ASSERT_TRUE(result.ok()); + VehiclePropValue value = result.value(); + ASSERT_EQ(value.prop, toInt(VehicleProperty::HVAC_TEMPERATURE_SET)); + ASSERT_EQ(value.areaId, areaId); + ASSERT_EQ(1u, value.value.floatValues.size()); + ASSERT_EQ(22.345f, value.value.floatValues[0]); +} + +TEST_F(FakeVehicleHardwareTest, GetPropertyWithPropertyNameAreaName) { + auto result = getHardware()->dump({"--get", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT"}); + + // Default value is 17 + ASSERT_THAT(result.buffer, ContainsRegex("17")); + + getHardware()->dump({"--set", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT", "-f", "22"}); + result = getHardware()->dump({"--get", "HVAC_TEMPERATURE_SET", "-a", "ROW_1_LEFT"}); + + ASSERT_THAT(result.buffer, ContainsRegex("22")); +} + +TEST_F(FakeVehicleHardwareTest, SetPropertyWithPropertyNameTwoAreasInOneId) { + int32_t propId = toInt(TestVendorProperty::VENDOR_EXTENSION_FLOAT_PROPERTY); + std::string testVendorProperty = std::to_string(propId); + getHardware()->dump({"--set", testVendorProperty, "-a", "ROW_1_LEFT|ROW_2_LEFT|ROW_2_CENTER", + "-f", "1.234"}); + + VehiclePropValue requestProp; + requestProp.prop = propId; + int32_t areaId = toInt(VehicleAreaSeat::ROW_1_LEFT) | toInt(VehicleAreaSeat::ROW_2_LEFT) | + toInt(VehicleAreaSeat::ROW_2_CENTER); + requestProp.areaId = areaId; + auto result = getValue(requestProp); + + ASSERT_TRUE(result.ok()); + VehiclePropValue value = result.value(); + ASSERT_EQ(value.prop, propId); + ASSERT_EQ(value.areaId, areaId); + ASSERT_EQ(1u, value.value.floatValues.size()); + ASSERT_EQ(1.234f, value.value.floatValues[0]); + + // Ignore space between two areas. + getHardware()->dump({"--set", testVendorProperty, "-a", + "ROW_1_LEFT | ROW_2_LEFT | ROW_2_CENTER", "-f", "2.345"}); + result = getValue(requestProp); + + ASSERT_TRUE(result.ok()); + value = result.value(); + ASSERT_EQ(value.prop, propId); + ASSERT_EQ(value.areaId, areaId); + ASSERT_EQ(1u, value.value.floatValues.size()); + ASSERT_EQ(2.345f, value.value.floatValues[0]); +} + struct OptionsTestCase { std::string name; std::vector options; diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h index f48bb2aa34..90a7c46f3f 100644 --- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h +++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h @@ -337,6 +337,9 @@ inline std::string propIdToString(int32_t propId) { // This is for debug purpose only. android::base::Result stringToPropId(const std::string& propName); +// This is for debug purpose only. Converts an area's name to its enum definition. +android::base::Result stringToArea(const std::string& areaName, int32_t propId); + template void roundToNearestResolution(std::vector& arrayToSanitize, float resolution) { if (resolution == 0) { diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp index 4d06e4e32d..7814c9993e 100644 --- a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp +++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp @@ -25,7 +25,13 @@ namespace vehicle { using ::aidl::android::hardware::automotive::vehicle::StatusCode; using ::aidl::android::hardware::automotive::vehicle::toString; +using ::aidl::android::hardware::automotive::vehicle::VehicleArea; using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig; +using ::aidl::android::hardware::automotive::vehicle::VehicleAreaDoor; +using ::aidl::android::hardware::automotive::vehicle::VehicleAreaMirror; +using ::aidl::android::hardware::automotive::vehicle::VehicleAreaSeat; +using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWheel; +using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow; using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig; using ::aidl::android::hardware::automotive::vehicle::VehicleProperty; using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup; @@ -44,7 +50,7 @@ class PropertyIdByNameSingleton { return instance; } - Result getPropertyId(const std::string& name) { + Result getPropertyId(const std::string& name) const { auto it = mPropertyIdByName.find(name); if (it == mPropertyIdByName.end()) { return Error(); @@ -66,6 +72,52 @@ class PropertyIdByNameSingleton { } }; +class AreaByNameSingleton { + public: + static AreaByNameSingleton& getInstance() { + static AreaByNameSingleton instance; + return instance; + } + + Result getArea(const std::string& name, int32_t propId) const { + VehicleArea areaType = getPropArea(propId); + + auto mapIt = mAreaByNameByAreaType.find(areaType); + if (mapIt == mAreaByNameByAreaType.end()) { + return Error() << "Invalid area type for property ID: " << propIdToString(propId); + } + + const auto& areaByName = mapIt->second; + auto it = areaByName.find(name); + if (it == areaByName.end()) { + return Error() << "Invalid area name for property " << propIdToString(propId) << ": " + << name; + } + return it->second; + } + + AreaByNameSingleton(AreaByNameSingleton const&) = delete; + void operator=(AreaByNameSingleton const&) = delete; + + private: + std::unordered_map> mAreaByNameByAreaType; + + AreaByNameSingleton() { + populateMap(VehicleArea::WINDOW, ndk::internal::enum_values); + populateMap(VehicleArea::MIRROR, ndk::internal::enum_values); + populateMap(VehicleArea::SEAT, ndk::internal::enum_values); + populateMap(VehicleArea::DOOR, ndk::internal::enum_values); + populateMap(VehicleArea::WHEEL, ndk::internal::enum_values); + } + + template + void populateMap(VehicleArea areaType, std::array values) { + for (unsigned int i = 0; i < values.size(); i++) { + mAreaByNameByAreaType[areaType].emplace(toString(values[i]), toInt(values[i])); + } + } +}; + } // namespace Result checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) { @@ -254,6 +306,10 @@ Result stringToPropId(const std::string& propName) { return PropertyIdByNameSingleton::getInstance().getPropertyId(propName); } +Result stringToArea(const std::string& areaName, int32_t propId) { + return AreaByNameSingleton::getInstance().getArea(areaName, propId); +} + } // namespace vehicle } // namespace automotive } // namespace hardware