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

Commit 0fd347a0 authored by Matt Buckley's avatar Matt Buckley
Browse files

Fix flaky notifyPowerBoostNotifiesTouchEvent test

This patch fixes the flaky notifyPowerBoostNotifiesTouchEvent test by
forcing all operations to happen in a deterministic order, avoiding
races.

Bug: 332875603
Test: atest libsurfaceflinger_unittest:DisplayTransactionTest
Change-Id: I882c8cce57f071ec0c4c4e59f1b00dcca090c650
parent ee5b0390
Loading
Loading
Loading
Loading
+29 −8
Original line number Original line Diff line number Diff line
@@ -33,24 +33,45 @@ using aidl::android::hardware::power::Boost;
TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
    using namespace std::chrono_literals;
    using namespace std::chrono_literals;


    std::mutex timerMutex;
    std::condition_variable cv;

    injectDefaultInternalDisplay([](FakeDisplayDeviceInjector&) {});
    injectDefaultInternalDisplay([](FakeDisplayDeviceInjector&) {});


    mFlinger.scheduler()->replaceTouchTimer(100);
    std::unique_lock lock(timerMutex);
    std::this_thread::sleep_for(10ms);                  // wait for callback to be triggered
    bool didReset = false; // keeps track of what the most recent call was

    auto waitForTimerReset = [&] { cv.wait_for(lock, 100ms, [&] { return didReset; }); };
    auto waitForTimerExpired = [&] { cv.wait_for(lock, 100ms, [&] { return !didReset; }); };

    // Add extra logic to unblock the test when the timer callbacks get called
    mFlinger.scheduler()->replaceTouchTimer(10, [&](bool isReset) {
        {
            std::unique_lock lock(timerMutex); // guarantee we're waiting on the cv
            didReset = isReset;
        }
        cv.notify_one();                   // wake the cv
        std::unique_lock lock(timerMutex); // guarantee we finished the cv logic
    });

    waitForTimerReset();
    EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch
    EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch


    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
    waitForTimerExpired();
    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive()); // Stopping timer deactivates touch


    EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::CAMERA_SHOT)));
    EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::CAMERA_SHOT)));
    std::this_thread::sleep_for(10ms); // wait for callback to maybe be triggered
    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());


    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
    // Wait for the timer to start just in case
    waitForTimerReset();
    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
    // Wait for the timer to stop, again just in case
    waitForTimerExpired();
    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());


    EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)));
    EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)));
    std::this_thread::sleep_for(10ms); // wait for callback to be triggered.
    waitForTimerReset();
    EXPECT_TRUE(mFlinger.scheduler()->isTouchActive());
    EXPECT_TRUE(mFlinger.scheduler()->isTouchActive());
}
}


+14 −3
Original line number Original line Diff line number Diff line
@@ -140,14 +140,25 @@ public:
        return mLayerHistory.mActiveLayerInfos.size();
        return mLayerHistory.mActiveLayerInfos.size();
    }
    }


    void replaceTouchTimer(int64_t millis) {
    void replaceTouchTimer(int64_t millis,
                           std::function<void(bool isReset)>&& testCallback = nullptr) {
        if (mTouchTimer) {
        if (mTouchTimer) {
            mTouchTimer.reset();
            mTouchTimer.reset();
        }
        }
        mTouchTimer.emplace(
        mTouchTimer.emplace(
                "Testable Touch timer", std::chrono::milliseconds(millis),
                "Testable Touch timer", std::chrono::milliseconds(millis),
                [this] { touchTimerCallback(TimerState::Reset); },
                [this, testCallback] {
                [this] { touchTimerCallback(TimerState::Expired); });
                    touchTimerCallback(TimerState::Reset);
                    if (testCallback != nullptr) {
                        testCallback(true);
                    }
                },
                [this, testCallback] {
                    touchTimerCallback(TimerState::Expired);
                    if (testCallback != nullptr) {
                        testCallback(false);
                    }
                });
        mTouchTimer->start();
        mTouchTimer->start();
    }
    }