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

Commit a1a49af6 authored by Ady Abraham's avatar Ady Abraham Committed by Ana Krulec
Browse files

SurfaceFlinger: Scheduler: move reset callback to scheduler thread

Dispatch timer reset callback from Scheduler's thread. This would
make both Scheduler callbacks (idle timer and reset timer) to be dispatched
from the same context and avoid any potential deadlocks.

Test: surfaceflinger unit tests
Change-Id: Iad7d10b85db090662f9b7c4ffb45ed9110035ea4
parent 482b4b1b
Loading
Loading
Loading
Loading
+35 −11
Original line number Diff line number Diff line
@@ -22,8 +22,9 @@
namespace android {
namespace scheduler {

IdleTimer::IdleTimer(const Interval& interval, const TimeoutCallback& timeoutCallback)
      : mInterval(interval), mTimeoutCallback(timeoutCallback) {}
IdleTimer::IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
                     const TimeoutCallback& timeoutCallback)
      : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {}

IdleTimer::~IdleTimer() {
    stop();
@@ -49,11 +50,34 @@ void IdleTimer::stop() {
}

void IdleTimer::loop() {
    while (true) {
        bool triggerReset = false;
        bool triggerTimeout = false;
        {
            std::lock_guard<std::mutex> lock(mMutex);
    while (mState != TimerState::STOPPED) {
            if (mState == TimerState::STOPPED) {
                break;
            }

            if (mState == TimerState::IDLE) {
                mCondition.wait(mMutex);
        } else if (mState == TimerState::RESET) {
                continue;
            }

            if (mState == TimerState::RESET) {
                triggerReset = true;
            }
        }
        if (triggerReset && mResetCallback) {
            mResetCallback();
        }

        { // lock the mutex again. someone might have called stop meanwhile
            std::lock_guard<std::mutex> lock(mMutex);
            if (mState == TimerState::STOPPED) {
                break;
            }

            auto triggerTime = std::chrono::steady_clock::now() + mInterval;
            mState = TimerState::WAITING;
            while (mState == TimerState::WAITING) {
@@ -62,14 +86,14 @@ void IdleTimer::loop() {
                if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
                if (mState == TimerState::WAITING &&
                    (triggerTime - std::chrono::steady_clock::now()) <= zero) {
                    if (mTimeoutCallback) {
                        mTimeoutCallback();
                    }

                    triggerTimeout = true;
                    mState = TimerState::IDLE;
                }
            }
        }
        if (triggerTimeout && mTimeoutCallback) {
            mTimeoutCallback();
        }
    }
} // namespace scheduler

+6 −1
Original line number Diff line number Diff line
@@ -32,9 +32,11 @@ namespace scheduler {
class IdleTimer {
public:
    using Interval = std::chrono::milliseconds;
    using ResetCallback = std::function<void()>;
    using TimeoutCallback = std::function<void()>;

    IdleTimer(const Interval& interval, const TimeoutCallback& timeoutCallback);
    IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
              const TimeoutCallback& timeoutCallback);
    ~IdleTimer();

    void start();
@@ -62,6 +64,9 @@ private:
    // Interval after which timer expires.
    const Interval mInterval;

    // Callback that happens when timer resets.
    const ResetCallback mResetCallback;

    // Callback that happens when timer expires.
    const TimeoutCallback mTimeoutCallback;
};
+19 −17
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function)
    if (mSetIdleTimerMs > 0) {
        mIdleTimer =
                std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetIdleTimerMs),
                                                       [this] { resetTimerCallback(); },
                                                       [this] { expiredTimerCallback(); });
        mIdleTimer->start();
    }
@@ -87,7 +88,6 @@ Scheduler::~Scheduler() {

sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
        const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
        ResetIdleTimerCallback resetIdleTimerCallback,
        impl::EventThread::InterceptVSyncsCallback interceptCallback) {
    const int64_t id = sNextId++;
    ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
@@ -97,8 +97,7 @@ sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
                            std::move(interceptCallback));

    auto eventThreadConnection =
            createConnectionInternal(eventThread.get(), std::move(resyncCallback),
                                     std::move(resetIdleTimerCallback));
            createConnectionInternal(eventThread.get(), std::move(resyncCallback));
    mConnections.emplace(id,
                         std::make_unique<Connection>(new ConnectionHandle(id),
                                                      eventThreadConnection,
@@ -115,26 +114,17 @@ std::unique_ptr<EventThread> Scheduler::makeEventThread(
                                               std::move(interceptCallback), connectionName);
}

sp<EventThreadConnection> Scheduler::createConnectionInternal(
        EventThread* eventThread, ResyncCallback&& resyncCallback,
        ResetIdleTimerCallback&& resetIdleTimerCallback) {
sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread,
                                                              ResyncCallback&& resyncCallback) {
    return eventThread->createEventConnection(std::move(resyncCallback),
                                              [this,
                                               resetIdleTimerCallback =
                                                       std::move(resetIdleTimerCallback)] {
                                                  resetIdleTimer();
                                                  if (resetIdleTimerCallback) {
                                                      resetIdleTimerCallback();
                                                  }
                                              });
                                              [this] { resetIdleTimer(); });
}

sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
        const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
        ResetIdleTimerCallback resetIdleTimerCallback) {
        const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
    RETURN_VALUE_IF_INVALID(nullptr);
    return createConnectionInternal(mConnections[handle->id]->thread.get(),
                                    std::move(resyncCallback), std::move(resetIdleTimerCallback));
                                    std::move(resyncCallback));
}

EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -263,6 +253,11 @@ void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expi
    mExpiredTimerCallback = expiredTimerCallback;
}

void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    mResetTimerCallback = resetTimerCallback;
}

void Scheduler::updateFrameSkipping(const int64_t skipCount) {
    ATRACE_INT("FrameSkipCount", skipCount);
    if (mSkipCount != skipCount) {
@@ -351,6 +346,13 @@ void Scheduler::determineTimestampAverage(bool isAutoTimestamp, const nsecs_t fr
void Scheduler::resetIdleTimer() {
    if (mIdleTimer) {
        mIdleTimer->reset();
    }
}

void Scheduler::resetTimerCallback() {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mResetTimerCallback) {
        mResetTimerCallback();
        ATRACE_INT("ExpiredIdleTimer", 0);
    }
}
+9 −6
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ class EventControlThread;
class Scheduler {
public:
    using ExpiredIdleTimerCallback = std::function<void()>;
    using ResetIdleTimerCallback = std::function<void()>;

    // Enum to indicate whether to start the transaction early, or at vsync time.
    enum class TransactionStart { EARLY, NORMAL };
@@ -72,12 +73,11 @@ public:

    /** Creates an EventThread connection. */
    sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
                                          ResyncCallback, ResetIdleTimerCallback,
                                          ResyncCallback,
                                          impl::EventThread::InterceptVSyncsCallback);

    sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
                                                             ResyncCallback,
                                                             ResetIdleTimerCallback);
                                                             ResyncCallback);

    // Getter methods.
    EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -117,6 +117,8 @@ public:
    void incrementFrameCounter();
    // Callback that gets invoked once the idle timer expires.
    void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
    // Callback that gets invoked once the idle timer is reset.
    void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
    // Returns relevant information about Scheduler for dumpsys purposes.
    std::string doDump();

@@ -127,8 +129,7 @@ protected:

private:
    // Creates a connection on the given EventThread and forwards the given callbacks.
    sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
                                                       ResetIdleTimerCallback&&);
    sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);

    nsecs_t calculateAverage() const;
    void updateFrameSkipping(const int64_t skipCount);
@@ -140,10 +141,11 @@ private:
    void determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime);
    // Function that resets the idle timer.
    void resetIdleTimer();
    // Function that is called when the timer resets.
    void resetTimerCallback();
    // Function that is called when the timer expires.
    void expiredTimerCallback();


    // If fences from sync Framework are supported.
    const bool mHasSyncFramework;

@@ -184,6 +186,7 @@ private:

    std::mutex mCallbackLock;
    ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
    ExpiredIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
};

} // namespace android
+7 −13
Original line number Diff line number Diff line
@@ -635,17 +635,13 @@ void SurfaceFlinger::init() {
        mPhaseOffsets->setRefreshRateType(
                scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);

        auto resetIdleTimerCallback =
                std::bind(&SurfaceFlinger::setRefreshRateTo, this, RefreshRateType::PERFORMANCE);

        mAppConnectionHandle =
                mScheduler->createConnection("appConnection", mPhaseOffsets->getCurrentAppOffset(),
                                             resyncCallback, resetIdleTimerCallback,
                                             resyncCallback,
                                             impl::EventThread::InterceptVSyncsCallback());
        mSfConnectionHandle =
                mScheduler->createConnection("sfConnection", mPhaseOffsets->getCurrentSfOffset(),
                                             resyncCallback, resetIdleTimerCallback,
                                             [this](nsecs_t timestamp) {
                                             resyncCallback, [this](nsecs_t timestamp) {
                                                 mInterceptor->saveVSyncEvent(timestamp);
                                             });

@@ -749,6 +745,10 @@ void SurfaceFlinger::init() {
            Mutex::Autolock lock(mStateLock);
            setRefreshRateTo(RefreshRateType::DEFAULT);
        });
        mScheduler->setResetIdleTimerCallback([this] {
            Mutex::Autolock lock(mStateLock);
            setRefreshRateTo(RefreshRateType::PERFORMANCE);
        });

        mRefreshRateStats =
                std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
@@ -1334,16 +1334,10 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
    });

    if (mUseScheduler) {
        auto resetIdleTimerCallback = [this] {
            Mutex::Autolock lock(mStateLock);
            setRefreshRateTo(RefreshRateType::PERFORMANCE);
        };

        const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle
                                                                       : mAppConnectionHandle;

        return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback),
                                                        std::move(resetIdleTimerCallback));
        return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
    } else {
        if (vsyncSource == eVsyncSourceSurfaceFlinger) {
            return mSFEventThread->createEventConnection(resyncCallback, ResetIdleTimerCallback());
Loading