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

Commit d39ff7de authored by Lais Andrade's avatar Lais Andrade
Browse files

Cache results from Vibrator HAL getters in wrapper

Cache HAL capabilities and supported effects, since these values do not
change for the same underlying HAL.

Bug: 153418251
Test: atest libvibratorservice_test
Change-Id: I23b9480d23810debb065794071319003360857cb
parent bf5d11d3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
*.iml
*.pyc
.idea/
+49 −23
Original line number Diff line number Diff line
@@ -43,6 +43,18 @@ namespace vibrator {

// -------------------------------------------------------------------------------------------------

template <class T>
HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) {
    if (cache.has_value()) {
        return HalResult<T>::ok(cache.value());
    }
    HalResult<T> ret = loadFn();
    if (ret.isOk()) {
        cache.emplace(ret.value());
    }
    return ret;
}

template <class T>
bool isStaticCastValid(Effect effect) {
    T castEffect = static_cast<T>(effect);
@@ -214,15 +226,23 @@ HalResult<void> AidlHalWrapper::alwaysOnDisable(int32_t id) {
}

HalResult<Capabilities> AidlHalWrapper::getCapabilities() {
    std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
    static auto loadFn = [this]() {
        int32_t capabilities = 0;
        auto result = mHandle->getCapabilities(&capabilities);
        return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
    };
    return loadCached<Capabilities>(loadFn, mCapabilities);
}

HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() {
    std::lock_guard<std::mutex> lock(mSupportedEffectsMutex);
    static auto loadFn = [this]() {
        std::vector<Effect> supportedEffects;
        auto result = mHandle->getSupportedEffects(&supportedEffects);
        return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
    };
    return loadCached<std::vector<Effect>>(loadFn, mSupportedEffects);
}

HalResult<milliseconds> AidlHalWrapper::performEffect(
@@ -279,10 +299,9 @@ HalResult<void> HidlHalWrapperV1_0::alwaysOnDisable(int32_t) {
}

HalResult<Capabilities> HidlHalWrapperV1_0::getCapabilities() {
    hardware::Return<bool> result = mHandleV1_0->supportsAmplitudeControl();
    Capabilities capabilities =
            result.withDefault(false) ? Capabilities::AMPLITUDE_CONTROL : Capabilities::NONE;
    return HalResult<Capabilities>::fromReturn(result, capabilities);
    std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
    return loadCached<Capabilities>(std::bind(&HidlHalWrapperV1_0::getCapabilitiesInternal, this),
                                    mCapabilities);
}

HalResult<std::vector<Effect>> HidlHalWrapperV1_0::getSupportedEffects() {
@@ -308,6 +327,13 @@ HalResult<void> HidlHalWrapperV1_0::performComposedEffect(const std::vector<Comp
    return HalResult<void>::unsupported();
}

HalResult<Capabilities> HidlHalWrapperV1_0::getCapabilitiesInternal() {
    hardware::Return<bool> result = mHandleV1_0->supportsAmplitudeControl();
    Capabilities capabilities =
            result.withDefault(false) ? Capabilities::AMPLITUDE_CONTROL : Capabilities::NONE;
    return HalResult<Capabilities>::fromReturn(result, capabilities);
}

// -------------------------------------------------------------------------------------------------

HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(Effect effect, EffectStrength strength,
@@ -355,19 +381,6 @@ HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) {
    return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
}

HalResult<Capabilities> HidlHalWrapperV1_3::getCapabilities() {
    HalResult<Capabilities> parentResult = HidlHalWrapperV1_2::getCapabilities();
    if (!parentResult.isOk()) {
        // Loading for versions up to v1.2 already failed, so propagate failure.
        return parentResult;
    }

    Capabilities capabilities = parentResult.value();
    auto result = mHandleV1_3->supportsExternalControl();
    capabilities |= result.withDefault(false) ? Capabilities::EXTERNAL_CONTROL : Capabilities::NONE;
    return HalResult<Capabilities>::fromReturn(result, capabilities);
}

HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(Effect effect, EffectStrength strength,
                                                          const std::function<void()>&) {
    if (isStaticCastValid<V1_0::Effect>(effect)) {
@@ -392,6 +405,19 @@ HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(Effect effect, EffectS
    return HalResult<milliseconds>::unsupported();
}

HalResult<Capabilities> HidlHalWrapperV1_3::getCapabilitiesInternal() {
    HalResult<Capabilities> parentResult = HidlHalWrapperV1_2::getCapabilitiesInternal();
    if (!parentResult.isOk()) {
        // Loading for previous HAL versions already failed, so propagate failure.
        return parentResult;
    }

    Capabilities capabilities = parentResult.value();
    auto result = mHandleV1_3->supportsExternalControl();
    capabilities |= result.withDefault(false) ? Capabilities::EXTERNAL_CONTROL : Capabilities::NONE;
    return HalResult<Capabilities>::fromReturn(result, capabilities);
}

// -------------------------------------------------------------------------------------------------

}; // namespace vibrator
+12 −1
Original line number Diff line number Diff line
@@ -181,6 +181,11 @@ public:

private:
    const sp<hardware::vibrator::IVibrator> mHandle;
    std::mutex mCapabilitiesMutex;
    std::mutex mSupportedEffectsMutex;
    std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
    std::optional<std::vector<hardware::vibrator::Effect>> mSupportedEffects
            GUARDED_BY(mSupportedEffectsMutex);
};

// Wrapper for the HDIL Vibrator HAL v1.0.
@@ -215,6 +220,11 @@ public:

protected:
    const sp<hardware::vibrator::V1_0::IVibrator> mHandleV1_0;
    std::mutex mCapabilitiesMutex;
    std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);

    // Loads directly from IVibrator handle, skipping the mCapabilities cache.
    virtual HalResult<Capabilities> getCapabilitiesInternal();
};

// Wrapper for the HDIL Vibrator HAL v1.1.
@@ -255,7 +265,6 @@ public:
            mHandleV1_3(hardware::vibrator::V1_3::IVibrator::castFrom(handleV1_0)) {}

    virtual HalResult<void> setExternalControl(bool enabled) override;
    virtual HalResult<Capabilities> getCapabilities() override;

    virtual HalResult<std::chrono::milliseconds> performEffect(
            hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
@@ -263,6 +272,8 @@ public:

protected:
    const sp<hardware::vibrator::V1_3::IVibrator> mHandleV1_3;

    virtual HalResult<Capabilities> getCapabilitiesInternal() override;
};

// -------------------------------------------------------------------------------------------------
+49 −10
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <gtest/gtest.h>

#include <utils/Log.h>
#include <thread>

#include <vibratorservice/VibratorHalWrapper.h>

@@ -243,38 +244,76 @@ TEST_F(VibratorHalWrapperAidlTest, TestAlwaysOnDisable) {
    ASSERT_TRUE(mWrapper->alwaysOnDisable(3).isFailed());
}

TEST_F(VibratorHalWrapperAidlTest, TestGetCapabilities) {
TEST_F(VibratorHalWrapperAidlTest, TestGetCapabilitiesDoesNotCacheFailedResult) {
    EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
            .Times(Exactly(3))
            .WillOnce(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())))
            .WillOnce(
                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
            .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
            .WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));

    ASSERT_TRUE(mWrapper->getCapabilities().isUnsupported());
    ASSERT_TRUE(mWrapper->getCapabilities().isFailed());

    auto result = mWrapper->getCapabilities();
    ASSERT_TRUE(result.isOk());
    ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
    ASSERT_TRUE(mWrapper->getCapabilities().isUnsupported());
    ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
}

TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedEffects) {
TEST_F(VibratorHalWrapperAidlTest, TestGetCapabilitiesCachesResult) {
    EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
            .Times(Exactly(1))
            .WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));

    std::vector<std::thread> threads;
    for (int i = 0; i < 10; i++) {
        threads.push_back(std::thread([&]() {
            auto result = mWrapper->getCapabilities();
            ASSERT_TRUE(result.isOk());
            ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
        }));
    }
    std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
}

TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedEffectsDoesNotCacheFailedResult) {
    std::vector<Effect> supportedEffects;
    supportedEffects.push_back(Effect::CLICK);
    supportedEffects.push_back(Effect::TICK);

    EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_))
            .Times(Exactly(3))
            .WillOnce(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())))
            .WillOnce(
                    Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
            .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
            .WillRepeatedly(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())));

    ASSERT_TRUE(mWrapper->getSupportedEffects().isUnsupported());
    ASSERT_TRUE(mWrapper->getSupportedEffects().isFailed());

    auto result = mWrapper->getSupportedEffects();
    ASSERT_TRUE(result.isOk());
    ASSERT_EQ(supportedEffects, result.value());
    ASSERT_TRUE(mWrapper->getSupportedEffects().isUnsupported());
    ASSERT_TRUE(mWrapper->getSupportedEffects().isFailed());
}

TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedEffectsCachesResult) {
    std::vector<Effect> supportedEffects;
    supportedEffects.push_back(Effect::CLICK);
    supportedEffects.push_back(Effect::TICK);

    EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_))
            .Times(Exactly(1))
            .WillRepeatedly(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())));

    std::vector<std::thread> threads;
    for (int i = 0; i < 10; i++) {
        threads.push_back(std::thread([&]() {
            auto result = mWrapper->getSupportedEffects();
            ASSERT_TRUE(result.isOk());
            ASSERT_EQ(supportedEffects, result.value());
        }));
    }
    std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
}

TEST_F(VibratorHalWrapperAidlTest, TestPerformEffect) {
+31 −11
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <gtest/gtest.h>

#include <utils/Log.h>
#include <thread>

#include <vibratorservice/VibratorHalWrapper.h>

@@ -186,29 +187,48 @@ TEST_F(VibratorHalWrapperHidlV1_0Test, TestAlwaysOnDisableUnsupported) {
    ASSERT_TRUE(mWrapper->alwaysOnDisable(1).isUnsupported());
}

TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilities) {
TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilitiesDoesNotCacheFailedResult) {
    EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
            .Times(Exactly(3))
            .WillOnce([]() { return hardware::Return<bool>(true); })
            .WillOnce([]() { return hardware::Return<bool>(false); })
            .WillRepeatedly([]() {
            .Times(Exactly(2))
            .WillOnce([]() {
                return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
            });
            })
            .WillRepeatedly([]() { return hardware::Return<bool>(true); });

    ASSERT_TRUE(mWrapper->getCapabilities().isFailed());

    // Amplitude control enabled.
    auto result = mWrapper->getCapabilities();
    ASSERT_TRUE(result.isOk());
    ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
}

TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilitiesWithoutAmplitudeControl) {
    EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillRepeatedly([]() {
        return hardware::Return<bool>(false);
    });

    // Amplitude control disabled.
    result = mWrapper->getCapabilities();
    auto result = mWrapper->getCapabilities();
    ASSERT_TRUE(result.isOk());
    ASSERT_EQ(vibrator::Capabilities::NONE, result.value());
}

    ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilitiesCachesResult) {
    EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillRepeatedly([]() {
        return hardware::Return<bool>(true);
    });

    std::vector<std::thread> threads;
    for (int i = 0; i < 10; i++) {
        threads.push_back(std::thread([&]() {
            auto result = mWrapper->getCapabilities();
            ASSERT_TRUE(result.isOk());
            ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
        }));
    }
    std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
}

TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetSupportedEffects) {
TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetSupportedEffectsUnsupported) {
    ASSERT_TRUE(mWrapper->getSupportedEffects().isUnsupported());
}

Loading