Add set supported value debug command.

Add debug command to ref VHAL to allow setting min/max value and
supported values list for the test vendor property. The command
also triggers supported value change event so that we can test
the subscription logic.

Flag: EXEMPT HAL change
Test: atest FakeVehicleHardwareTest
Manual test using KS, verify we see the supported value change event.
Bug: 382563296

Change-Id: I7ec791b1ee8e6cade4e267b55e4b58e1d3a9e49c
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h
index b7ada62..e20befc 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -100,6 +100,9 @@
     void registerOnPropertySetErrorEvent(
             std::unique_ptr<const PropertySetErrorCallback> callback) override;
 
+    void registerSupportedValueChangeCallback(
+            std::unique_ptr<const SupportedValueChangeCallback> callback) override;
+
     // Subscribe to a new [propId, areaId] or change the update rate.
     aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
             aidl::android::hardware::automotive::vehicle::SubscribeOptions options) override;
@@ -177,6 +180,7 @@
     // Only allowed to set once.
     std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback;
     std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback;
+    std::unique_ptr<const SupportedValueChangeCallback> mOnSupportedValueChangeCallback;
 
     std::mutex mLock;
     std::unordered_map<PropIdAreaId, RefreshInfo, PropIdAreaIdHash> mRefreshInfoByPropIdAreaId
@@ -185,6 +189,10 @@
     std::unordered_map<PropIdAreaId, VehiclePropValuePool::RecyclableType, PropIdAreaIdHash>
             mSavedProps GUARDED_BY(mLock);
     std::unordered_set<PropIdAreaId, PropIdAreaIdHash> mSubOnChangePropIdAreaIds GUARDED_BY(mLock);
+    int32_t mMinSupportedValueForTestIntProp GUARDED_BY(mLock) = 0;
+    int32_t mMaxSupportedValueForTestIntProp GUARDED_BY(mLock) = 10;
+    std::vector<int32_t> mSupportedValuesListForTestIntProp GUARDED_BY(mLock) = {0, 2, 4, 6, 8, 10};
+
     // PendingRequestHandler is thread-safe.
     mutable PendingRequestHandler<GetValuesCallback,
                                   aidl::android::hardware::automotive::vehicle::GetValueRequest>
@@ -281,6 +289,8 @@
     std::string dumpRestoreProperty(const std::vector<std::string>& options);
     std::string dumpInjectEvent(const std::vector<std::string>& options);
     std::string dumpSubscriptions();
+    std::string dumpSetSupportedValues(const std::vector<std::string>& options);
+    std::string dumpSetMinMaxValue(const std::vector<std::string>& options);
 
     std::vector<std::string> getOptionValues(const std::vector<std::string>& options,
                                              size_t* index);
@@ -310,6 +320,9 @@
                                float sampleRateHz) REQUIRES(mLock);
     void unregisterRefreshLocked(PropIdAreaId propIdAreaId) REQUIRES(mLock);
     void refreshTimestampForInterval(int64_t intervalInNanos) EXCLUDES(mLock);
+    void triggerSupportedValueChange(
+            const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config)
+            EXCLUDES(mLock);
 
     static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwInputKeyProp(
             aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction action,
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
index f1aaefc..01e40fb 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -73,6 +73,7 @@
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
@@ -1372,6 +1373,10 @@
         result.buffer = "successfully restored vendor configs";
     } else if (EqualsIgnoreCase(option, "--dumpSub")) {
         result.buffer = dumpSubscriptions();
+    } else if (EqualsIgnoreCase(option, "--set-minmaxvalue")) {
+        result.buffer = dumpSetMinMaxValue(options);
+    } else if (EqualsIgnoreCase(option, "--set-supportedvalues")) {
+        result.buffer = dumpSetSupportedValues(options);
     } else {
         result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
     }
@@ -1794,6 +1799,88 @@
     return result;
 }
 
