Support debug setValue.

Test: atest android.hardware.automotive.vehicle@2.0-default-impl-unit-tests
Bug: 193565753
Change-Id: I603f9fb986b2b131d05a23fb1cc1517f99c5bf0a
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
index 0aaa4c1..2facc4b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
@@ -370,10 +370,11 @@
         return result;
     }
 
-    return debug(options);
+    return debugCommand(options);
 }
 
-IVehicleServer::DumpResult DefaultVehicleHalServer::debug(const std::vector<std::string>& options) {
+IVehicleServer::DumpResult DefaultVehicleHalServer::debugCommand(
+        const std::vector<std::string>& options) {
     DumpResult result;
     // This is a debug command for the HAL, caller should not continue to dump state.
     result.callerShouldDumpState = false;
@@ -389,7 +390,9 @@
         result.buffer += getHelpInfo();
         return result;
     } else if (command == "--genfakedata") {
-        return genFakeData(options);
+        return genFakeDataCommand(options);
+    } else if (command == "--setint" || command == "--setfloat" || command == "--setbool") {
+        return setValueCommand(options);
     }
 
     result.buffer += "Unknown command: \"" + command + "\"\n";
@@ -411,10 +414,19 @@
            "\tStop a json generator: \n"
            "\t--debughal --genfakedata --stopjson [jsonFilePath(string)]\n"
            "\tGenerate key press: \n"
-           "\t--debughal --genfakedata --keypress [keyCode(int32)] [display[int32]]\n";
+           "\t--debughal --genfakedata --keypress [keyCode(int32)] [display[int32]]\n"
+           "\tSet a int property value: \n"
+           "\t--setint [propID(int32)] [value(int32)] [timestamp(int64)] "
+           "[areaID(int32)(optional)]\n"
+           "\tSet a boolean property value: \n"
+           "\t--setbool [propID(int32)] [value(\"true\"/\"false\")] [timestamp(int64)] "
+           "[areaID(int32)(optional)]\n"
+           "\tSet a float property value: \n"
+           "\t--setfloat [propID(int32)] [value(float)] [timestamp(int64)] "
+           "[areaID(int32)(optional)]\n";
 }
 
-IVehicleServer::DumpResult DefaultVehicleHalServer::genFakeData(
+IVehicleServer::DumpResult DefaultVehicleHalServer::genFakeDataCommand(
         const std::vector<std::string>& options) {
     DumpResult result;
     // This is a debug command for the HAL, caller should not continue to dump state.
@@ -597,6 +609,80 @@
     }
 }
 
+IVehicleServer::DumpResult DefaultVehicleHalServer::setValueCommand(
+        const std::vector<std::string>& options) {
+    DumpResult result;
+    // This is a debug command for the HAL, caller should not continue to dump state.
+    result.callerShouldDumpState = false;
+    // --debughal --set* [propID(int32)] [value] [timestamp(int64)]
+    // [areaId(int32)(optional)]
+    if (options.size() != 5 && options.size() != 6) {
+        result.buffer +=
+                "incorrect argument count, need 5 or 6 arguments for --setint or --setfloat or "
+                "--setbool\n";
+        result.buffer += getHelpInfo();
+        return result;
+    }
+    std::unique_ptr<VehiclePropValue> updatedPropValue;
+    int32_t propId;
+    int32_t intValue;
+    float floatValue;
+    int64_t timestamp;
+    int32_t areaId = 0;
+    if (options[1] == "--setint") {
+        updatedPropValue = std::move(createVehiclePropValue(VehiclePropertyType::INT32, 1));
+        if (!android::base::ParseInt(options[3], &intValue)) {
+            result.buffer += "failed to parse value as int: \"" + options[3] + "\"\n";
+            result.buffer += getHelpInfo();
+            return result;
+        }
+        updatedPropValue->value.int32Values[0] = intValue;
+    } else if (options[1] == "--setbool") {
+        updatedPropValue = std::move(createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1));
+        if (options[3] == "true" || options[3] == "True") {
+            updatedPropValue->value.int32Values[0] = 1;
+        } else if (options[3] == "false" || options[3] == "False") {
+            updatedPropValue->value.int32Values[0] = 0;
+        } else {
+            result.buffer += "failed to parse value as bool, only accepts true/false: \"" +
+                             options[3] + "\"\n";
+            result.buffer += getHelpInfo();
+            return result;
+        }
+    } else {
+        updatedPropValue = std::move(createVehiclePropValue(VehiclePropertyType::FLOAT, 1));
+        if (!android::base::ParseFloat(options[3], &floatValue)) {
+            result.buffer += "failed to parse value as float: \"" + options[3] + "\"\n";
+            result.buffer += getHelpInfo();
+            return result;
+        }
+        updatedPropValue->value.floatValues[0] = floatValue;
+    }
+    if (!android::base::ParseInt(options[2], &propId)) {
+        result.buffer += "failed to parse propID as int: \"" + options[2] + "\"\n";
+        result.buffer += getHelpInfo();
+        return result;
+    }
+    updatedPropValue->prop = propId;
+    if (!android::base::ParseInt(options[4], &timestamp)) {
+        result.buffer += "failed to parse timestamp as int: \"" + options[4] + "\"\n";
+        result.buffer += getHelpInfo();
+        return result;
+    }
+    updatedPropValue->timestamp = timestamp;
+    if (options.size() == 6) {
+        if (!android::base::ParseInt(options[5], &areaId)) {
+            result.buffer += "failed to parse areaID as int: \"" + options[5] + "\"\n";
+            result.buffer += getHelpInfo();
+            return result;
+        }
+    }
+    updatedPropValue->areaId = areaId;
+
+    onPropertyValueFromCar(*updatedPropValue, /*updateStatus=*/true);
+    return result;
+}
+
 }  // namespace impl
 
 }  // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.h
