Merge "Convert VehicleHalDefaultConfig to JsonConfigLoader."

This commit is contained in:
TreeHugger Robot
2022-08-03 18:07:29 +00:00
committed by Android (Google) Code Review
16 changed files with 327 additions and 167 deletions

View File

@@ -89,7 +89,8 @@ class JsonValueParser final {
// The main class to parse a VHAL config file in JSON format.
class JsonConfigParser {
public:
android::base::Result<std::vector<ConfigDeclaration>> parseJsonConfig(std::istream& is);
android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> parseJsonConfig(
std::istream& is);
private:
JsonValueParser mValueParser;
@@ -155,8 +156,13 @@ class JsonConfigLoader final {
public:
JsonConfigLoader();
// Loads a JSON file stream and parses it to a list of ConfigDeclarations.
android::base::Result<std::vector<ConfigDeclaration>> loadPropConfig(std::istream& is);
// Loads a JSON file stream and parses it to a map from propId to ConfigDeclarations.
android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> loadPropConfig(
std::istream& is);
// Loads a JSON config file and parses it to a map from propId to ConfigDeclarations.
android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> loadPropConfig(
const std::string& configPath);
private:
std::unique_ptr<jsonconfigloader_impl::JsonConfigParser> mParser;

View File

@@ -25,6 +25,7 @@
#endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
#include <android-base/strings.h>
#include <fstream>
namespace android {
namespace hardware {
@@ -509,25 +510,32 @@ std::optional<ConfigDeclaration> JsonConfigParser::parseEachProperty(
return configDecl;
}
Result<std::vector<ConfigDeclaration>> JsonConfigParser::parseJsonConfig(std::istream& is) {
Result<std::unordered_map<int32_t, ConfigDeclaration>> JsonConfigParser::parseJsonConfig(
std::istream& is) {
Json::CharReaderBuilder builder;
Json::Value root;
std::vector<ConfigDeclaration> configs;
std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
std::string errs;
if (!Json::parseFromStream(builder, is, &root, &errs)) {
return Error() << "Failed to parse property config file as JSON, error: " << errs;
}
if (!root.isObject()) {
return Error() << "root element must be an object";
}
if (!root.isMember("properties") || !root["properties"].isArray()) {
return Error() << "Missing 'properties' field in root or the field is not an array";
}
Json::Value properties = root["properties"];
std::vector<std::string> errors;
for (unsigned int i = 0; i < properties.size(); i++) {
if (auto maybeConfig = parseEachProperty(properties[i], &errors); maybeConfig.has_value()) {
configs.push_back(std::move(maybeConfig.value()));
configsByPropId[maybeConfig.value().config.prop] = std::move(maybeConfig.value());
}
}
if (!errors.empty()) {
return Error() << android::base::Join(errors, '\n');
}
return configs;
return configsByPropId;
}
} // namespace jsonconfigloader_impl
@@ -536,11 +544,21 @@ JsonConfigLoader::JsonConfigLoader() {
mParser = std::make_unique<jsonconfigloader_impl::JsonConfigParser>();
}
android::base::Result<std::vector<ConfigDeclaration>> JsonConfigLoader::loadPropConfig(
std::istream& is) {
android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>>
JsonConfigLoader::loadPropConfig(std::istream& is) {
return mParser->parseJsonConfig(is);
}
android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>>
JsonConfigLoader::loadPropConfig(const std::string& configPath) {
std::ifstream ifs(configPath.c_str());
if (!ifs) {
return android::base::Error() << "couldn't open " << configPath << " for parsing.";
}
return loadPropConfig(ifs);
}
} // namespace vehicle
} // namespace automotive
} // namespace hardware

View File

@@ -38,7 +38,7 @@ class JsonConfigLoaderUnitTest : public ::testing::Test {
JsonConfigLoader mLoader;
};
TEST_F(JsonConfigLoaderUnitTest, TestBasic) {
TEST_F(JsonConfigLoaderUnitTest, testBasic) {
std::istringstream iss(R"(
{
"properties": [{
@@ -53,11 +53,39 @@ TEST_F(JsonConfigLoaderUnitTest, TestBasic) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
ASSERT_EQ(configs[0].config.prop, 291504388);
ASSERT_EQ(configs.begin()->second.config.prop, 291504388);
}
TEST_F(JsonConfigLoaderUnitTest, TestPropertyIsEnum) {
TEST_F(JsonConfigLoaderUnitTest, testRootNotObject) {
std::istringstream iss(R"(
[]
)");
ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "root is not an object must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, testMissingPropertiesField) {
std::istringstream iss(R"(
{
"abcd": 1234
}
)");
ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "Missing 'properties' field must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, testPropertiesFieldNotArray) {
std::istringstream iss(R"(
{
"properties': {'a': 'b'}
}
)");
ASSERT_FALSE(mLoader.loadPropConfig(iss).ok())
<< "'properties' field is not an array must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, testPropertyIsEnum) {
std::istringstream iss(R"(
{
"properties": [{
@@ -72,11 +100,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestPropertyIsEnum) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
ASSERT_EQ(configs[0].config.prop, toInt(VehicleProperty::INFO_FUEL_CAPACITY));
ASSERT_EQ(configs.begin()->second.config.prop, toInt(VehicleProperty::INFO_FUEL_CAPACITY));
}
TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidEnum) {
TEST_F(JsonConfigLoaderUnitTest, testPropertyEnum_FailInvalidEnum) {
std::istringstream iss(R"(
{
"properties": [{
@@ -89,7 +116,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidEnum) {
<< "Invalid VehicleProperty enum must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidType) {
TEST_F(JsonConfigLoaderUnitTest, testPropertyEnum_FailInvalidType) {
std::istringstream iss(R"(
{
"properties": [{
@@ -102,7 +129,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidType) {
<< "Invalid VehicleProperty type must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestProperty_FailInvalidJson) {
TEST_F(JsonConfigLoaderUnitTest, testProperty_FailInvalidJson) {
std::istringstream iss(R"(
{
"properties": [{
@@ -112,7 +139,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestProperty_FailInvalidJson) {
ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "Invalid JSON format must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestConfigArray) {
TEST_F(JsonConfigLoaderUnitTest, testConfigArray) {
std::istringstream iss(R"(
{
"properties": [{
@@ -128,10 +155,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArray) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
ASSERT_EQ(configs[0].config.configArray, std::vector<int>({1, 2, 3}));
ASSERT_EQ(configs.begin()->second.config.configArray, std::vector<int>({1, 2, 3}));
}
TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayConstants) {
TEST_F(JsonConfigLoaderUnitTest, testConfigArrayConstants) {
std::istringstream iss(R"(
{
"properties": [{
@@ -147,11 +174,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayConstants) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
ASSERT_EQ(configs[0].config.configArray, std::vector<int>({1, 2, FUEL_DOOR_REAR_LEFT}));
ASSERT_EQ(configs.begin()->second.config.configArray,
std::vector<int>({1, 2, FUEL_DOOR_REAR_LEFT}));
}
// We have special logic to deal with GALLON and US_GALLON since they share the same value.
TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitGallon) {
TEST_F(JsonConfigLoaderUnitTest, testConfigArrayUnitGallon) {
std::istringstream iss(R"(
{
"properties": [{
@@ -166,7 +194,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitGallon) {
ASSERT_TRUE(result.ok()) << result.error().message();
}
TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitUsGallon) {
TEST_F(JsonConfigLoaderUnitTest, testConfigArrayUnitUsGallon) {
std::istringstream iss(R"(
{
"properties": [{
@@ -181,7 +209,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitUsGallon) {
ASSERT_TRUE(result.ok()) << result.error().message();
}
TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailInvalidEnum) {
TEST_F(JsonConfigLoaderUnitTest, testConfigArray_FailInvalidEnum) {
std::istringstream iss(R"(
{
"properties": [{
@@ -195,7 +223,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailInvalidEnum) {
<< "Invalid enum in ConfigArray must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailNotArray) {
TEST_F(JsonConfigLoaderUnitTest, testConfigArray_FailNotArray) {
std::istringstream iss(R"(
{
"properties": [{
@@ -209,7 +237,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailNotArray) {
<< "ConfigArray is not an array must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestConfigString) {
TEST_F(JsonConfigLoaderUnitTest, testConfigString) {
std::istringstream iss(R"(
{
"properties": [{
@@ -225,10 +253,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigString) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
ASSERT_EQ(configs[0].config.configString, "test");
ASSERT_EQ(configs.begin()->second.config.configString, "test");
}
TEST_F(JsonConfigLoaderUnitTest, TestConfigString_FailNotString) {
TEST_F(JsonConfigLoaderUnitTest, testConfigString_FailNotString) {
std::istringstream iss(R"(
{
"properties": [{
@@ -242,7 +270,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigString_FailNotString) {
<< "ConfigString is not a String must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestCheckDefaultAccessChangeMode) {
TEST_F(JsonConfigLoaderUnitTest, testCheckDefaultAccessChangeMode) {
std::istringstream iss(R"(
{
"properties": [{
@@ -257,12 +285,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestCheckDefaultAccessChangeMode) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
const VehiclePropConfig& propConfig = configs[0].config;
const VehiclePropConfig& propConfig = configs.begin()->second.config;
ASSERT_EQ(propConfig.access, VehiclePropertyAccess::READ);
ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::STATIC);
}
TEST_F(JsonConfigLoaderUnitTest, TestAccessOverride) {
TEST_F(JsonConfigLoaderUnitTest, testAccessOverride) {
std::istringstream iss(R"(
{
"properties": [{
@@ -278,12 +306,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestAccessOverride) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
const VehiclePropConfig& propConfig = configs[0].config;
const VehiclePropConfig& propConfig = configs.begin()->second.config;
ASSERT_EQ(propConfig.access, VehiclePropertyAccess::WRITE);
ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::STATIC);
}
TEST_F(JsonConfigLoaderUnitTest, TestChangeModeOverride) {
TEST_F(JsonConfigLoaderUnitTest, testChangeModeOverride) {
std::istringstream iss(R"(
{
"properties": [{
@@ -299,12 +327,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestChangeModeOverride) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
const VehiclePropConfig& propConfig = configs[0].config;
const VehiclePropConfig& propConfig = configs.begin()->second.config;
ASSERT_EQ(propConfig.access, VehiclePropertyAccess::READ);
ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::ON_CHANGE);
}
TEST_F(JsonConfigLoaderUnitTest, TestCustomProp) {
TEST_F(JsonConfigLoaderUnitTest, testCustomProp) {
std::istringstream iss(R"(
{
"properties": [{
@@ -321,12 +349,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestCustomProp) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
const VehiclePropConfig& propConfig = configs[0].config;
const VehiclePropConfig& propConfig = configs.begin()->second.config;
ASSERT_EQ(propConfig.access, VehiclePropertyAccess::WRITE);
ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::ON_CHANGE);
}
TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingAccess) {
TEST_F(JsonConfigLoaderUnitTest, testCustomProp_FailMissingAccess) {
std::istringstream iss(R"(
{
"properties": [{
@@ -340,7 +368,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingAccess) {
<< "Missing access for custom property must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingChangeMode) {
TEST_F(JsonConfigLoaderUnitTest, testCustomProp_FailMissingChangeMode) {
std::istringstream iss(R"(
{
"properties": [{
@@ -354,7 +382,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingChangeMode) {
<< "Missing change mode for custom property must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate) {
TEST_F(JsonConfigLoaderUnitTest, testMinSampleRate) {
std::istringstream iss(R"(
{
"properties": [{
@@ -370,10 +398,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
ASSERT_EQ(configs[0].config.minSampleRate, 1);
ASSERT_EQ(configs.begin()->second.config.minSampleRate, 1);
}
TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate_FailInvalidType) {
TEST_F(JsonConfigLoaderUnitTest, testMinSampleRate_FailInvalidType) {
std::istringstream iss(R"(
{
"properties": [{
@@ -387,7 +415,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate_FailInvalidType) {
<< "Wrong type for MinSampleRate must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate) {
TEST_F(JsonConfigLoaderUnitTest, testMaxSampleRate) {
std::istringstream iss(R"(
{
"properties": [{
@@ -403,10 +431,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
ASSERT_EQ(configs[0].config.maxSampleRate, 1);
ASSERT_EQ(configs.begin()->second.config.maxSampleRate, 1);
}
TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate_FailInvalidType) {
TEST_F(JsonConfigLoaderUnitTest, testMaxSampleRate_FailInvalidType) {
std::istringstream iss(R"(
{
"properties": [{
@@ -420,7 +448,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate_FailInvalidType) {
<< "Wrong type for MaxSampleRate must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Simple) {
TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_Simple) {
std::istringstream iss(R"(
{
"properties": [{
@@ -438,10 +466,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Simple) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
ASSERT_EQ(configs[0].initialValue.int32Values, std::vector<int32_t>({1, 2}));
ASSERT_EQ(configs.begin()->second.initialValue.int32Values, std::vector<int32_t>({1, 2}));
}
TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Mixed) {
TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_Mixed) {
std::istringstream iss(R"(
{
"properties": [{
@@ -463,7 +491,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Mixed) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
const RawPropValues& initialValue = configs[0].initialValue;
const RawPropValues& initialValue = configs.begin()->second.initialValue;
ASSERT_EQ(initialValue.int32Values, std::vector<int32_t>({1, FUEL_DOOR_REAR_LEFT}));
ASSERT_EQ(initialValue.int64Values,
std::vector<int64_t>({2, static_cast<int64_t>(FUEL_DOOR_REAR_LEFT)}));
@@ -472,7 +500,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Mixed) {
ASSERT_EQ(initialValue.stringValue, "abcd");
}
TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailNotObject) {
TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_FailNotObject) {
std::istringstream iss(R"(
{
"properties": [{
@@ -486,7 +514,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailNotObject) {
<< "DefaultValue is not an object must cause error";
}
TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailInvalidType) {
TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_FailInvalidType) {
std::istringstream iss(R"(
{
"properties": [{
@@ -521,7 +549,7 @@ TEST_F(JsonConfigLoaderUnitTest, testAreas_Simple) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
const VehiclePropConfig& config = configs[0].config;
const VehiclePropConfig& config = configs.begin()->second.config;
ASSERT_EQ(config.areaConfigs.size(), 1u);
const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
ASSERT_EQ(areaConfig.minInt32Value, 1);
@@ -554,12 +582,14 @@ TEST_F(JsonConfigLoaderUnitTest, testAreas_DefaultValueForEachArea) {
auto configs = result.value();
ASSERT_EQ(configs.size(), 1u);
const VehiclePropConfig& config = configs[0].config;
const VehiclePropConfig& config = configs.begin()->second.config;
ASSERT_EQ(config.areaConfigs.size(), 2u);
ASSERT_EQ(config.areaConfigs[0].areaId, HVAC_LEFT);
ASSERT_EQ(config.areaConfigs[1].areaId, HVAC_RIGHT);
ASSERT_EQ(configs[0].initialAreaValues[HVAC_LEFT], RawPropValues{.int32Values = {1}});
ASSERT_EQ(configs[0].initialAreaValues[HVAC_RIGHT], RawPropValues{.int32Values = {2}});
ASSERT_EQ(configs.begin()->second.initialAreaValues[HVAC_LEFT],
RawPropValues{.int32Values = {1}});
ASSERT_EQ(configs.begin()->second.initialAreaValues[HVAC_RIGHT],
RawPropValues{.int32Values = {2}});
}
TEST_F(JsonConfigLoaderUnitTest, testAreas_FailInvalidTypeForOneAreaValue) {

View File

@@ -21,3 +21,27 @@ filegroup {
name: "VehicleHalVendorClusterTestProperties_JSON",
srcs: ["VendorClusterTestProperties.json"],
}
prebuilt_etc {
name: "Prebuilt_VehicleHalDefaultProperties_JSON",
filename_from_src: true,
src: "DefaultProperties.json",
sub_dir: "automotive/vhalconfig/",
vendor: true,
}
prebuilt_etc {
name: "Prebuilt_VehicleHalTestProperties_JSON",
filename_from_src: true,
src: "TestProperties.json",
sub_dir: "automotive/vhalconfig/",
vendor: true,
}
prebuilt_etc {
name: "Prebuilt_VehicleHalVendorClusterTestProperties_JSON",
filename_from_src: true,
src: "VendorClusterTestProperties.json",
sub_dir: "automotive/vhalconfig/",
vendor: true,
}

View File

@@ -21,6 +21,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <fstream>
#include <unordered_map>
namespace android {
namespace hardware {
@@ -45,7 +46,8 @@ std::string getTestFilePath(const char* filename) {
return baseDir + "/" + filename;
}
Result<std::vector<ConfigDeclaration>> loadConfig(JsonConfigLoader& loader, const char* path) {
Result<std::unordered_map<int32_t, ConfigDeclaration>> loadConfig(JsonConfigLoader& loader,
const char* path) {
std::string configPath = getTestFilePath(path);
std::ifstream ifs(configPath.c_str());
if (!ifs) {
@@ -89,7 +91,9 @@ TEST(DefaultConfigTest, TestCompatibleWithDefaultConfigHeader) {
kVendorClusterTestPropertiesConfigFile})) {
auto result = loadConfig(loader, file);
ASSERT_TRUE(result.ok()) << result.error().message();
configsFromJson.insert(configsFromJson.end(), result.value().begin(), result.value().end());
for (auto& [propId, configDeclaration] : result.value()) {
configsFromJson.push_back(configDeclaration);
}
}
ASSERT_EQ(configsFromHeaderFile.size(), configsFromJson.size());

View File

@@ -24,6 +24,7 @@ cc_library {
srcs: ["src/*.cpp"],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
defaults: [
"VehicleHalDefaults",
"FakeVehicleHardwareDefaults",
@@ -32,18 +33,23 @@ cc_library {
cc_defaults {
name: "FakeVehicleHardwareDefaults",
cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"],
header_libs: [
"IVehicleHardware",
"VehicleHalDefaultConfig",
"VehicleHalTestUtilHeaders",
],
export_header_lib_headers: ["IVehicleHardware"],
static_libs: [
"VehicleHalJsonConfigLoaderEnableTestProperties",
"VehicleHalUtils",
"FakeVehicleHalValueGenerators",
"FakeObd2Frame",
"FakeUserHal",
],
required: [
"Prebuilt_VehicleHalDefaultProperties_JSON",
"Prebuilt_VehicleHalTestProperties_JSON",
"Prebuilt_VehicleHalVendorClusterTestProperties_JSON",
],
shared_libs: [
"libjsoncpp",
],

View File

@@ -18,11 +18,12 @@
#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
#include <ConcurrentQueue.h>
#include <DefaultConfig.h>
#include <ConfigDeclaration.h>
#include <FakeObd2Frame.h>
#include <FakeUserHal.h>
#include <GeneratorHub.h>
#include <IVehicleHardware.h>
#include <JsonConfigLoader.h>
#include <RecurrentTimer.h>
#include <VehicleHalTypes.h>
#include <VehiclePropertyStore.h>
@@ -32,9 +33,9 @@
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <map>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <vector>
namespace android {
@@ -49,7 +50,8 @@ class FakeVehicleHardware : public IVehicleHardware {
FakeVehicleHardware();
explicit FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool);
FakeVehicleHardware(std::string defaultConfigDir, std::string overrideConfigDir,
bool forceOverride);
~FakeVehicleHardware();
@@ -151,17 +153,23 @@ class FakeVehicleHardware : public IVehicleHardware {
aidl::android::hardware::automotive::vehicle::SetValueRequest>
mPendingSetValueRequests;
const std::string mDefaultConfigDir;
const std::string mOverrideConfigDir;
const bool mForceOverride;
// Only used during initialization.
JsonConfigLoader mLoader;
void init();
// Stores the initial value to property store.
void storePropInitialValue(const ConfigDeclaration& config);
// The callback that would be called when a vehicle property value change happens.
void onValueChangeCallback(
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
// If property "persist.vendor.vhal_init_value_override" is set to true, override the properties
// using config files in 'overrideDir'.
void maybeOverrideProperties(const char* overrideDir);
// Override the properties using config files in 'overrideDir'.
void overrideProperties(const char* overrideDir);
// Load the config files in format '*.json' from the directory and parse the config files
// into a map from property ID to ConfigDeclarations.
void loadPropConfigsFromDir(const std::string& dirPath,
std::unordered_map<int32_t, ConfigDeclaration>* configs);
// Function to be called when a value change event comes from vehicle bus. In our fake
// implementation, this function is only called during "--inject-event" dump command.
void eventFromVehicleBus(
@@ -185,6 +193,8 @@ class FakeVehicleHardware : public IVehicleHardware {
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
bool isHvacPropAndHvacNotAvailable(int32_t propId);
std::unordered_map<int32_t, ConfigDeclaration> loadConfigDeclarations();
std::string dumpAllProperties();
std::string dumpOnePropertyByConfig(
int rowNumber,

View File

@@ -19,7 +19,6 @@
#include "FakeVehicleHardware.h"
#include <DefaultConfig.h>
#include <FakeObd2Frame.h>
#include <JsonFakeValueGenerator.h>
#include <LinearFakeValueGenerator.h>
@@ -27,6 +26,8 @@
#include <TestPropertyUtils.h>
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
#include <android-base/file.h>
#include <android-base/parsedouble.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
@@ -74,9 +75,16 @@ using ::android::base::ScopedLockAssertion;
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";
const char* POWER_STATE_REQ_CONFIG_PROPERTY = "ro.vendor.fake_vhal.ap_power_state_req.config";
// The directory for default property configuration file.
// For config file format, see impl/default_config/config/README.md.
constexpr char DEFAULT_CONFIG_DIR[] = "/vendor/etc/automotive/vhalconfig/";
// The directory for property configuration file that overrides the default configuration file.
// For config file format, see impl/default_config/config/README.md.
constexpr char OVERRIDE_CONFIG_DIR[] = "/vendor/etc/automotive/vhaloverride/";
// If OVERRIDE_PROPERTY is set, we will use the configuration files from OVERRIDE_CONFIG_DIR to
// overwrite the default configs.
constexpr char OVERRIDE_PROPERTY[] = "persist.vendor.vhal_init_value_override";
constexpr char POWER_STATE_REQ_CONFIG_PROPERTY[] = "ro.vendor.fake_vhal.ap_power_state_req.config";
// A list of supported options for "--set" command.
const std::unordered_set<std::string> SET_PROP_OPTIONS = {
@@ -139,10 +147,11 @@ void FakeVehicleHardware::storePropInitialValue(const ConfigDeclaration& config)
}
FakeVehicleHardware::FakeVehicleHardware()
: FakeVehicleHardware(std::make_unique<VehiclePropValuePool>()) {}
: FakeVehicleHardware(DEFAULT_CONFIG_DIR, OVERRIDE_CONFIG_DIR, false) {}
FakeVehicleHardware::FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool)
: mValuePool(std::move(valuePool)),
FakeVehicleHardware::FakeVehicleHardware(std::string defaultConfigDir,
std::string overrideConfigDir, bool forceOverride)
: mValuePool(std::make_unique<VehiclePropValuePool>()),
mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
mFakeUserHal(new FakeUserHal(mValuePool)),
@@ -150,7 +159,10 @@ FakeVehicleHardware::FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> v
mGeneratorHub(new GeneratorHub(
[this](const VehiclePropValue& value) { eventFromVehicleBus(value); })),
mPendingGetValueRequests(this),
mPendingSetValueRequests(this) {
mPendingSetValueRequests(this),
mDefaultConfigDir(defaultConfigDir),
mOverrideConfigDir(overrideConfigDir),
mForceOverride(forceOverride) {
init();
}
@@ -160,9 +172,19 @@ FakeVehicleHardware::~FakeVehicleHardware() {
mGeneratorHub.reset();
}
std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
if (mForceOverride ||
android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false)) {
loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
}
return configsByPropId;
}
void FakeVehicleHardware::init() {
for (auto& it : defaultconfig::getDefaultConfigs()) {
VehiclePropConfig cfg = it.config;
for (auto& [_, configDeclaration] : loadConfigDeclarations()) {
VehiclePropConfig cfg = configDeclaration.config;
VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
if (cfg.prop == toInt(VehicleProperty::AP_POWER_STATE_REQ)) {
@@ -178,15 +200,18 @@ void FakeVehicleHardware::init() {
// logic.
continue;
}
storePropInitialValue(it);
storePropInitialValue(configDeclaration);
}
maybeOverrideProperties(VENDOR_OVERRIDE_DIR);
// OBD2_LIVE_FRAME and OBD2_FREEZE_FRAME must be configured in default configs.
mFakeObd2Frame->initObd2LiveFrame(*mServerSidePropStore->getConfig(OBD2_LIVE_FRAME).value());
mFakeObd2Frame->initObd2FreezeFrame(
*mServerSidePropStore->getConfig(OBD2_FREEZE_FRAME).value());
auto maybeObd2LiveFrame = mServerSidePropStore->getConfig(OBD2_LIVE_FRAME);
if (maybeObd2LiveFrame.has_value()) {
mFakeObd2Frame->initObd2LiveFrame(*maybeObd2LiveFrame.value());
}
auto maybeObd2FreezeFrame = mServerSidePropStore->getConfig(OBD2_FREEZE_FRAME);
if (maybeObd2FreezeFrame.has_value()) {
mFakeObd2Frame->initObd2FreezeFrame(*maybeObd2FreezeFrame.value());
}
mServerSidePropStore->setOnValueChangeCallback(
[this](const VehiclePropValue& value) { return onValueChangeCallback(value); });
@@ -408,7 +433,7 @@ VhalResult<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValu
*isSpecialValue = true;
return mFakeObd2Frame->clearObd2FreezeFrames(value);
#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
#ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
case toInt(VehicleProperty::CLUSTER_REPORT_STATE):
[[fallthrough]];
case toInt(VehicleProperty::CLUSTER_REQUEST_DISPLAY):
@@ -436,7 +461,7 @@ VhalResult<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValu
<< getErrorMsg(writeResult);
}
return {};
#endif // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
#endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
default:
break;
@@ -1264,33 +1289,26 @@ void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
(*mOnPropertyChangeCallback)(std::move(updatedValues));
}
void FakeVehicleHardware::maybeOverrideProperties(const char* overrideDir) {
if (android::base::GetBoolProperty(OVERRIDE_PROPERTY, false)) {
overrideProperties(overrideDir);
}
}
void FakeVehicleHardware::overrideProperties(const char* overrideDir) {
ALOGI("loading vendor override properties from %s", overrideDir);
if (auto dir = opendir(overrideDir); dir != NULL) {
void FakeVehicleHardware::loadPropConfigsFromDir(
const std::string& dirPath,
std::unordered_map<int32_t, ConfigDeclaration>* configsByPropId) {
ALOGI("loading properties from %s", dirPath.c_str());
if (auto dir = opendir(dirPath.c_str()); dir != NULL) {
std::regex regJson(".*[.]json", std::regex::icase);
while (auto f = readdir(dir)) {
if (!std::regex_match(f->d_name, regJson)) {
continue;
}
std::string file = overrideDir + std::string(f->d_name);
JsonFakeValueGenerator tmpGenerator(file);
std::vector<VehiclePropValue> propValues = tmpGenerator.getAllEvents();
for (const VehiclePropValue& prop : propValues) {
auto propToStore = mValuePool->obtain(prop);
propToStore->timestamp = elapsedRealtimeNano();
if (auto result = mServerSidePropStore->writeValue(std::move(propToStore),
/*updateStatus=*/true);
!result.ok()) {
ALOGW("failed to write vendor override properties: %d, error: %s, code: %d",
prop.prop, getErrorMsg(result).c_str(), getIntErrorCode(result));
}
std::string filePath = dirPath + "/" + std::string(f->d_name);
ALOGI("loading properties from %s", filePath.c_str());
auto result = mLoader.loadPropConfig(filePath);
if (!result.ok()) {
ALOGE("failed to load config file: %s, error: %s", filePath.c_str(),
result.error().message().c_str());
continue;
}
for (auto& [propId, configDeclaration] : result.value()) {
(*configsByPropId)[propId] = std::move(configDeclaration);
}
}
closedir(dir);

View File

@@ -22,13 +22,13 @@ cc_test {
name: "FakeVehicleHardwareTest",
vendor: true,
srcs: ["*.cpp"],
cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"],
cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
header_libs: [
"IVehicleHardware",
"VehicleHalDefaultConfig",
"VehicleHalTestUtilHeaders",
],
static_libs: [
"VehicleHalJsonConfigLoaderEnableTestProperties",
"VehicleHalUtils",
"FakeVehicleHardware",
"FakeVehicleHalValueGenerators",
@@ -41,6 +41,9 @@ cc_test {
"libjsoncpp",
],
data: [
":VehicleHalDefaultProperties_JSON",
":VehicleHalTestProperties_JSON",
":VehicleHalVendorClusterTestProperties_JSON",
":FakeVehicleHardwareTestOverrideJson",
":FakeVehicleHardwareTestPropJson",
],
@@ -55,5 +58,5 @@ filegroup {
filegroup {
name: "FakeVehicleHardwareTestPropJson",
srcs: ["prop.json"],
srcs: ["fakedata/prop.json"],
}

View File

@@ -16,7 +16,6 @@
#include <FakeVehicleHardware.h>
#include <DefaultConfig.h>
#include <FakeObd2Frame.h>
#include <FakeUserHal.h>
#include <PropertyUtils.h>
@@ -80,7 +79,9 @@ class FakeVehicleHardwareTestHelper {
public:
FakeVehicleHardwareTestHelper(FakeVehicleHardware* hardware) { mHardware = hardware; }
void overrideProperties(const char* overrideDir) { mHardware->overrideProperties(overrideDir); }
std::unordered_map<int32_t, ConfigDeclaration> loadConfigDeclarations() {
return mHardware->loadConfigDeclarations();
}
private:
FakeVehicleHardware* mHardware;
@@ -89,7 +90,9 @@ class FakeVehicleHardwareTestHelper {
class FakeVehicleHardwareTest : public ::testing::Test {
protected:
void SetUp() override {
mHardware = std::make_unique<FakeVehicleHardware>();
mHardware = std::make_unique<FakeVehicleHardware>(android::base::GetExecutableDirectory(),
/*overrideConfigDir=*/"",
/*forceOverride=*/false);
auto callback = std::make_unique<IVehicleHardware::PropertyChangeCallback>(
[this](const std::vector<VehiclePropValue>& values) {
onPropertyChangeEvent(values);
@@ -109,6 +112,10 @@ class FakeVehicleHardwareTest : public ::testing::Test {
FakeVehicleHardware* getHardware() { return mHardware.get(); }
void setHardware(std::unique_ptr<FakeVehicleHardware> hardware) {
mHardware = std::move(hardware);
}
StatusCode setValues(const std::vector<SetValueRequest>& requests) {
{
std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -374,7 +381,8 @@ class FakeVehicleHardwareTest : public ::testing::Test {
TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs) {
std::vector<VehiclePropConfig> configs = getHardware()->getAllPropertyConfigs();
ASSERT_EQ(configs.size(), defaultconfig::getDefaultConfigs().size());
FakeVehicleHardwareTestHelper helper(getHardware());
ASSERT_EQ(configs.size(), helper.loadConfigDeclarations().size());
}
TEST_F(FakeVehicleHardwareTest, testGetDefaultValues) {
@@ -382,7 +390,8 @@ TEST_F(FakeVehicleHardwareTest, testGetDefaultValues) {
std::vector<GetValueResult> expectedGetValueResults;
int64_t requestId = 1;
for (auto& config : defaultconfig::getDefaultConfigs()) {
FakeVehicleHardwareTestHelper helper(getHardware());
for (auto& [propId, config] : helper.loadConfigDeclarations()) {
if (obd2frame::FakeObd2Frame::isDiagnosticProperty(config.config)) {
// Ignore storing default value for diagnostic property. They have special get/set
// logic.
@@ -394,12 +403,11 @@ TEST_F(FakeVehicleHardwareTest, testGetDefaultValues) {
continue;
}
if (config.config.prop == ECHO_REVERSE_BYTES) {
if (propId == ECHO_REVERSE_BYTES) {
// Ignore ECHO_REVERSE_BYTES, it has special logic.
continue;
}
int propId = config.config.prop;
if (isGlobalProp(propId)) {
if (config.initialValue == RawPropValues{}) {
addGetValueRequest(getValueRequests, expectedGetValueResults, requestId++,
@@ -657,10 +665,12 @@ TEST_F(FakeVehicleHardwareTest, testSetStatusMustIgnore) {
}
TEST_F(FakeVehicleHardwareTest, testVendorOverrideProperties) {
std::string overrideDir = android::base::GetExecutableDirectory() + "/override/";
std::string currentDir = android::base::GetExecutableDirectory();
std::string overrideDir = currentDir + "/override/";
// Set vendor override directory.
FakeVehicleHardwareTestHelper helper(getHardware());
helper.overrideProperties(overrideDir.c_str());
std::unique_ptr<FakeVehicleHardware> hardware =
std::make_unique<FakeVehicleHardware>(currentDir, overrideDir, /*forceOverride=*/true);
setHardware(std::move(hardware));
// This is the same as the prop in 'gear_selection.json'.
int gearProp = toInt(VehicleProperty::GEAR_SELECTION);
@@ -695,10 +705,12 @@ TEST_F(FakeVehicleHardwareTest, testVendorOverrideProperties) {
}
TEST_F(FakeVehicleHardwareTest, testVendorOverridePropertiesMultipleAreas) {
std::string overrideDir = android::base::GetExecutableDirectory() + "/override/";
std::string currentDir = android::base::GetExecutableDirectory();
std::string overrideDir = currentDir + "/override/";
// Set vendor override directory.
FakeVehicleHardwareTestHelper helper(getHardware());
helper.overrideProperties(overrideDir.c_str());
std::unique_ptr<FakeVehicleHardware> hardware =
std::make_unique<FakeVehicleHardware>(currentDir, overrideDir, /*forceOverride=*/true);
setHardware(std::move(hardware));
// This is the same as the prop in 'hvac_temperature_set.json'.
int hvacProp = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);
@@ -711,22 +723,16 @@ TEST_F(FakeVehicleHardwareTest, testVendorOverridePropertiesMultipleAreas) {
ASSERT_TRUE(result.ok()) << "expect to get the overridden property ok: " << getStatus(result);
ASSERT_EQ(static_cast<size_t>(1), result.value().value.floatValues.size());
ASSERT_EQ(30.0f, result.value().value.floatValues[0]);
// HVAC_RIGHT should not be affected and return the default value.
result = getValue(VehiclePropValue{
.prop = hvacProp,
.areaId = HVAC_RIGHT,
});
ASSERT_TRUE(result.ok()) << "expect to get the default property ok: " << getStatus(result);
ASSERT_EQ(static_cast<size_t>(1), result.value().value.floatValues.size());
ASSERT_EQ(20.0f, result.value().value.floatValues[0]);
}
TEST_F(FakeVehicleHardwareTest, testVendorOverridePropertiesDirDoesNotExist) {
// Set vendor override directory to a non-existing dir
FakeVehicleHardwareTestHelper helper(getHardware());
helper.overrideProperties("123");
std::string currentDir = android::base::GetExecutableDirectory();
std::string overrideDir = currentDir + "/override/";
// Set vendor override directory to a non-existing dir.
std::unique_ptr<FakeVehicleHardware> hardware =
std::make_unique<FakeVehicleHardware>(currentDir, "1234", /*forceOverride=*/true);
setHardware(std::move(hardware));
auto result = getValue(VehiclePropValue{
.prop = toInt(VehicleProperty::GEAR_SELECTION),
});
@@ -1840,7 +1846,7 @@ TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataLinear) {
std::string getTestFilePath(const char* filename) {
static std::string baseDir = android::base::GetExecutableDirectory();
return baseDir + "/" + filename;
return baseDir + "/fakedata/" + filename;
}
TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataJson) {

View File

@@ -1,9 +1,13 @@
[
{
"timestamp": 1000000,
"areaId": 0,
"value": 8,
// GEAR_SELECTION
"prop": 289408000
}
]
{
"apiVersion": 1,
"properties": [
{
"property": "VehicleProperty::GEAR_SELECTION",
"defaultValue": {
"int32Values": [
8
]
}
}
]
}

View File

@@ -1,10 +1,20 @@
[
{
"timestamp": 1000000,
// HVAC_LEFT
"areaId": 49,
"value": 30,
// HVAC_TEMPERATURE_SET
"prop": 358614275
}
]
{
"apiVersion": 1,
"properties": [
{
"property": "VehicleProperty::HVAC_TEMPERATURE_SET",
"areas": [
{
"defaultValue": {
"floatValues": [
30.0
]
},
"areaId": 49,
"minFloatValue": 16.0,
"maxFloatValue": 32.0
}
]
}
]
}

View File

@@ -47,13 +47,20 @@ cc_test {
],
vendor: true,
defaults: ["VehicleHalDefaults"],
shared_libs: ["libprotobuf-cpp-full"],
shared_libs: [
"libprotobuf-cpp-full",
"libjsoncpp",
],
static_libs: [
"VehicleHalJsonConfigLoaderEnableTestProperties",
"VehicleHalProtoMessageConverter",
"VehicleHalProtos",
"VehicleHalUtils",
"libgtest",
],
data: [
":VehicleHalDefaultProperties_JSON",
],
header_libs: ["VehicleHalDefaultConfig"],
test_suites: ["device-tests"],
}

View File

@@ -16,9 +16,11 @@
#include <vector>
#include <DefaultConfig.h>
#include <JsonConfigLoader.h>
#include <ProtoMessageConverter.h>
#include <VehicleHalTypes.h>
#include <android-base/file.h>
#include <android-base/format.h>
#include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
@@ -35,23 +37,39 @@ namespace {
namespace proto = ::android::hardware::automotive::vehicle::proto;
namespace aidl_vehicle = ::aidl::android::hardware::automotive::vehicle;
constexpr char DEFAULT_PROPERTIES_CONFIG[] = "DefaultProperties.json";
inline std::string getConfigPath(const std::string& name) {
return android::base::GetExecutableDirectory() + "/" + name;
}
std::vector<aidl_vehicle::VehiclePropConfig> prepareTestConfigs() {
JsonConfigLoader loader;
auto result = loader.loadPropConfig(getConfigPath(DEFAULT_PROPERTIES_CONFIG));
if (!result.ok()) {
return {};
}
std::vector<aidl_vehicle::VehiclePropConfig> configs;
for (auto& property : defaultconfig::getDefaultConfigs()) {
configs.push_back(property.config);
for (auto& [_, configDeclaration] : result.value()) {
configs.push_back(configDeclaration.config);
}
return configs;
}
std::vector<aidl_vehicle::VehiclePropValue> prepareTestValues() {
JsonConfigLoader loader;
auto result = loader.loadPropConfig(getConfigPath(DEFAULT_PROPERTIES_CONFIG));
if (!result.ok()) {
return {};
}
std::vector<aidl_vehicle::VehiclePropValue> values;
int64_t timestamp = 1;
for (auto& property : defaultconfig::getDefaultConfigs()) {
for (auto& [_, configDeclaration] : result.value()) {
values.push_back({
.timestamp = timestamp,
.areaId = 123,
.prop = property.config.prop,
.value = property.initialValue,
.prop = configDeclaration.config.prop,
.value = configDeclaration.initialValue,
.status = aidl_vehicle::VehiclePropertyStatus::ERROR,
});
}

View File

@@ -75,10 +75,6 @@ cc_fuzz {
"VehicleHalDefaults",
"android-automotive-large-parcelable-defaults",
],
header_libs: [
"IVehicleHardware",
"VehicleHalDefaultConfig",
],
static_libs: [
"DefaultVehicleHal",
"FakeVehicleHardware",