SF: Simplify Scheduler's hardware VSYNC delegate

As a step toward hiding implementation details of how Scheduler handles
changes in a display's power mode (e.g. toggling of hardware/synthetic
VSYNC), move and rename SurfaceFlinger::setVsyncEnabled to Scheduler::
onHardwareVsyncRequest. This hides setPendingHardwareVsyncState.

(getPendingHardwareVsyncState will be moved to Scheduler later.)

Store the per-display hal::PowerMode in Scheduler. On power mode change
in SurfaceFlinger::setPowerModeInternal, update the Scheduler for every
display, not just the active display.

Inject the delegate into VsyncSchedule's constructor, instead of passing
the (partly unrelated) ISchedulerCallback to several member functions.

Bug: 271431077
Bug: 241286146
Bug: 255635821
Bug: 241285191
Test: FoldableTest
Change-Id: I157b0895a77f055763f86dd21602d0dac13622da
diff --git a/services/surfaceflinger/Scheduler/ISchedulerCallback.h b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
index 92c2189..badbf53 100644
--- a/services/surfaceflinger/Scheduler/ISchedulerCallback.h
+++ b/services/surfaceflinger/Scheduler/ISchedulerCallback.h
@@ -25,7 +25,7 @@
 namespace android::scheduler {
 
 struct ISchedulerCallback {
-    virtual void setVsyncEnabled(PhysicalDisplayId, bool) = 0;
+    virtual void requestHardwareVsync(PhysicalDisplayId, bool enabled) = 0;
     virtual void requestDisplayModes(std::vector<display::DisplayModeRequest>) = 0;
     virtual void kernelTimerChanged(bool expired) = 0;
     virtual void triggerOnFrameRateOverridesChanged() = 0;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 8e1ac36..41639b6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -114,8 +114,12 @@
 }
 
 void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
-    registerDisplayInternal(displayId, std::move(selectorPtr),
-                            std::make_shared<VsyncSchedule>(displayId, mFeatures));
+    auto schedulePtr = std::make_shared<VsyncSchedule>(displayId, mFeatures,
+                                                       [this](PhysicalDisplayId id, bool enable) {
+                                                           onHardwareVsyncRequest(id, enable);
+                                                       });
+
+    registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr));
 }
 
 void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
@@ -137,7 +141,7 @@
 
     // Disable hardware VSYNC if the registration is new, as opposed to a renewal.
     if (isNew) {
-        mSchedulerCallback.setVsyncEnabled(displayId, false);
+        onHardwareVsyncRequest(displayId, false);
     }
 }
 
@@ -422,13 +426,13 @@
 void Scheduler::enableHardwareVsync(PhysicalDisplayId id) {
     auto schedule = getVsyncSchedule(id);
     LOG_ALWAYS_FATAL_IF(!schedule);
-    schedule->enableHardwareVsync(mSchedulerCallback);
+    schedule->enableHardwareVsync();
 }
 
 void Scheduler::disableHardwareVsync(PhysicalDisplayId id, bool disallow) {
     auto schedule = getVsyncSchedule(id);
     LOG_ALWAYS_FATAL_IF(!schedule);
-    schedule->disableHardwareVsync(mSchedulerCallback, disallow);
+    schedule->disableHardwareVsync(disallow);
 }
 
 void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) {
@@ -455,12 +459,32 @@
             refreshRate = display.selectorPtr->getActiveMode().modePtr->getFps();
         }
         if (refreshRate->isValid()) {
-            display.schedulePtr->startPeriodTransition(mSchedulerCallback, refreshRate->getPeriod(),
-                                                       false /* force */);
+            constexpr bool kForce = false;
+            display.schedulePtr->startPeriodTransition(refreshRate->getPeriod(), kForce);
         }
     }
 }
 