index 5858325..8754846 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.h
@@ -45,6 +45,9 @@
 
     StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
 
+    // Dump/debug the Default VHAL server. If options is empty, the internal information for the
+    // server would be dumped. Otherwise, the options would be treated as debug commands and sent
+    // to debug function to handle the commands.
     DumpResult onDump(const std::vector<std::string>& options) override;
 
     // Set the Property Value Pool used in this server
@@ -67,16 +70,25 @@
 
     void storePropInitialValue(const ConfigDeclaration& config);
 
-    DumpResult debug(const std::vector<std::string>& options);
+    // Handles debug commands. The first option must be "--debughal" otherwise the command would be
+    // ignored. The second option specifies the operations to execute. Different operations require
+    // different input options, for detail, see the helpInfo printed by getHelpInfo().
+    DumpResult debugCommand(const std::vector<std::string>& options);
 
+    // Gets help info. Contains the usage for different debug commands.
     std::string getHelpInfo();
 
-    DumpResult genFakeData(const std::vector<std::string>& options);
     // If "persist.vendor.vhal_init_value_override" is true, try to override the properties default
     // values according to JSON files in 'overrideDir'. Would be called in constructor using
     // VENDOR_OVERRIDE_DIR as overrideDir.
     void maybeOverrideProperties(const char* overrideDir);
 
+    // Handles "--genfakedata" debug command.
+    DumpResult genFakeDataCommand(const std::vector<std::string>& options);
+
+    // Handles "--setint" or "--setfloat" or "--setbool" debug command.
+    DumpResult setValueCommand(const std::vector<std::string>& options);
+
   protected:
     GeneratorHub mGeneratorHub{
             [this](const VehiclePropValue& value) { return onFakeValueGenerated(value); }};
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
index 2268df8..e3c8dd6 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
@@ -71,6 +71,8 @@
 using ::android::hardware::automotive::vehicle::V2_0::impl::DefaultVehicleConnector;
 using ::android::hardware::automotive::vehicle::V2_0::impl::DefaultVehicleHal;
 using ::android::hardware::automotive::vehicle::V2_0::impl::DefaultVhalImplTestHelper;
+using ::android::hardware::automotive::vehicle::V2_0::impl::DOOR_1_LEFT;
+using ::android::hardware::automotive::vehicle::V2_0::impl::DOOR_1_RIGHT;
 using ::android::hardware::automotive::vehicle::V2_0::impl::HVAC_ALL;
 using ::android::hardware::automotive::vehicle::V2_0::impl::HVAC_LEFT;
 using ::android::hardware::automotive::vehicle::V2_0::impl::HVAC_RIGHT;
@@ -661,7 +663,28 @@
              "failed to parse keyCode as int: \"0.1\""},
             {"genfakedata_keypress_invalid_display",
              {"--debughal", "--genfakedata", "--keypress", "1", "0.1"},
-             "failed to parse display as int: \"0.1\""}};
+             "failed to parse display as int: \"0.1\""},
+            {"setint_no_args", {"--debughal", "--setint"}, "incorrect argument count"},
+            {"setint_invalid_prop_id",
+             {"--debughal", "--setint", "abcd", "0", "0", "0"},
+             "failed to parse propID as int: \"abcd\""},
+            {"setint_invalid_value",
+             {"--debughal", "--setint", "0", "1.1", "0", "0"},
+             "failed to parse value as int: \"1.1\""},
+            {"setint_invalid_timestamp",
+             {"--debughal", "--setint", "0", "0", "1.1", "0"},
+             "failed to parse timestamp as int: \"1.1\""},
+            {"setint_invalid_areaId",
+             {"--debughal", "--setint", "0", "0", "0", "1.1"},
+             "failed to parse areaID as int: \"1.1\""},
+            {"setbool_no_args", {"--debughal", "--setbool"}, "incorrect argument count"},
+            {"setbool_invalid_value",
+             {"--debughal", "--setbool", "0", "1", "0", "0"},
+             "failed to parse value as bool"},
+            {"setfloat_no_args", {"--debughal", "--setfloat"}, "incorrect argument count"},
+            {"setfloat_invalid_value",
+             {"--debughal", "--setfloat", "0", "abcd", "0", "0"},
+             "failed to parse value as float: \"abcd\""}};
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -1263,4 +1286,109 @@
     EXPECT_EQ(0, events[0]->value.int32Values[3]);
 }
 
