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

Commit 1aefc1fd authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add retries to vibrator HAL controller"

parents c5fb9a25 37d0f048
Loading
Loading
Loading
Loading
+22 −11
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ namespace vibrator {

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

static constexpr int MAX_RETRIES = 1;

template <typename T>
using hal_connect_fn = std::function<sp<T>()>;

@@ -111,6 +113,14 @@ std::shared_ptr<HalWrapper> HalConnector::connect(std::shared_ptr<CallbackSchedu

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

std::shared_ptr<HalWrapper> HalController::initHal() {
    std::lock_guard<std::mutex> lock(mConnectedHalMutex);
    if (mConnectedHal == nullptr) {
        mConnectedHal = mHalConnector->connect(mCallbackScheduler);
    }
    return mConnectedHal;
}

template <typename T>
HalResult<T> HalController::processHalResult(HalResult<T> result, const char* functionName) {
    if (result.isFailed()) {
@@ -124,20 +134,21 @@ HalResult<T> HalController::processHalResult(HalResult<T> result, const char* fu

template <typename T>
HalResult<T> HalController::apply(HalController::hal_fn<T>& halFn, const char* functionName) {
    std::shared_ptr<HalWrapper> hal = nullptr;
    {
        std::lock_guard<std::mutex> lock(mConnectedHalMutex);
        if (mConnectedHal == nullptr) {
            mConnectedHal = mHalConnector->connect(mCallbackScheduler);
        }
        hal = mConnectedHal;
    std::shared_ptr<HalWrapper> hal = initHal();
    if (hal == nullptr) {
        ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
        return HalResult<T>::unsupported();
    }

    HalResult<T> ret = processHalResult(halFn(hal), functionName);
    for (int i = 0; i < MAX_RETRIES && ret.isFailed(); i++) {
        hal = initHal();
        if (hal) {
        return processHalResult(halFn(hal), functionName);
            ret = processHalResult(halFn(hal), functionName);
        }
    }

    ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
    return HalResult<T>::unsupported();
    return ret;
}

// -------------------------------------------------------------------------------------------------
+2 −0
Original line number Diff line number Diff line
@@ -81,6 +81,8 @@ private:
    // Shared pointer to allow local copies to be used by different threads.
    std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);

    std::shared_ptr<HalWrapper> initHal();

    template <typename T>
    HalResult<T> processHalResult(HalResult<T> result, const char* functionName);

+43 −20
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ using namespace android;
using namespace std::chrono_literals;
using namespace testing;

static constexpr int MAX_ATTEMPTS = 2;

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

class MockHalWrapper : public vibrator::HalWrapper {
@@ -125,41 +127,45 @@ protected:
    std::shared_ptr<MockHalWrapper> mMockHal;
    std::unique_ptr<vibrator::HalController> mController;

    void setHalExpectations(std::vector<CompositeEffect> compositeEffects,
    void setHalExpectations(int32_t cardinality, std::vector<CompositeEffect> compositeEffects,
                            vibrator::HalResult<void> voidResult,
                            vibrator::HalResult<vibrator::Capabilities> capabilitiesResult,
                            vibrator::HalResult<std::vector<Effect>> effectsResult,
                            vibrator::HalResult<milliseconds> durationResult) {
        InSequence seq;
        EXPECT_CALL(*mMockHal.get(), ping()).Times(Exactly(1)).WillRepeatedly(Return(voidResult));
        EXPECT_CALL(*mMockHal.get(), ping())
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(voidResult));
        EXPECT_CALL(*mMockHal.get(), on(Eq(10ms), _))
                .Times(Exactly(1))
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(voidResult));
        EXPECT_CALL(*mMockHal.get(), off())
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(voidResult));
        EXPECT_CALL(*mMockHal.get(), off()).Times(Exactly(1)).WillRepeatedly(Return(voidResult));
        EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(255)))
                .Times(Exactly(1))
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(voidResult));
        EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(true)))
                .Times(Exactly(1))
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(voidResult));
        EXPECT_CALL(*mMockHal.get(),
                    alwaysOnEnable(Eq(1), Eq(Effect::CLICK), Eq(EffectStrength::LIGHT)))
                .Times(Exactly(1))
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(voidResult));
        EXPECT_CALL(*mMockHal.get(), alwaysOnDisable(Eq(1)))
                .Times(Exactly(1))
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(voidResult));
        EXPECT_CALL(*mMockHal.get(), getCapabilities())
                .Times(Exactly(1))
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(capabilitiesResult));
        EXPECT_CALL(*mMockHal.get(), getSupportedEffects())
                .Times(Exactly(1))
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(effectsResult));
        EXPECT_CALL(*mMockHal.get(), performEffect(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _))
                .Times(Exactly(1))
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(durationResult));
        EXPECT_CALL(*mMockHal.get(), performComposedEffect(Eq(compositeEffects), _))
                .Times(Exactly(1))
                .Times(Exactly(cardinality))
                .WillRepeatedly(Return(voidResult));
    }
};
@@ -176,7 +182,7 @@ TEST_F(VibratorHalControllerTest, TestApiCallsAreForwardedToHal) {
    compositeEffects.push_back(
            vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 1000ms, 1.0f));

    setHalExpectations(compositeEffects, vibrator::HalResult<void>::ok(),
    setHalExpectations(/* cardinality= */ 1, compositeEffects, vibrator::HalResult<void>::ok(),
                       vibrator::HalResult<vibrator::Capabilities>::ok(
                               vibrator::Capabilities::ON_CALLBACK),
                       vibrator::HalResult<std::vector<Effect>>::ok(supportedEffects),
@@ -210,7 +216,8 @@ TEST_F(VibratorHalControllerTest, TestApiCallsAreForwardedToHal) {
}

TEST_F(VibratorHalControllerTest, TestUnsupportedApiResultDoNotResetHalConnection) {
    setHalExpectations(std::vector<CompositeEffect>(), vibrator::HalResult<void>::unsupported(),
    setHalExpectations(/* cardinality= */ 1, std::vector<CompositeEffect>(),
                       vibrator::HalResult<void>::unsupported(),
                       vibrator::HalResult<vibrator::Capabilities>::unsupported(),
                       vibrator::HalResult<std::vector<Effect>>::unsupported(),
                       vibrator::HalResult<milliseconds>::unsupported());
@@ -237,7 +244,8 @@ TEST_F(VibratorHalControllerTest, TestUnsupportedApiResultDoNotResetHalConnectio
}

TEST_F(VibratorHalControllerTest, TestFailedApiResultResetsHalConnection) {
    setHalExpectations(std::vector<CompositeEffect>(), vibrator::HalResult<void>::failed(),
    setHalExpectations(MAX_ATTEMPTS, std::vector<CompositeEffect>(),
                       vibrator::HalResult<void>::failed(),
                       vibrator::HalResult<vibrator::Capabilities>::failed(),
                       vibrator::HalResult<std::vector<Effect>>::failed(),
                       vibrator::HalResult<milliseconds>::failed());
@@ -258,8 +266,23 @@ TEST_F(VibratorHalControllerTest, TestFailedApiResultResetsHalConnection) {
    ASSERT_TRUE(
            mController->performComposedEffect(std::vector<CompositeEffect>(), []() {}).isFailed());

    // One reconnection attempt per api call.
    ASSERT_EQ(11, mConnectCounter);
    // One reconnection attempt + retry attempts per api call.
    ASSERT_EQ(11 * MAX_ATTEMPTS, mConnectCounter);
}

TEST_F(VibratorHalControllerTest, TestFailedApiResultReturnsSuccessAfterRetries) {
    {
        InSequence seq;
        EXPECT_CALL(*mMockHal.get(), ping())
                .Times(Exactly(2))
                .WillOnce(Return(vibrator::HalResult<void>::failed()))
                .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
    }

    ASSERT_EQ(0, mConnectCounter);
    ASSERT_TRUE(mController->ping().isOk());
    // One connect + one retry.
    ASSERT_EQ(2, mConnectCounter);
}

TEST_F(VibratorHalControllerTest, TestMultiThreadConnectsOnlyOnce) {
@@ -279,7 +302,7 @@ TEST_F(VibratorHalControllerTest, TestMultiThreadConnectsOnlyOnce) {
    ASSERT_EQ(1, mConnectCounter);
}

TEST_F(VibratorHalControllerTest, TestNoHalReturnsUnsupportedAndAttemptsToReconnect) {
TEST_F(VibratorHalControllerTest, TestNoVibratorReturnsUnsupportedAndAttemptsToReconnect) {
    auto failingHalConnector = std::make_unique<FailingHalConnector>(&mConnectCounter);
    mController =
            std::make_unique<vibrator::HalController>(std::move(failingHalConnector), nullptr);
@@ -300,7 +323,7 @@ TEST_F(VibratorHalControllerTest, TestNoHalReturnsUnsupportedAndAttemptsToReconn
    ASSERT_TRUE(mController->performComposedEffect(std::vector<CompositeEffect>(), []() {})
                        .isUnsupported());

    // One reconnection attempt per api call.
    // One reconnection attempt per api call, no retry.
    ASSERT_EQ(11, mConnectCounter);
}

@@ -314,7 +337,7 @@ TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
                    return vibrator::HalResult<void>::ok();
                });
        EXPECT_CALL(*mMockHal.get(), ping())
                .Times(Exactly(1))
                .Times(Exactly(MAX_ATTEMPTS))
                .WillRepeatedly(Return(vibrator::HalResult<void>::failed()));
    }