+void Scheduler::onHardwareVsyncRequest(PhysicalDisplayId id, bool enabled) {
+    static const auto& whence = __func__;
+    ATRACE_NAME(ftl::Concat(whence, ' ', id.value, ' ', enabled).c_str());
+
+    // On main thread to serialize reads/writes of pending hardware VSYNC state.
+    static_cast<void>(
+            schedule([=]() FTL_FAKE_GUARD(mDisplayLock) FTL_FAKE_GUARD(kMainThreadContext) {
+                ATRACE_NAME(ftl::Concat(whence, ' ', id.value, ' ', enabled).c_str());
+
+                if (const auto displayOpt = mDisplays.get(id)) {
+                    auto& display = displayOpt->get();
+                    display.schedulePtr->setPendingHardwareVsyncState(enabled);
+
+                    if (display.powerMode != hal::PowerMode::OFF) {
+                        mSchedulerCallback.requestHardwareVsync(id, enabled);
+                    }
+                }
+            }));
+}
+
 void Scheduler::setRenderRate(PhysicalDisplayId id, Fps renderFrameRate) {
     std::scoped_lock lock(mDisplayLock);
     ftl::FakeGuard guard(kMainThreadContext);
@@ -506,18 +530,17 @@
         ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
         return false;
     }
-    return schedule->addResyncSample(mSchedulerCallback, TimePoint::fromNs(timestamp),
-                                     hwcVsyncPeriod);
+    return schedule->addResyncSample(TimePoint::fromNs(timestamp), hwcVsyncPeriod);
 }
 
 void Scheduler::addPresentFence(PhysicalDisplayId id, std::shared_ptr<FenceTime> fence) {
     auto schedule = getVsyncSchedule(id);
     LOG_ALWAYS_FATAL_IF(!schedule);
-    const bool needMoreSignals = schedule->getController().addPresentFence(std::move(fence));
-    if (needMoreSignals) {
-        schedule->enableHardwareVsync(mSchedulerCallback);
+    if (const bool needMoreSignals = schedule->getController().addPresentFence(std::move(fence))) {
+        schedule->enableHardwareVsync();
     } else {
-        schedule->disableHardwareVsync(mSchedulerCallback, false /* disallow */);
+        constexpr bool kDisallow = false;
+        schedule->disableHardwareVsync(kDisallow);
     }
 }
 
@@ -581,9 +604,13 @@
     }
     {
         std::scoped_lock lock(mDisplayLock);
-        auto vsyncSchedule = getVsyncScheduleLocked(id);
-        LOG_ALWAYS_FATAL_IF(!vsyncSchedule);
-        vsyncSchedule->getController().setDisplayPowerMode(powerMode);
+
+        const auto displayOpt = mDisplays.get(id);
+        LOG_ALWAYS_FATAL_IF(!displayOpt);
+        auto& display = displayOpt->get();
+
+        display.powerMode = powerMode;
+        display.schedulePtr->getController().setDisplayPowerMode(powerMode);
     }
     if (!isPacesetter) return;
 
@@ -641,7 +668,7 @@
         ftl::FakeGuard guard(kMainThreadContext);
         for (const auto& [_, display] : mDisplays) {
             constexpr bool kDisallow = false;
-            display.schedulePtr->disableHardwareVsync(mSchedulerCallback, kDisallow);
+            display.schedulePtr->disableHardwareVsync(kDisallow);
         }
     }
 
@@ -762,8 +789,8 @@
         newVsyncSchedulePtr = pacesetter.schedulePtr;
 
         const Fps refreshRate = pacesetter.selectorPtr->getActiveMode().modePtr->getFps();
-        newVsyncSchedulePtr->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod(),
-                                                   true /* force */);
+        constexpr bool kForce = true;
+        newVsyncSchedulePtr->startPeriodTransition(refreshRate.getPeriod(), kForce);
     }
     return newVsyncSchedulePtr;
 }
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index d628ac3..17e9cea 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -320,6 +320,9 @@
     void touchTimerCallback(TimerState);
     void displayPowerTimerCallback(TimerState);
 
+    // VsyncSchedule delegate.
+    void onHardwareVsyncRequest(PhysicalDisplayId, bool enable);
+
     void resyncToHardwareVsyncLocked(PhysicalDisplayId, bool allowToEnable,
                                      std::optional<Fps> refreshRate = std::nullopt)
             REQUIRES(kMainThreadContext, mDisplayLock);
@@ -433,6 +436,8 @@
         // Effectively const except in move constructor.
         RefreshRateSelectorPtr selectorPtr;
         VsyncSchedulePtr schedulePtr;
