SF: Adding callback to Scheduler for setting refresh rate to 60 and 90.

When device is idle, refresh rate is set to 60. When not it's set to 90.

See go/surface-flinger-scheduler for more info.

Test: All SF tests pass.
Bug: 113612090
Bug: 122347908
Change-Id: Ica6e483118db276f72d3cb4e79535303c76f99d7
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 1683982..bf925b2 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -67,7 +67,13 @@
 }
 
 void EventThreadConnection::requestNextVsync() {
-    mEventThread->requestNextVsync(this);
+    ATRACE_NAME("requestNextVsync");
+    mEventThread->requestNextVsync(this, true);
+}
+
+void EventThreadConnection::requestNextVsyncForHWC() {
+    ATRACE_NAME("requestNextVsyncForHWC");
+    mEventThread->requestNextVsync(this, false);
 }
 
 status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
@@ -184,16 +190,17 @@
     }
 }
 
-void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (mResetIdleTimer) {
+void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
+    if (mResetIdleTimer && reset) {
+        ATRACE_NAME("resetIdleTimer");
         mResetIdleTimer();
     }
-
     if (mResyncWithRateLimitCallback) {
         mResyncWithRateLimitCallback();
     }
 
+    std::lock_guard<std::mutex> lock(mMutex);
+
     if (connection->count < 0) {
         connection->count = 0;
         mCondition.notify_all();
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 66f54bd..e110488 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -68,6 +68,9 @@
     status_t stealReceiveChannel(gui::BitTube* outChannel) override;
     status_t setVsyncRate(uint32_t count) override;
     void requestNextVsync() override; // asynchronous
+    // Requesting Vsync for HWC does not reset the idle timer, since HWC requires a refresh
+    // in order to update the configs.
+    void requestNextVsyncForHWC();
 
     // count >= 1 : continuous event. count is the vsync rate
     // count == 0 : one-shot event that has not fired
@@ -105,7 +108,9 @@
     virtual status_t registerDisplayEventConnection(
             const sp<EventThreadConnection>& connection) = 0;
     virtual void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) = 0;
-    virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+    // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
+    virtual void requestNextVsync(const sp<EventThreadConnection>& connection,
+                                  bool resetIdleTimer) = 0;
 };
 
 namespace impl {
@@ -129,7 +134,8 @@
 
     status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
     void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) override;
-    void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+    void requestNextVsync(const sp<EventThreadConnection>& connection,
+                          bool resetIdleTimer) override;
 
     // called before the screen is turned off from main thread
     void onScreenReleased() override;
@@ -166,6 +172,9 @@
     // Implements VSyncSource::Callback
     void onVSyncEvent(nsecs_t timestamp) override;
 
+    // Acquires mutex and requests next vsync.
+    void requestNextVsyncInternal(const sp<EventThreadConnection>& connection) EXCLUDES(mMutex);
+
     // TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
     VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
     std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 36403cc..66f42bb 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -148,6 +148,10 @@
     mEvents->requestNextVsync();
 }
 
+void MessageQueue::invalidateForHWC() {
+    mEvents->requestNextVsyncForHWC();
+}
+
 void MessageQueue::refresh() {
     mHandler->dispatchRefresh();
 }
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 24a3834..0bf00b0 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -91,6 +91,7 @@
     virtual void waitMessage() = 0;
     virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
     virtual void invalidate() = 0;
+    virtual void invalidateForHWC() = 0;
     virtual void refresh() = 0;
 };
 
@@ -134,6 +135,9 @@
 
     // sends INVALIDATE message at next VSYNC
     void invalidate() override;
+
+    // sends INVALIDATE message at next VSYNC, without resetting the idle timer in the Scheduler
+    void invalidateForHWC();
     // sends REFRESH message at next VSYNC
     void refresh() override;
 };
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c363ba5..fec53af 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -238,6 +238,16 @@
     mLayerHistory.incrementCounter();
 }
 
+void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback) {
+    std::lock_guard<std::mutex> lock(mCallbackLock);
+    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) {
@@ -314,12 +324,12 @@
     // TODO(b/113612090): This are current numbers from trial and error while running videos
     // from YouTube at 24, 30, and 60 fps.
     if (mean > 14 && mean < 18) {
-        ATRACE_INT("FPS", 60);
+        ATRACE_INT("MediaFPS", 60);
     } else if (mean > 31 && mean < 34) {
-        ATRACE_INT("FPS", 30);
+        ATRACE_INT("MediaFPS", 30);
         return;
     } else if (mean > 39 && mean < 42) {
-        ATRACE_INT("FPS", 24);
+        ATRACE_INT("MediaFPS", 24);
     }
 }
 
