Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 605faf68 authored by Yu Shan's avatar Yu Shan
Browse files

Support VUR in FakeVehicleHardware.

Support VUR in reference VHAL FakeVehicleHardware layer. Unless
specified in config, all continuous properties in reference VHAL
supports VUR.

Test: atest FakeVehicleHardwareTest
Bug: 306748801
Change-Id: I5265172996418a5d405392570673355e7860b50c
parent db4f577d
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -274,6 +274,16 @@ JsonValueParser::JsonValueParser() {
#endif  // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
}

template <>
Result<bool> JsonValueParser::convertValueToType<bool>(const std::string& fieldName,
                                                       const Json::Value& value) {
    if (!value.isBool()) {
        return Error() << "The value: " << value << " for field: " << fieldName
                       << " is not in correct type, expect bool";
    }
    return value.asBool();
}

template <>
Result<int32_t> JsonValueParser::convertValueToType<int32_t>(const std::string& fieldName,
                                                             const Json::Value& value) {
@@ -531,6 +541,12 @@ void JsonConfigParser::parseAreas(const Json::Value& parentJsonNode, const std::
        tryParseJsonValueToVariable(jsonAreaConfig, "maxFloatValue", /*optional=*/true,
                                    &areaConfig.maxFloatValue, errors);

        // By default we support variable update rate for all properties except it is explicitly
        // disabled.
        areaConfig.supportVariableUpdateRate = true;
        tryParseJsonValueToVariable(jsonAreaConfig, "supportVariableUpdateRate", /*optional=*/true,
                                    &areaConfig.supportVariableUpdateRate, errors);

        std::vector<int64_t> supportedEnumValues;
        tryParseJsonArrayToVariable(jsonAreaConfig, "supportedEnumValues", /*optional=*/true,
                                    &supportedEnumValues, errors);
@@ -585,6 +601,16 @@ std::optional<ConfigDeclaration> JsonConfigParser::parseEachProperty(
    if (errors->size() != initialErrorCount) {
        return std::nullopt;
    }

    // If there is no area config, by default we allow variable update rate, so we have to add
    // a global area config.
    if (configDecl.config.areaConfigs.size() == 0) {
        VehicleAreaConfig areaConfig = {
                .areaId = 0,
                .supportVariableUpdateRate = true,
        };
        configDecl.config.areaConfigs.push_back(std::move(areaConfig));
    }
    return configDecl;
}

+13 −1
Original line number Diff line number Diff line
@@ -3579,7 +3579,13 @@
            "property": "VehicleProperty::WATCHDOG_TERMINATED_PROCESS"
        },
        {
            "property": "VehicleProperty::VHAL_HEARTBEAT"
            "property": "VehicleProperty::VHAL_HEARTBEAT",
            "areas": [
                {
                    "areaId": 0,
                    "supportVariableUpdateRate": false
                }
            ]
        },
        {
            "property": "VehicleProperty::CLUSTER_SWITCH_UI",
@@ -3641,6 +3647,12 @@
                0,
                16
            ],
            "areas": [
                {
                    "areaId": 0,
                    "supportVariableUpdateRate": false
                }
            ],
            "comment": "configArray specifies it consists of int64[2] and byte[16]."
        },
        {
+7 −3
Original line number Diff line number Diff line
@@ -269,9 +269,9 @@ class FakeVehicleHardware : public IVehicleHardware {
            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>&) const;

    aidl::android::hardware::automotive::vehicle::StatusCode subscribePropIdAreaIdLocked(
            int32_t propId, int32_t areaId, float sampleRateHz,
            aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode changeMode)
            REQUIRES(mLock);
            int32_t propId, int32_t areaId, float sampleRateHz, bool enableVariableUpdateRate,
            const aidl::android::hardware::automotive::vehicle::VehiclePropConfig&
                    vehiclePropConfig) REQUIRES(mLock);

    static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwInputKeyProp(
            aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction action,
@@ -286,6 +286,10 @@ class FakeVehicleHardware : public IVehicleHardware {

    static std::string genFakeDataHelp();
    static std::string parseErrMsg(std::string fieldName, std::string value, std::string type);
    static bool isVariableUpdateRateSupported(
            const aidl::android::hardware::automotive::vehicle::VehiclePropConfig&
                    vehiclePropConfig,
            int32_t areaId);
};

}  // namespace fake
+33 −9
Original line number Diff line number Diff line
@@ -1941,7 +1941,8 @@ StatusCode FakeVehicleHardware::subscribe(SubscribeOptions options) {
    std::scoped_lock<std::mutex> lockGuard(mLock);
    for (int areaId : options.areaIds) {
        if (StatusCode status = subscribePropIdAreaIdLocked(propId, areaId, options.sampleRate,
                                                            configResult.value()->changeMode);
                                                            options.enableVariableUpdateRate,
                                                            *configResult.value());
            status != StatusCode::OK) {
            return status;
        }
@@ -1949,14 +1950,29 @@ StatusCode FakeVehicleHardware::subscribe(SubscribeOptions options) {
    return StatusCode::OK;
}

StatusCode FakeVehicleHardware::subscribePropIdAreaIdLocked(int32_t propId, int32_t areaId,
                                                            float sampleRateHz,
                                                            VehiclePropertyChangeMode changeMode) {
bool FakeVehicleHardware::isVariableUpdateRateSupported(const VehiclePropConfig& vehiclePropConfig,
                                                        int32_t areaId) {
    for (size_t i = 0; i < vehiclePropConfig.areaConfigs.size(); i++) {
        const auto& areaConfig = vehiclePropConfig.areaConfigs[i];
        if (areaConfig.areaId != areaId) {
            continue;
        }
        if (areaConfig.supportVariableUpdateRate) {
            return true;
        }
        break;
    }
    return false;
}

StatusCode FakeVehicleHardware::subscribePropIdAreaIdLocked(
        int32_t propId, int32_t areaId, float sampleRateHz, bool enableVariableUpdateRate,
        const VehiclePropConfig& vehiclePropConfig) {
    PropIdAreaId propIdAreaId{
            .propId = propId,
            .areaId = areaId,
    };
    switch (changeMode) {
    switch (vehiclePropConfig.changeMode) {
        case VehiclePropertyChangeMode::STATIC:
            ALOGW("subscribe to a static property, do nothing.");
            return StatusCode::OK;
@@ -1972,7 +1988,16 @@ StatusCode FakeVehicleHardware::subscribePropIdAreaIdLocked(int32_t propId, int3
                mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propIdAreaId]);
            }
            int64_t intervalInNanos = static_cast<int64_t>(1'000'000'000. / sampleRateHz);
            auto action = std::make_shared<RecurrentTimer::Callback>([this, propId, areaId] {

            // For continuous properties, we must generate a new onPropertyChange event
            // periodically according to the sample rate.
            auto eventMode = VehiclePropertyStore::EventMode::ALWAYS;
            if (isVariableUpdateRateSupported(vehiclePropConfig, areaId) &&
                enableVariableUpdateRate) {
                eventMode = VehiclePropertyStore::EventMode::ON_VALUE_CHANGE;
            }
            auto action = std::make_shared<RecurrentTimer::Callback>([this, propId, areaId,
                                                                      eventMode] {
                // Refresh the property value. In real implementation, this should poll the latest
                // value from vehicle bus. Here, we are just refreshing the existing value with a
                // new timestamp.
@@ -1986,10 +2011,9 @@ StatusCode FakeVehicleHardware::subscribePropIdAreaIdLocked(int32_t propId, int3
                    return;
                }
                result.value()->timestamp = elapsedRealtimeNano();
                // For continuous properties, we must generate a new onPropertyChange event
                // periodically according to the sample rate.

                mServerSidePropStore->writeValue(std::move(result.value()), /*updateStatus=*/true,
                                                 VehiclePropertyStore::EventMode::ALWAYS);
                                                 eventMode);
            });
            mRecurrentTimer->registerTimerCallback(intervalInNanos, action);
            mRecurrentActions[propIdAreaId] = action;
+65 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ using ::testing::ContainsRegex;
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::IsSubsetOf;
using ::testing::UnorderedElementsAre;
using ::testing::WhenSortedBy;

using std::chrono::milliseconds;
@@ -454,6 +455,29 @@ TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs) {
    ASSERT_EQ(configs.size(), helper.loadConfigDeclarations().size());
}

TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs_defaultSupportVUR) {
    std::vector<VehiclePropConfig> configs = getHardware()->getAllPropertyConfigs();

    for (const auto& config : configs) {
        bool expectedSupportVUR = true;
        if (config.prop == toInt(VehicleProperty::VHAL_HEARTBEAT) ||
            config.prop == toInt(VehicleProperty::CLUSTER_HEARTBEAT)) {
            expectedSupportVUR = false;
        }
        EXPECT_GE(config.areaConfigs.size(), 1u)
                << "expect at least one area config, including global area config, propId: "
                << config.prop;
        if (config.areaConfigs.size() == 0) {
            continue;
        }
        for (const auto& areaConfig : config.areaConfigs) {
            EXPECT_EQ(areaConfig.supportVariableUpdateRate, expectedSupportVUR)
                    << "unexpected supportVariableUpdateRate for propId: " << config.prop
                    << ", areaId: " << areaConfig.areaId;
        }
    }
}

TEST_F(FakeVehicleHardwareTest, testGetDefaultValues) {
    std::vector<GetValueRequest> getValueRequests;
    std::vector<GetValueResult> expectedGetValueResults;
@@ -3117,6 +3141,47 @@ TEST_F(FakeVehicleHardwareTest, testSubscribeUnsubscribe_continuous) {
    }
}

TEST_F(FakeVehicleHardwareTest, testSubscribe_enableVUR) {
    int32_t propSpeed = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
    int32_t areaId = 0;
    SubscribeOptions options;
    options.propId = propSpeed;
    options.areaIds = {areaId};
    options.enableVariableUpdateRate = true;
    options.sampleRate = 5;
    int64_t timestamp = elapsedRealtimeNano();

    auto status = getHardware()->subscribe(options);
    ASSERT_EQ(status, StatusCode::OK) << "failed to subscribe";

    status = setValue({
            .prop = propSpeed,
            .areaId = 0,
            .value.floatValues = {1.1f},
    });
    ASSERT_EQ(status, StatusCode::OK) << "failed to set speed";

    status = setValue({
            .prop = propSpeed,
            .areaId = 0,
            .value.floatValues = {1.2f},
    });
    ASSERT_EQ(status, StatusCode::OK) << "failed to set speed";

    ASSERT_TRUE(waitForChangedProperties(propSpeed, areaId, /*count=*/2, milliseconds(100)))
            << "not enough events generated for speed";
    auto updatedValues = getChangedProperties();
    std::unordered_set<float> gotValues;
    for (auto& value : updatedValues) {
        EXPECT_GE(value.timestamp, timestamp) << "timestamp must be updated";
        EXPECT_EQ(value.prop, propSpeed) << "propId must be correct";
        EXPECT_EQ(value.areaId, areaId) << "areaId must be correct";
        gotValues.insert(value.value.floatValues[0]);
    }
    EXPECT_THAT(gotValues, UnorderedElementsAre(1.1f, 1.2f))
            << "must only receive property event for changed value";
}

TEST_F(FakeVehicleHardwareTest, testSubscribeUnusubscribe_onChange) {
    int32_t propHvac = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);
    int32_t areaId = SEAT_1_LEFT;