+
+        hal::PowerMode powerMode = hal::PowerMode::OFF;
     };
 
     using DisplayRef = std::reference_wrapper<Display>;
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
index 84671ae..ff3f29d 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
@@ -22,7 +22,6 @@
 
 #include "VsyncSchedule.h"
 
-#include "ISchedulerCallback.h"
 #include "Utils/Dumper.h"
 #include "VSyncDispatchTimerQueue.h"
 #include "VSyncPredictor.h"
@@ -54,8 +53,10 @@
     VSyncCallbackRegistration mRegistration;
 };
 
-VsyncSchedule::VsyncSchedule(PhysicalDisplayId id, FeatureFlags features)
+VsyncSchedule::VsyncSchedule(PhysicalDisplayId id, FeatureFlags features,
+                             RequestHardwareVsync requestHardwareVsync)
       : mId(id),
+        mRequestHardwareVsync(std::move(requestHardwareVsync)),
         mTracker(createTracker(id)),
         mDispatch(createDispatch(mTracker)),
         mController(createController(id, *mTracker, features)),
@@ -64,8 +65,9 @@
                         : nullptr) {}
 
 VsyncSchedule::VsyncSchedule(PhysicalDisplayId id, TrackerPtr tracker, DispatchPtr dispatch,
-                             ControllerPtr controller)
+                             ControllerPtr controller, RequestHardwareVsync requestHardwareVsync)
       : mId(id),
+        mRequestHardwareVsync(std::move(requestHardwareVsync)),
         mTracker(std::move(tracker)),
         mDispatch(std::move(dispatch)),
         mController(std::move(controller)) {}
@@ -135,14 +137,13 @@
     return reactor;
 }
 