+TEST_F(DefaultVhalImplTest, testDebugSetInt) {
+    hidl_vec<hidl_string> options = {"--debughal", "--setint",
+                                     getPropIdString(VehicleProperty::INFO_MODEL_YEAR), "2022",
+                                     "1000"};
+    hidl_handle fd = {};
+    int memfd = createMemfd(&fd);
+    // Clear existing events.
+    mEventQueue.flush();
+
+    EXPECT_FALSE(mHal->dump(fd, options));
+
+    lseek(memfd, 0, SEEK_SET);
+    char buf[10240] = {};
+    // The dumped info should be empty.
+    read(memfd, buf, sizeof(buf));
+    EXPECT_STREQ("", buf);
+
+    auto events = mEventQueue.flush();
+    ASSERT_EQ((size_t)1, events.size());
+    ASSERT_EQ((size_t)1, events[0]->value.int32Values.size());
+    EXPECT_EQ(2022, events[0]->value.int32Values[0]);
+    EXPECT_EQ(1000, events[0]->timestamp);
+
+    VehiclePropValue value;
+    StatusCode status;
+    value.prop = toInt(VehicleProperty::INFO_MODEL_YEAR);
+    auto gotValue = mHal->get(value, &status);
+    ASSERT_EQ(StatusCode::OK, status);
+    ASSERT_EQ((size_t)1, gotValue->value.int32Values.size());
+    EXPECT_EQ(2022, gotValue->value.int32Values[0]);
+}
+
+TEST_F(DefaultVhalImplTest, testDebugSetBool) {
+    char doorLeft[100];
+    snprintf(doorLeft, sizeof(doorLeft), "%d", DOOR_1_LEFT);
+    hidl_vec<hidl_string> options = {
+            "--debughal", "--setbool", getPropIdString(VehicleProperty::DOOR_LOCK),
+            "false",      "1000",      doorLeft};
+    hidl_handle fd = {};
+    int memfd = createMemfd(&fd);
+    // Clear existing events.
+    mEventQueue.flush();
+
+    EXPECT_FALSE(mHal->dump(fd, options));
+
+    lseek(memfd, 0, SEEK_SET);
+    char buf[10240] = {};
+    // The dumped info should be empty.
+    read(memfd, buf, sizeof(buf));
+    EXPECT_STREQ("", buf);
+
+    auto events = mEventQueue.flush();
+    ASSERT_EQ((size_t)1, events.size());
+    EXPECT_EQ(0, events[0]->value.int32Values[0]);
+    EXPECT_EQ(DOOR_1_LEFT, events[0]->areaId);
+    EXPECT_EQ(1000, events[0]->timestamp);
+
+    VehiclePropValue value;
+    StatusCode status;
+    value.prop = toInt(VehicleProperty::DOOR_LOCK);
+    value.areaId = DOOR_1_LEFT;
+    auto gotValue = mHal->get(value, &status);
+    ASSERT_EQ(StatusCode::OK, status);
+    ASSERT_EQ((size_t)1, gotValue->value.int32Values.size());
+    EXPECT_EQ(0, gotValue->value.int32Values[0]);
+
+    value.areaId = DOOR_1_RIGHT;
+    gotValue = mHal->get(value, &status);
+    ASSERT_EQ(StatusCode::OK, status);
+    ASSERT_EQ((size_t)1, gotValue->value.int32Values.size());
+    EXPECT_EQ(1, gotValue->value.int32Values[0]);
+}
+
+TEST_F(DefaultVhalImplTest, testDebugSetFloat) {
+    hidl_vec<hidl_string> options = {"--debughal", "--setfloat",
+                                     getPropIdString(VehicleProperty::INFO_FUEL_CAPACITY), "10.5",
+                                     "1000"};
+    hidl_handle fd = {};
+    int memfd = createMemfd(&fd);
+    // Clear existing events.
+    mEventQueue.flush();
+
+    EXPECT_FALSE(mHal->dump(fd, options));
+
+    lseek(memfd, 0, SEEK_SET);
+    char buf[10240] = {};
+    // The dumped info should be empty.
+    read(memfd, buf, sizeof(buf));
+    EXPECT_STREQ("", buf);
+
+    auto events = mEventQueue.flush();
+    ASSERT_EQ((size_t)1, events.size());
+    ASSERT_EQ((size_t)1, events[0]->value.floatValues.size());
+    EXPECT_EQ(10.5, events[0]->value.floatValues[0]);
+    EXPECT_EQ(1000, events[0]->timestamp);
+
+    VehiclePropValue value;
+    StatusCode status;
+    value.prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY);
+    auto gotValue = mHal->get(value, &status);
+    ASSERT_EQ(StatusCode::OK, status);
+    ASSERT_EQ((size_t)1, gotValue->value.floatValues.size());
+    EXPECT_EQ(10.5, gotValue->value.floatValues[0]);
+}
+
 }  // namespace