diff options
| -rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.cpp | 65 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.h | 24 |
2 files changed, 57 insertions, 32 deletions
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 0dffa4bd3b..0cf7bdcc4e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -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; - 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); }}, - .vrr = {.onReset = [this] { mSchedulerCallback.vrrDisplayIdle(false); }, - .onExpired = [this] { mSchedulerCallback.vrrDisplayIdle(true); }}}); - - pacesetter.selectorPtr->startIdleTimer(); + 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); }}, + .vrr = {.onReset = [this] { mSchedulerCallback.vrrDisplayIdle(false); }, + .onExpired = [this] { mSchedulerCallback.vrrDisplayIdle(true); }}}); + + pacesetter.selectorPtr->startIdleTimer(); + } newVsyncSchedulePtr = pacesetter.schedulePtr; @@ -966,11 +976,14 @@ void Scheduler::applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedu } } -void Scheduler::demotePacesetterDisplay() { - // No need to lock for reads on kMainThreadContext. - if (const auto pacesetterPtr = FTL_FAKE_GUARD(mDisplayLock, pacesetterSelectorPtrLocked())) { - pacesetterPtr->stopIdleTimer(); - pacesetterPtr->clearIdleTimerCallbacks(); +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())) { + pacesetterPtr->stopIdleTimer(); + pacesetterPtr->clearIdleTimerCallbacks(); + } } // Clear state that depends on the pacesetter's RefreshRateSelector. diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 4dba6fcfb1..94583db5a8 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -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) |