-void VsyncSchedule::startPeriodTransition(ISchedulerCallback& callback, Period period, bool force) {
+void VsyncSchedule::startPeriodTransition(Period period, bool force) {
     std::lock_guard<std::mutex> lock(mHwVsyncLock);
     mController->startPeriodTransition(period.ns(), force);
-    enableHardwareVsyncLocked(callback);
+    enableHardwareVsyncLocked();
 }
 
-bool VsyncSchedule::addResyncSample(ISchedulerCallback& callback, TimePoint timestamp,
-                                    ftl::Optional<Period> hwcVsyncPeriod) {
+bool VsyncSchedule::addResyncSample(TimePoint timestamp, ftl::Optional<Period> hwcVsyncPeriod) {
     bool needsHwVsync = false;
     bool periodFlushed = false;
     {
@@ -154,31 +155,32 @@
         }
     }
     if (needsHwVsync) {
-        enableHardwareVsync(callback);
+        enableHardwareVsync();
     } else {
-        disableHardwareVsync(callback, false /* disallow */);
+        constexpr bool kDisallow = false;
+        disableHardwareVsync(kDisallow);
     }
     return periodFlushed;
 }
 
-void VsyncSchedule::enableHardwareVsync(ISchedulerCallback& callback) {
+void VsyncSchedule::enableHardwareVsync() {
     std::lock_guard<std::mutex> lock(mHwVsyncLock);
-    enableHardwareVsyncLocked(callback);
+    enableHardwareVsyncLocked();
 }
 
-void VsyncSchedule::enableHardwareVsyncLocked(ISchedulerCallback& callback) {
+void VsyncSchedule::enableHardwareVsyncLocked() {
     if (mHwVsyncState == HwVsyncState::Disabled) {
         getTracker().resetModel();
-        callback.setVsyncEnabled(mId, true);
+        mRequestHardwareVsync(mId, true);
         mHwVsyncState = HwVsyncState::Enabled;
     }
 }
 
-void VsyncSchedule::disableHardwareVsync(ISchedulerCallback& callback, bool disallow) {
+void VsyncSchedule::disableHardwareVsync(bool disallow) {
     std::lock_guard<std::mutex> lock(mHwVsyncLock);
     switch (mHwVsyncState) {
         case HwVsyncState::Enabled:
-            callback.setVsyncEnabled(mId, false);
+            mRequestHardwareVsync(mId, false);
             [[fallthrough]];
         case HwVsyncState::Disabled:
             mHwVsyncState = disallow ? HwVsyncState::Disallowed : HwVsyncState::Disabled;
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h
index 9867b41..0757b57 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.h
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <functional>
 #include <memory>
 #include <string>
 
@@ -41,8 +42,6 @@
 
 namespace android::scheduler {
 
-struct ISchedulerCallback;
-
 // TODO(b/185535769): Rename classes, and remove aliases.
 class VSyncDispatch;
 class VSyncTracker;
@@ -54,7 +53,9 @@
 // Schedule that synchronizes to hardware VSYNC of a physical display.
 class VsyncSchedule final : public IVsyncSource {
 public:
-    VsyncSchedule(PhysicalDisplayId, FeatureFlags);
+    using RequestHardwareVsync = std::function<void(PhysicalDisplayId, bool enabled)>;
+
+    VsyncSchedule(PhysicalDisplayId, FeatureFlags, RequestHardwareVsync);
     ~VsyncSchedule();
 
     // IVsyncSource overrides:
@@ -68,13 +69,12 @@
     // \param [in] period   The period that the system is changing into.
     // \param [in] force    True to force a transition even if it is not a
     //                      change.
-    void startPeriodTransition(ISchedulerCallback&, Period period, bool force);
+    void startPeriodTransition(Period period, bool force);
 
     // Pass a VSYNC sample to VsyncController. Return true if
     // VsyncController detected that the VSYNC period changed. Enable or disable
     // hardware VSYNCs depending on whether more samples are needed.
-    bool addResyncSample(ISchedulerCallback&, TimePoint timestamp,
-                         ftl::Optional<Period> hwcVsyncPeriod);
+    bool addResyncSample(TimePoint timestamp, ftl::Optional<Period> hwcVsyncPeriod);
 
     // TODO(b/185535769): Hide behind API.
     const VsyncTracker& getTracker() const { return *mTracker; }
@@ -93,12 +93,12 @@
 
     // Turn on hardware VSYNCs, unless mHwVsyncState is Disallowed, in which
     // case this call is ignored.
-    void enableHardwareVsync(ISchedulerCallback&) EXCLUDES(mHwVsyncLock);
+    void enableHardwareVsync() EXCLUDES(mHwVsyncLock);
 
     // Disable hardware VSYNCs. If `disallow` is true, future calls to
     // enableHardwareVsync are ineffective until isHardwareVsyncAllowed is
     // called with `makeAllowed` set to true.
-    void disableHardwareVsync(ISchedulerCallback&, bool disallow) EXCLUDES(mHwVsyncLock);
+    void disableHardwareVsync(bool disallow) EXCLUDES(mHwVsyncLock);
 
     // If true, enableHardwareVsync can enable hardware VSYNC (if not already
     // enabled). If false, enableHardwareVsync does nothing.
@@ -111,8 +111,11 @@
 protected:
     using ControllerPtr = std::unique_ptr<VsyncController>;
 
+    static void NoOpRequestHardwareVsync(PhysicalDisplayId, bool) {}
+
     // For tests.
-    VsyncSchedule(PhysicalDisplayId, TrackerPtr, DispatchPtr, ControllerPtr);
+    VsyncSchedule(PhysicalDisplayId, TrackerPtr, DispatchPtr, ControllerPtr,
+                  RequestHardwareVsync = NoOpRequestHardwareVsync);
 
 private:
     friend class TestableScheduler;
@@ -124,7 +127,7 @@
     static DispatchPtr createDispatch(TrackerPtr);
     static ControllerPtr createController(PhysicalDisplayId, VsyncTracker&, FeatureFlags);
 
-    void enableHardwareVsyncLocked(ISchedulerCallback&) REQUIRES(mHwVsyncLock);
+    void enableHardwareVsyncLocked() REQUIRES(mHwVsyncLock);
 
     mutable std::mutex mHwVsyncLock;
     enum class HwVsyncState {
@@ -151,6 +154,7 @@
     using TracerPtr = std::unique_ptr<PredictedVsyncTracer>;
 
     const PhysicalDisplayId mId;
+    const RequestHardwareVsync mRequestHardwareVsync;
     const TrackerPtr mTracker;
     const DispatchPtr mDispatch;
     const ControllerPtr mController;