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

Commit 7448e0c3 authored by Dominik Laskowski's avatar Dominik Laskowski Committed by Android (Google) Code Review
Browse files

Merge "SF: Do not toggle idle timer on display hotplug" into main

parents acb36242 b9724196
Loading
Loading
Loading
Loading
+39 −26
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ Scheduler::~Scheduler() {
    mTouchTimer.reset();

    // Stop idle timer and clear callbacks, as the RefreshRateSelector may outlive the Scheduler.
    demotePacesetterDisplay();
    demotePacesetterDisplay({.toggleIdleTimer = true});
}

void Scheduler::initVsync(frametimeline::TokenManager& tokenManager,
@@ -118,9 +118,10 @@ void Scheduler::startTimers() {
}

void Scheduler::setPacesetterDisplay(PhysicalDisplayId pacesetterId) {
    demotePacesetterDisplay();
    constexpr PromotionParams kPromotionParams = {.toggleIdleTimer = true};

    promotePacesetterDisplay(pacesetterId);
    demotePacesetterDisplay(kPromotionParams);
    promotePacesetterDisplay(pacesetterId, kPromotionParams);
}

void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
@@ -139,16 +140,22 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
                                        RefreshRateSelectorPtr selectorPtr,
                                        VsyncSchedulePtr schedulePtr,
                                        PhysicalDisplayId activeDisplayId) {
    demotePacesetterDisplay();
    const bool isPrimary = (ftl::FakeGuard(mDisplayLock), !mPacesetterDisplayId);

    auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) {
    // Start the idle timer for the first registered (i.e. primary) display.
    const PromotionParams promotionParams = {.toggleIdleTimer = isPrimary};

    demotePacesetterDisplay(promotionParams);

    auto [pacesetterVsyncSchedule, isNew] = [&]() REQUIRES(kMainThreadContext) {
        std::scoped_lock lock(mDisplayLock);
        const bool isNew = mDisplays
                                   .emplace_or_replace(displayId, displayId, std::move(selectorPtr),
                                                       std::move(schedulePtr), mFeatures)
                                   .second;

        return std::make_pair(promotePacesetterDisplayLocked(activeDisplayId), isNew);
        return std::make_pair(promotePacesetterDisplayLocked(activeDisplayId, promotionParams),
                              isNew);
    }();

    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
@@ -166,7 +173,8 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId, PhysicalDisplayId

    dispatchHotplug(displayId, Hotplug::Disconnected);

    demotePacesetterDisplay();
    constexpr PromotionParams kPromotionParams = {.toggleIdleTimer = false};
    demotePacesetterDisplay(kPromotionParams);

    std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
    {
@@ -178,7 +186,7 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId, PhysicalDisplayId
        // headless virtual display.)
        LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!");

        pacesetterVsyncSchedule = promotePacesetterDisplayLocked(activeDisplayId);
        pacesetterVsyncSchedule = promotePacesetterDisplayLocked(activeDisplayId, kPromotionParams);
    }
    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}
@@ -917,19 +925,18 @@ bool Scheduler::updateFrameRateOverridesLocked(GlobalSignals consideredSignals,
    return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides);
}

void Scheduler::promotePacesetterDisplay(PhysicalDisplayId pacesetterId) {
void Scheduler::promotePacesetterDisplay(PhysicalDisplayId pacesetterId, PromotionParams params) {
    std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;

    {
        std::scoped_lock lock(mDisplayLock);
        pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterId);
        pacesetterVsyncSchedule = promotePacesetterDisplayLocked(pacesetterId, params);
    }

    applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}

