Merge "SF: throttle WindowInfosListener calls" into tm-qpr-dev
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 494aa2c..5db7999 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3257,8 +3257,11 @@
                                                       inputFlinger = mInputFlinger, this]() {
         ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
         if (updateWindowInfo) {
-            mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
-                                                            inputWindowCommands.syncInputWindows);
+            mWindowInfosListenerInvoker
+                    ->windowInfosChanged(std::move(windowInfos), std::move(displayInfos),
+                                         /* shouldSync= */ inputWindowCommands.syncInputWindows,
+                                         /* forceImmediateCall= */
+                                         !inputWindowCommands.focusRequests.empty());
         } else if (inputWindowCommands.syncInputWindows) {
             // If the caller requested to sync input windows, but there are no
             // changes to input windows, notify immediately.
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 30b9d8f..023402f 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -28,19 +28,26 @@
 
 struct WindowInfosListenerInvoker::WindowInfosReportedListener
       : gui::BnWindowInfosReportedListener {
-    explicit WindowInfosReportedListener(WindowInfosListenerInvoker& invoker) : mInvoker(invoker) {}
+    explicit WindowInfosReportedListener(WindowInfosListenerInvoker& invoker, size_t callbackCount,
+                                         bool shouldSync)
+          : mInvoker(invoker), mCallbacksPending(callbackCount), mShouldSync(shouldSync) {}
 
     binder::Status onWindowInfosReported() override {
-        mInvoker.windowInfosReported();
+        mCallbacksPending--;
+        if (mCallbacksPending == 0) {
+            mInvoker.windowInfosReported(mShouldSync);
+        }
         return binder::Status::ok();
     }
 
+private:
     WindowInfosListenerInvoker& mInvoker;
+    std::atomic<size_t> mCallbacksPending;
+    bool mShouldSync;
 };
 
 WindowInfosListenerInvoker::WindowInfosListenerInvoker(SurfaceFlinger& flinger)
-      : mFlinger(flinger),
-        mWindowInfosReportedListener(sp<WindowInfosReportedListener>::make(*this)) {}
+      : mFlinger(flinger) {}
 
 void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
     sp<IBinder> asBinder = IInterface::asBinder(listener);
@@ -64,30 +71,76 @@
     mWindowInfosListeners.erase(who);
 }
 
-void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
-                                                    const std::vector<DisplayInfo>& displayInfos,
-                                                    bool shouldSync) {
-    ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
-    {
-        std::scoped_lock lock(mListenersMutex);
-        for (const auto& [_, listener] : mWindowInfosListeners) {
-            windowInfosListeners.push_back(listener);
+void WindowInfosListenerInvoker::windowInfosChanged(std::vector<WindowInfo> windowInfos,
+                                                    std::vector<DisplayInfo> displayInfos,
+                                                    bool shouldSync, bool forceImmediateCall) {
+    auto callListeners = [this, windowInfos = std::move(windowInfos),
+                          displayInfos = std::move(displayInfos)](bool shouldSync) mutable {
+        ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
+        {
+            std::scoped_lock lock(mListenersMutex);
+            for (const auto& [_, listener] : mWindowInfosListeners) {
+                windowInfosListeners.push_back(listener);
+            }
         }
-    }
 
-    mCallbacksPending = windowInfosListeners.size();
+        auto reportedListener =
+                sp<WindowInfosReportedListener>::make(*this, windowInfosListeners.size(),
+                                                      shouldSync);
 
-    for (const auto& listener : windowInfosListeners) {
-        listener->onWindowInfosChanged(windowInfos, displayInfos,
-                                       shouldSync ? mWindowInfosReportedListener : nullptr);
+        for (const auto& listener : windowInfosListeners) {
+            auto status =
+                    listener->onWindowInfosChanged(windowInfos, displayInfos, reportedListener);
+            if (!status.isOk()) {
+                reportedListener->onWindowInfosReported();
+            }
+        }
+    };
+
+    {
+        std::scoped_lock lock(mMessagesMutex);
+        // If there are unacked messages and this isn't a forced call, then return immediately.
+        // If a forced window infos change doesn't happen first, the update will be sent after
+        // the WindowInfosReportedListeners are called. If a forced window infos change happens or
+        // if there are subsequent delayed messages before this update is sent, then this message
+        // will be dropped and the listeners will only be called with the latest info. This is done
+        // to reduce the amount of binder memory used.
+        if (mActiveMessageCount > 0 && !forceImmediateCall) {
+            mWindowInfosChangedDelayed = std::move(callListeners);
+            mShouldSyncDelayed |= shouldSync;
+            return;
+        }
+
+        mWindowInfosChangedDelayed = nullptr;
+        shouldSync |= mShouldSyncDelayed;
+        mShouldSyncDelayed = false;
+        mActiveMessageCount++;
     }
+    callListeners(shouldSync);
 }
 
-void WindowInfosListenerInvoker::windowInfosReported() {
-    mCallbacksPending--;
-    if (mCallbacksPending == 0) {
+void WindowInfosListenerInvoker::windowInfosReported(bool shouldSync) {
+    if (shouldSync) {
         mFlinger.windowInfosReported();
     }
+
+    std::function<void(bool)> callListeners;
+    bool shouldSyncDelayed;
+    {
+        std::scoped_lock lock{mMessagesMutex};
+        mActiveMessageCount--;
+        if (!mWindowInfosChangedDelayed || mActiveMessageCount > 0) {
+            return;
+        }
+
+        mActiveMessageCount++;
+        callListeners = std::move(mWindowInfosChangedDelayed);
+        mWindowInfosChangedDelayed = nullptr;
+        shouldSyncDelayed = mShouldSyncDelayed;
+        mShouldSyncDelayed = false;
+    }
+
+    callListeners(shouldSyncDelayed);
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index d8d8d0f..701f11e 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -34,15 +34,15 @@
     void addWindowInfosListener(sp<gui::IWindowInfosListener>);
     void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
 
-    void windowInfosChanged(const std::vector<gui::WindowInfo>&,
-                            const std::vector<gui::DisplayInfo>&, bool shouldSync);
+    void windowInfosChanged(std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>,
+                            bool shouldSync, bool forceImmediateCall);
 
 protected:
     void binderDied(const wp<IBinder>& who) override;
 
 private:
     struct WindowInfosReportedListener;
-    void windowInfosReported();
+    void windowInfosReported(bool shouldSync);
 
     SurfaceFlinger& mFlinger;
     std::mutex mListenersMutex;
@@ -51,8 +51,10 @@
     ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity>
             mWindowInfosListeners GUARDED_BY(mListenersMutex);
 
-    sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener;
-    std::atomic<size_t> mCallbacksPending{0};
+    std::mutex mMessagesMutex;
+    uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0;
+    std::function<void(bool)> mWindowInfosChangedDelayed GUARDED_BY(mMessagesMutex);
+    bool mShouldSyncDelayed;
 };
 
 } // namespace android