Convert VehicleHalDefaultConfig to JsonConfigLoader.

Test: Presubmit
Bug: 238685398
Change-Id: I4a10b3b4484f593a6311b85f2143ef0ef12f5f81
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h
index fd73a26..f3bdbd2 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h
@@ -89,7 +89,8 @@
 // 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 @@
   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;
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index 392d540..e6b7d14 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -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 @@
     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 @@
     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
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
index cff70d9..9ff8c1b 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
@@ -38,7 +38,7 @@
     JsonConfigLoader mLoader;
 };
 
-TEST_F(JsonConfigLoaderUnitTest, TestBasic) {
+TEST_F(JsonConfigLoaderUnitTest, testBasic) {
     std::istringstream iss(R"(
     {
         "properties": [{
@@ -53,11 +53,39 @@
 
     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 @@
 
     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 @@
             << "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 @@
             << "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 @@
     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 @@
 
     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 @@
 
     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 @@
     ASSERT_TRUE(result.ok()) << result.error().message();
 }
 
-TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitUsGallon) {
+TEST_F(JsonConfigLoaderUnitTest, testConfigArrayUnitUsGallon) {
     std::istringstream iss(R"(
     {
         "properties": [{
@@ -181,7 +209,7 @@
     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 @@
             << "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 @@
             << "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 @@
 
     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 @@
             << "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 @@
     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 @@
     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 @@
     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 @@
     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 @@
             << "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 @@
             << "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 @@
 
     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 @@
             << "Wrong type for MinSampleRate must cause error";
 }
 
-TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate) {
+TEST_F(JsonConfigLoaderUnitTest, testMaxSampleRate) {
     std::istringstream iss(R"(
     {
         "properties": [{
@@ -403,10 +431,10 @@
 
     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 @@
             << "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 @@
 
     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 @@
     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 @@
     ASSERT_EQ(initialValue.stringValue, "abcd");
 }
 
-TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailNotObject) {
+TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_FailNotObject) {
     std::istringstream iss(R"(
     {
         "properties": [{
@@ -486,7 +514,7 @@
             << "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 @@
     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 @@
     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) {
diff --git a/automotive/vehicle/aidl/impl/default_config/config/Android.bp b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
index c5f86c2..8f1c7d1 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
@@ -21,3 +21,27 @@
     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,
+}
diff --git a/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp b/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp
index b16ea14..f0ab806 100644
--- a/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp
@@ -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 @@
     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 @@
                                    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());
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
index dcd9208..4c17cde 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -24,6 +24,7 @@
     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_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",
     ],
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 9091fee..1636cb6 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -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 @@
 
     FakeVehicleHardware();
 
-    explicit FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool);
+    FakeVehicleHardware(std::string defaultConfigDir, std::string overrideConfigDir,
+                        bool forceOverride);
 
     ~FakeVehicleHardware();
 
@@ -151,17 +153,23 @@
                                   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 @@
             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,
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 c6ec85d..d87e5aa 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -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::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 @@
 }
 
 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 @@
       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 @@
     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 @@
             // 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 @@
             *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 @@
                        << getErrorMsg(writeResult);
             }
             return {};
-#endif  // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+#endif  // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
 
         default:
             break;
@@ -1264,33 +1289,26 @@
     (*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);
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index cfd6577..8d8fcf5 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -22,13 +22,13 @@
     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 @@
         "libjsoncpp",
     ],
     data: [
+        ":VehicleHalDefaultProperties_JSON",
+        ":VehicleHalTestProperties_JSON",
+        ":VehicleHalVendorClusterTestProperties_JSON",
         ":FakeVehicleHardwareTestOverrideJson",
         ":FakeVehicleHardwareTestPropJson",
     ],
@@ -55,5 +58,5 @@
 
 filegroup {
     name: "FakeVehicleHardwareTestPropJson",
-    srcs: ["prop.json"],
+    srcs: ["fakedata/prop.json"],
 }
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 ab6bf51..c230c51 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -16,7 +16,6 @@
 
 #include <FakeVehicleHardware.h>
 
-#include <DefaultConfig.h>
 #include <FakeObd2Frame.h>
 #include <FakeUserHal.h>
 #include <PropertyUtils.h>
@@ -80,7 +79,9 @@
   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 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 @@
 
     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 @@
 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 @@
     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 @@
             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, 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, 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 @@
     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 @@
 
 std::string getTestFilePath(const char* filename) {
     static std::string baseDir = android::base::GetExecutableDirectory();
-    return baseDir + "/" + filename;
+    return baseDir + "/fakedata/" + filename;
 }
 
 TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataJson) {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/prop.json b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/fakedata/prop.json
similarity index 100%
rename from automotive/vehicle/aidl/impl/fake_impl/hardware/test/prop.json
rename to automotive/vehicle/aidl/impl/fake_impl/hardware/test/fakedata/prop.json
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/gear_selection.json b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/gear_selection.json
index 59666b8..693f1e2 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/gear_selection.json
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/gear_selection.json
@@ -1,9 +1,13 @@
-[
-  {
-    "timestamp": 1000000,
-    "areaId": 0,
-    "value": 8,
-    // GEAR_SELECTION
-    "prop": 289408000
-  }
-]
+{
+    "apiVersion": 1,
+    "properties": [
+        {
+            "property": "VehicleProperty::GEAR_SELECTION",
+            "defaultValue": {
+                "int32Values": [
+                    8
+                ]
+            }
+        }
+    ]
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/hvac_temperature_set.json b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/hvac_temperature_set.json
index 93a97ed..07cfebb 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/hvac_temperature_set.json
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/override/hvac_temperature_set.json
@@ -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
+                }
+            ]
+        }
+    ]
+}
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
index 7670c25..c368334 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
@@ -47,13 +47,20 @@
     ],
     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"],
 }
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
index c742db5..308be46 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
@@ -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 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,
         });
     }
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index 8b4f559..6fec2c9 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -75,10 +75,6 @@
         "VehicleHalDefaults",
         "android-automotive-large-parcelable-defaults",
     ],
-    header_libs: [
-        "IVehicleHardware",
-        "VehicleHalDefaultConfig",
-    ],
     static_libs: [
         "DefaultVehicleHal",
         "FakeVehicleHardware",