+std::string FakeVehicleHardware::dumpSetMinMaxValue(const std::vector<std::string>& options) {
+    if (auto result = checkArgumentsSize(options, /*minSize=*/3); !result.ok()) {
+        return getErrorMsg(result);
+    }
+    int testPropId = toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY);
+    auto configResult = mServerSidePropStore->getPropConfig(testPropId);
+    if (!configResult.ok()) {
+        return "Failed to set min/max supported value: VENDOR_EXTENSION_INT_PROPERTY not supported";
+    }
+    int32_t values[2];
+    for (size_t i = 1; i < 3; i++) {
+        auto int32Result = safelyParseInt<int32_t>(i, options[i]);
+        if (!int32Result.ok()) {
+            return StringPrintf(
+                    "Failed to set min/max supported value: Value: \"%s\" is not a valid int: %s\n",
+                    options[i].c_str(), getErrorMsg(int32Result).c_str());
+        }
+        values[i - 1] = int32Result.value();
+    }
+    int32_t minValue = values[0];
+    int32_t maxValue = values[1];
+    if (minValue > maxValue) {
+        return StringPrintf("Failed to set min/max supported value: MinValue: %" PRId32
+                            " must not > MaxValue: %" PRId32,
+                            minValue, maxValue);
+    }
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        mMinSupportedValueForTestIntProp = minValue;
+        mMaxSupportedValueForTestIntProp = maxValue;
+    }
+    triggerSupportedValueChange(configResult.value());
+    return "Min/Max supported value for VENDOR_EXTENSION_INT_PROPERTY set";
+}
+
+std::string FakeVehicleHardware::dumpSetSupportedValues(const std::vector<std::string>& options) {
+    if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
+        return getErrorMsg(result);
+    }
+    int testPropId = toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY);
+    auto configResult = mServerSidePropStore->getPropConfig(testPropId);
+    if (!configResult.ok()) {
+        return "Failed to set min/max supported value: VENDOR_EXTENSION_INT_PROPERTY not supported";
+    }
+    std::vector<int32_t> values;
+    for (size_t i = 1; i < options.size(); i++) {
+        auto int32Result = safelyParseInt<int32_t>(i, options[i]);
+        if (!int32Result.ok()) {
+            return StringPrintf(
+                    "Failed to set supported values: Value: \"%s\" is not a valid int: %s\n",
+                    options[i].c_str(), getErrorMsg(int32Result).c_str());
+        }
+        values.push_back(int32Result.value());
+    }
+
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        mSupportedValuesListForTestIntProp = values;
+    }
+    triggerSupportedValueChange(configResult.value());
+    return "Supported values list for VENDOR_EXTENSION_INT_PROPERTY set";
+}
+
+// Triggers supported value change for all areaIds that specify hasSupportedValueInfo.
+void FakeVehicleHardware::triggerSupportedValueChange(const VehiclePropConfig& config) {
+    if (mOnSupportedValueChangeCallback == nullptr) {
+        ALOGE("onSupportedValueChangeCallback is not registered, ignore event");
+        return;
+    }
+
+    std::vector<PropIdAreaId> propIdAreaIds;
+    for (const VehicleAreaConfig& areaConfig : config.areaConfigs) {
+        if (areaConfig.hasSupportedValueInfo != std::nullopt) {
+            propIdAreaIds.push_back({
+                    .propId = config.prop,
+                    .areaId = areaConfig.areaId,
+            });
+        }
+    }
+    (*mOnSupportedValueChangeCallback)(std::move(propIdAreaIds));
+}
+
 std::string FakeVehicleHardware::dumpHelp() {
     return "Usage: \n\n"
            "[no args]: dumps (id and value) all supported properties \n"
@@ -1805,6 +1892,10 @@
            "The value arguments constructs a VehiclePropValue used in the getValue request. \n"
            "--set <PROP_ID> [ValueArguments]: sets the value of property PROP_ID, the value "
            "arguments constructs a VehiclePropValue used in the setValue request. \n"
+           "--set-minmaxvalue <MIN_VALUE(int)> <MAX_VALUE(int)>: sets the min max supported value "
+           "for VENDOR_EXTENSION_INT_PROPERTY\n"
+           "--set-supportedvalues <VALUE_1(int)> [VALUE_2(int) ...]: sets the supported values list"
+           "for VENDOR_EXTENSION_INT_PROPERTY\n"
            "--save-prop <PROP_ID> [-a AREA_ID]: saves the current value for PROP_ID, integration "
            "tests that modify prop value must call this before test and restore-prop after test. \n"
            "--restore-prop <PROP_ID> [-a AREA_ID]: restores a previously saved property value. \n"
@@ -2280,6 +2371,15 @@
     mOnPropertySetErrorCallback = std::move(callback);
 }
 
+void FakeVehicleHardware::registerSupportedValueChangeCallback(
+        std::unique_ptr<const SupportedValueChangeCallback> callback) {
+    if (mOnSupportedValueChangeCallback != nullptr) {
+        ALOGE("registerOnPropertyChangeEvent must only be called once");
+        return;
+    }
+    mOnSupportedValueChangeCallback = std::move(callback);
+}
+
 StatusCode FakeVehicleHardware::subscribe(SubscribeOptions options) {
     int32_t propId = options.propId;
 
@@ -2303,6 +2403,7 @@
 
 std::vector<MinMaxSupportedValueResult> FakeVehicleHardware::getMinMaxSupportedValues(
         const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
     std::vector<MinMaxSupportedValueResult> results;
     // We only support VENDOR_EXTENSION_INT_PROPERTY
     for (const auto& propIdAreaId : propIdAreaIds) {
@@ -2318,11 +2419,11 @@
                 .status = StatusCode::OK,
                 .minSupportedValue =
                         RawPropValues{
-                                .int32Values = {0},
+                                .int32Values = {mMinSupportedValueForTestIntProp},
                         },
                 .maxSupportedValue =
                         RawPropValues{
-                                .int32Values = {10},
+                                .int32Values = {mMaxSupportedValueForTestIntProp},
                         },
         });
     }