@@ -328,13 +338,19 @@
         mIdleTimer->reset();
         ATRACE_INT("ExpiredIdleTimer", 0);
     }
+
+    std::lock_guard<std::mutex> lock(mCallbackLock);
+    if (mResetTimerCallback) {
+        mResetTimerCallback();
+    }
 }
 
 void Scheduler::expiredTimerCallback() {
-    // TODO(b/113612090): Each time a timer expired, we should record the information into
-    // a circular buffer. Once this has happened a given amount (TBD) of times, we can comfortably
-    // say that the device is sitting in idle.
-    ATRACE_INT("ExpiredIdleTimer", 1);
+    std::lock_guard<std::mutex> lock(mCallbackLock);
+    if (mExpiredTimerCallback) {
+        mExpiredTimerCallback();
+        ATRACE_INT("ExpiredIdleTimer", 1);
+    }
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9d7dd4d..3538f31 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -36,6 +36,9 @@
 
 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 };
 
@@ -111,6 +114,10 @@
                                      const std::string layerName);
     // Increments counter in the layer history to indicate that SF has started a new frame.
     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);
 
 protected:
     virtual std::unique_ptr<EventThread> makeEventThread(
@@ -173,6 +180,10 @@
     // interval, a callback is fired. Set this variable to >0 to use this feature.
     int64_t mSetIdleTimerMs = 0;
     std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
+
+    std::mutex mCallbackLock;
+    ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
+    ResetIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dc82b32..bd16d64 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -729,6 +729,11 @@
         ALOGE("Run StartPropertySetThread failed!");
     }
 
+    if (mUseScheduler) {
+        mScheduler->setExpiredIdleTimerCallback([this]() { setRefreshRateTo(60.f /* fps */); });
+        mScheduler->setResetIdleTimerCallback([this]() { setRefreshRateTo(90.f /* fps */); });
+    }
+
     ALOGV("Done initializing");
 }
 
@@ -934,14 +939,45 @@
     return display->getActiveConfig();
 }
 
-void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) {
+    ATRACE_NAME("setActiveConfigAsync");
+    postMessageAsync(new LambdaMessage([=] { setActiveConfigInternal(displayToken, mode); }));
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+    ATRACE_NAME("setActiveConfigSync");
+    postMessageSync(new LambdaMessage([&] { setActiveConfigInternal(displayToken, mode); }));
+    return NO_ERROR;
+}
+
+void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) {
+    Vector<DisplayInfo> configs;
+    getDisplayConfigs(displayToken, &configs);
+    if (mode < 0 || mode >= static_cast<int>(configs.size())) {
+        ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
+        return;
+    }
+
+    const auto display = getDisplayDevice(displayToken);
+    if (!display) {
+        ALOGE("Attempt to set active config %d for invalid display token %p", mode,
+              displayToken.get());
+        return;
+    }
     if (display->isVirtual()) {
-        ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+        ALOGW("Attempt to set active config %d for virtual display", mode);
+        return;
+    }
+    int currentDisplayPowerMode = display->getPowerMode();
+    if (currentDisplayPowerMode != HWC_POWER_MODE_NORMAL) {
+        // Don't change active config when in AoD.
         return;
     }
 
     int currentMode = display->getActiveConfig();
     if (mode == currentMode) {
+        // Don't update config if we are already running in the desired mode.
         return;
     }
 
@@ -950,29 +986,9 @@
 
     display->setActiveConfig(mode);
     getHwComposer().setActiveConfig(*displayId, mode);
-}
 
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
-    postMessageSync(new LambdaMessage([&] {
-        Vector<DisplayInfo> configs;
-        getDisplayConfigs(displayToken, &configs);
-        if (mode < 0 || mode >= static_cast<int>(configs.size())) {
-            ALOGE("Attempt to set active config %d for display with %zu configs", mode,
-                  configs.size());
-            return;
-        }
-        const auto display = getDisplayDevice(displayToken);
-        if (!display) {
-            ALOGE("Attempt to set active config %d for invalid display token %p", mode,
-                  displayToken.get());
-        } else if (display->isVirtual()) {
-            ALOGW("Attempt to set active config %d for virtual display", mode);
-        } else {
-            setActiveConfigInternal(display, mode);
-        }
-    }));
-
-    return NO_ERROR;
+    ATRACE_INT("ActiveConfigMode", mode);
+    resyncToHardwareVsync(true);
 }
 
 status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