std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked(
        PhysicalDisplayId pacesetterId) {
        PhysicalDisplayId pacesetterId, PromotionParams params) {
    // TODO: b/241286431 - Choose the pacesetter among mDisplays.
    mPacesetterDisplayId = pacesetterId;
    ALOGI("Display %s is the pacesetter", to_string(pacesetterId).c_str());
@@ -938,15 +945,18 @@ std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked(
    if (const auto pacesetterOpt = pacesetterDisplayLocked()) {
        const Display& pacesetter = *pacesetterOpt;

        if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
            pacesetter.selectorPtr->setIdleTimerCallbacks(
                    {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
                                  .onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
                     .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); },
                            .onExpired = [this] { kernelIdleTimerCallback(TimerState::Expired); }},
                                .onExpired =
                                        [this] { kernelIdleTimerCallback(TimerState::Expired); }},
                     .vrr = {.onReset = [this] { mSchedulerCallback.vrrDisplayIdle(false); },
                             .onExpired = [this] { mSchedulerCallback.vrrDisplayIdle(true); }}});

            pacesetter.selectorPtr->startIdleTimer();
        }

        newVsyncSchedulePtr = pacesetter.schedulePtr;

@@ -966,12 +976,15 @@ void Scheduler::applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedu
    }
}

void Scheduler::demotePacesetterDisplay() {
void Scheduler::demotePacesetterDisplay(PromotionParams params) {
    if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
        // No need to lock for reads on kMainThreadContext.
    if (const auto pacesetterPtr = FTL_FAKE_GUARD(mDisplayLock, pacesetterSelectorPtrLocked())) {
        if (const auto pacesetterPtr =
                    FTL_FAKE_GUARD(mDisplayLock, pacesetterSelectorPtrLocked())) {
            pacesetterPtr->stopIdleTimer();
            pacesetterPtr->clearIdleTimerCallbacks();
        }
    }

    // Clear state that depends on the pacesetter's RefreshRateSelector.
    std::scoped_lock lock(mPolicyLock);
+18 −6
Original line number Diff line number Diff line
@@ -377,8 +377,17 @@ private:
    void resyncAllToHardwareVsync(bool allowToEnable) EXCLUDES(mDisplayLock);
    void setVsyncConfig(const VsyncConfig&, Period vsyncPeriod);

    void promotePacesetterDisplay(PhysicalDisplayId pacesetterId) REQUIRES(kMainThreadContext)
            EXCLUDES(mDisplayLock);
    // TODO: b/241286431 - Remove this option, which assumes that the pacesetter does not change
    // when a (secondary) display is registered or unregistered. In the short term, this avoids
    // a deadlock where the main thread joins with the timer thread as the timer thread waits to
    // lock a mutex held by the main thread.
    struct PromotionParams {
        // Whether to stop and start the idle timer. Ignored unless connected_display flag is set.
        bool toggleIdleTimer;
    };

    void promotePacesetterDisplay(PhysicalDisplayId pacesetterId, PromotionParams)
            REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);

    // Changes to the displays (e.g. registering and unregistering) must be made
    // while mDisplayLock is locked, and the new pacesetter then must be promoted while
@@ -386,13 +395,16 @@ private:
    // MessageQueue and EventThread need to use the new pacesetter's
    // VsyncSchedule, and this must happen while mDisplayLock is *not* locked,
    // or else we may deadlock with EventThread.
    std::shared_ptr<VsyncSchedule> promotePacesetterDisplayLocked(PhysicalDisplayId pacesetterId)
    std::shared_ptr<VsyncSchedule> promotePacesetterDisplayLocked(PhysicalDisplayId pacesetterId,
                                                                  PromotionParams)
            REQUIRES(kMainThreadContext, mDisplayLock);
    void applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule>) EXCLUDES(mDisplayLock);

    // Blocks until the pacesetter's idle timer thread exits. `mDisplayLock` must not be locked by
    // the caller on the main thread to avoid deadlock, since the timer thread locks it before exit.
    void demotePacesetterDisplay() REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock, mPolicyLock);
    // If toggleIdleTimer is true, the calling thread blocks until the pacesetter's idle timer
    // thread exits, in which case mDisplayLock must not be locked by the caller to avoid deadlock,
    // since the timer thread locks it before exit.
    void demotePacesetterDisplay(PromotionParams) REQUIRES(kMainThreadContext)
            EXCLUDES(mDisplayLock, mPolicyLock);

    void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr, VsyncSchedulePtr,
                                 PhysicalDisplayId activeDisplayId) REQUIRES(kMainThreadContext)