@@ -2331,6 +2432,7 @@
 
 std::vector<SupportedValuesListResult> FakeVehicleHardware::getSupportedValuesLists(
         const std::vector<PropIdAreaId>& propIdAreaIds) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
     std::vector<SupportedValuesListResult> results;
     // We only support VENDOR_EXTENSION_INT_PROPERTY
     for (const auto& propIdAreaId : propIdAreaIds) {
@@ -2342,16 +2444,13 @@
             });
             continue;
         }
+        std::vector<std::optional<RawPropValues>> supportedValuesList;
+        for (int32_t value : mSupportedValuesListForTestIntProp) {
+            supportedValuesList.push_back(RawPropValues{.int32Values = {value}});
+        }
         results.push_back(SupportedValuesListResult{
                 .status = StatusCode::OK,
-                .supportedValuesList = std::vector<std::optional<RawPropValues>>({
-                        RawPropValues{.int32Values = {0}},
-                        RawPropValues{.int32Values = {2}},
-                        RawPropValues{.int32Values = {4}},
-                        RawPropValues{.int32Values = {6}},
-                        RawPropValues{.int32Values = {8}},
-                        RawPropValues{.int32Values = {10}},
-                }),
+                .supportedValuesList = supportedValuesList,
         });
     }
     return results;
diff --git a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 29a690b..a097135 100644
--- a/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/current/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -2759,6 +2759,86 @@
                               "response\nNo SetUserIdentificationAssociation response\n"));
 }
 
+TEST_F(FakeVehicleHardwareTest, testDumpSetMinMaxValue) {
+    std::vector<std::string> options = {"--set-minmaxvalue", "1", "100"};
+    std::vector<PropIdAreaId> changedPropIdAreaIds;
+
+    getHardware()->registerSupportedValueChangeCallback(
+            std::make_unique<IVehicleHardware::SupportedValueChangeCallback>(
+                    [&changedPropIdAreaIds](std::vector<PropIdAreaId> propIdAreaIds) {
+                        changedPropIdAreaIds = propIdAreaIds;
+                    }));
+
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_THAT(result.buffer, ContainsRegex("Min/Max supported value .* set"));
+
+    ASSERT_EQ(changedPropIdAreaIds.size(), 1u);
+
+    auto results = getHardware()->getMinMaxSupportedValues({PropIdAreaId{
+            .propId = toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY), .areaId = 0}});
+
+    ASSERT_EQ(results.size(), 1u);
+    EXPECT_EQ(results[0].status, StatusCode::OK);
+    EXPECT_EQ(results[0].minSupportedValue.value(), RawPropValues{.int32Values = {1}});
+    EXPECT_EQ(results[0].maxSupportedValue.value(), RawPropValues{.int32Values = {100}});
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSetMinMaxValue_invalidInt) {
+    std::vector<std::string> options = {"--set-minmaxvalue", "abc", "100"};
+
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_THAT(result.buffer, ContainsRegex("Failed"));
+
+    options = {"--set-minmaxvalue", "1", "abc"};
+
+    result = getHardware()->dump(options);
+    ASSERT_THAT(result.buffer, ContainsRegex("Failed"));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSetMinMaxValue_minLargerThanMax) {
+    std::vector<std::string> options = {"--set-minmaxvalue", "2", "1"};
+
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_THAT(result.buffer, ContainsRegex("Failed"));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSetSupportedValues) {
+    std::vector<std::string> options = {"--set-supportedvalues", "1", "2", "3"};
+    std::vector<PropIdAreaId> changedPropIdAreaIds;
+
+    getHardware()->registerSupportedValueChangeCallback(
+            std::make_unique<IVehicleHardware::SupportedValueChangeCallback>(
+                    [&changedPropIdAreaIds](std::vector<PropIdAreaId> propIdAreaIds) {
+                        changedPropIdAreaIds = propIdAreaIds;
+                    }));
+
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_FALSE(result.callerShouldDumpState);
+    ASSERT_THAT(result.buffer, ContainsRegex("Supported values list .* set"));
+
+    ASSERT_EQ(changedPropIdAreaIds.size(), 1u);
+
+    auto results = getHardware()->getSupportedValuesLists({PropIdAreaId{
+            .propId = toInt(TestVendorProperty::VENDOR_EXTENSION_INT_PROPERTY), .areaId = 0}});
+
+    ASSERT_EQ(results.size(), 1u);
+    EXPECT_EQ(results[0].status, StatusCode::OK);
+    EXPECT_NE(results[0].supportedValuesList, std::nullopt);
+    EXPECT_EQ(results[0].supportedValuesList.value(), std::vector<std::optional<RawPropValues>>({
+                                                              RawPropValues{.int32Values = {1}},
+                                                              RawPropValues{.int32Values = {2}},
+                                                              RawPropValues{.int32Values = {3}},
+                                                      }));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpSetSupportedValues_invalidInt) {
+    std::vector<std::string> options = {"--set-supportedvalues", "1", "2", "ab", "3"};
+
+    DumpResult result = getHardware()->dump(options);
+    ASSERT_THAT(result.buffer, ContainsRegex("Failed"));
+}
+
 struct SetPropTestCase {
     std::string test_name;
     std::vector<std::string> options;