@@ -1382,6 +1398,49 @@
     *compositorTiming = getBE().mCompositorTiming;
 }
 
+void SurfaceFlinger::setRefreshRateTo(float newFps) {
+    const auto displayId = getInternalDisplayId();
+    if (!displayId || mBootStage != BootStage::FINISHED) {
+        return;
+    }
+    // TODO(b/113612090): There should be a message queue flush here. Because this esentially
+    // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
+    // manner, once the setActiveConfig is synchronous, and is executed at a known time in a
+    // refresh cycle.
+
+    // Don't do any updating if the current fps is the same as the new one.
+    const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+    const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod();
+    if (currentVsyncPeriod == 0) {
+        return;
+    }
+    // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
+    // floating numbers.
+    const float currentFps = 1e9 / currentVsyncPeriod;
+    if (std::abs(currentFps - newFps) <= 1) {
+        return;
+    }
+
+    auto configs = getHwComposer().getConfigs(*displayId);
+    for (int i = 0; i < configs.size(); i++) {
+        const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
+        if (vsyncPeriod == 0) {
+            continue;
+        }
+        const float fps = 1e9 / vsyncPeriod;
+        // TODO(b/113612090): There should be a better way at determining which config
+        // has the right refresh rate.
+        if (std::abs(fps - newFps) <= 1) {
+            const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY);
+            if (!display) return;
+            // This is posted in async function to avoid deadlock when getDisplayDevice
+            // requires mStateLock.
+            setActiveConfigAsync(display, i);
+            ATRACE_INT("FPS", newFps);
+        }
+    }
+}
+
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                                        HWC2::Connection connection) {
     ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
@@ -1413,7 +1472,7 @@
     if (sequenceId != getBE().mComposerSequenceId) {
         return;
     }
-    repaintEverything();
+    repaintEverythingForHWC();
 }
 
 void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
@@ -5177,6 +5236,11 @@
     signalTransaction();
 }
 
+void SurfaceFlinger::repaintEverythingForHWC() {
+    mRepaintEverything = true;
+    mEventQueue->invalidateForHWC();
+}
+
 // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
 class WindowDisconnector {
 public:
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ac730ab..eb7127e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -311,6 +311,9 @@
     // force full composition on all displays
     void repaintEverything();
 
+    // force full composition on all displays without resetting the scheduler idle timer.
+    void repaintEverythingForHWC();
+
     surfaceflinger::Factory& getFactory() { return mFactory; }
 
     // The CompositionEngine encapsulates all composition related interfaces and actions.
@@ -502,8 +505,10 @@
 
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays();
+    // setActiveConfigInternal() posted on a main thread for async execution
+    status_t setActiveConfigAsync(const sp<IBinder>& displayToken, int mode);
     // called on the main thread in response to setActiveConfig()
-    void setActiveConfigInternal(const sp<DisplayDevice>& display, int mode);
+    void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode);
     // called on the main thread in response to setPowerMode()
     void setPowerModeInternal(const sp<DisplayDevice>& display, int mode);
 
@@ -763,6 +768,9 @@
     void resyncWithRateLimit();
     void getCompositorTiming(CompositorTiming* compositorTiming);
 private:
+    // Sets the refresh rate to newFps by switching active configs, if they are available for
+    // the desired refresh rate.
+    void setRefreshRateTo(float newFps);
 
     /* ------------------------------------------------------------------------
      * Debugging & dumpsys
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index acbed51..2d26bb3 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -200,7 +200,7 @@
 
 TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
     // Signal that we want the next vsync event to be posted to the connection
-    mThread->requestNextVsync(mConnection);
+    mThread->requestNextVsync(mConnection, false);
 
     // EventThread should immediately request a resync.
     EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index bb6e183..48d45fa 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -37,7 +37,7 @@
     MOCK_METHOD1(registerDisplayEventConnection,
                  status_t(const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
-    MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+    MOCK_METHOD2(requestNextVsync, void(const sp<android::EventThreadConnection> &, bool));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index dc8d606..8c113e2 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -35,6 +35,7 @@
     MOCK_METHOD0(waitMessage, void());
     MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
     MOCK_METHOD0(invalidate, void());
+    MOCK_METHOD0(invalidateForHWC, void());
     MOCK_METHOD0(refresh, void());
 };