Revert "Improve updateInputFlinger performance"

This reverts commit 82f3463d449eb13e28c5dbffeee16e10721c71d2.

Reason for revert: Broken Build 10741338 on git_udc-mainline-prod on mainline_modules_arm-userdebug 
Bug: 298282482

Change-Id: I9a8eaaff637017cd84caaa5c0d570e24f257ed81
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 3c8df2b..bf34987 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -73,7 +73,6 @@
         "android/gui/FocusRequest.aidl",
         "android/gui/InputApplicationInfo.aidl",
         "android/gui/IWindowInfosListener.aidl",
-        "android/gui/IWindowInfosPublisher.aidl",
         "android/gui/IWindowInfosReportedListener.aidl",
         "android/gui/WindowInfo.aidl",
         "android/gui/WindowInfosUpdate.aidl",
@@ -91,7 +90,6 @@
         "android/gui/FocusRequest.aidl",
         "android/gui/InputApplicationInfo.aidl",
         "android/gui/IWindowInfosListener.aidl",
-        "android/gui/IWindowInfosPublisher.aidl",
         "android/gui/IWindowInfosReportedListener.aidl",
         "android/gui/WindowInfosUpdate.aidl",
         "android/gui/WindowInfo.aidl",
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index 0929b8e..76e7b6e 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -22,6 +22,7 @@
 namespace android {
 
 using gui::DisplayInfo;
+using gui::IWindowInfosReportedListener;
 using gui::WindowInfo;
 using gui::WindowInfosListener;
 using gui::aidl_utils::statusTFromBinderStatus;
@@ -39,13 +40,8 @@
     {
         std::scoped_lock lock(mListenersMutex);
         if (mWindowInfosListeners.empty()) {
-            gui::WindowInfosListenerInfo listenerInfo;
-            binder::Status s = surfaceComposer->addWindowInfosListener(this, &listenerInfo);
+            binder::Status s = surfaceComposer->addWindowInfosListener(this);
             status = statusTFromBinderStatus(s);
-            if (status == OK) {
-                mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher);
-                mListenerId = listenerInfo.listenerId;
-            }
         }
 
         if (status == OK) {
@@ -89,7 +85,8 @@
 }
 
 binder::Status WindowInfosListenerReporter::onWindowInfosChanged(
-        const gui::WindowInfosUpdate& update) {
+        const gui::WindowInfosUpdate& update,
+        const sp<IWindowInfosReportedListener>& windowInfosReportedListener) {
     std::unordered_set<sp<WindowInfosListener>, gui::SpHash<WindowInfosListener>>
             windowInfosListeners;
 
@@ -107,7 +104,9 @@
         listener->onWindowInfosChanged(update);
     }
 
-    mWindowInfosPublisher->ackWindowInfosReceived(update.vsyncId, mListenerId);
+    if (windowInfosReportedListener) {
+        windowInfosReportedListener->onWindowInfosReported();
+    }
 
     return binder::Status::ok();
 }
@@ -115,10 +114,7 @@
 void WindowInfosListenerReporter::reconnect(const sp<gui::ISurfaceComposer>& composerService) {
     std::scoped_lock lock(mListenersMutex);
     if (!mWindowInfosListeners.empty()) {
-        gui::WindowInfosListenerInfo listenerInfo;
-        composerService->addWindowInfosListener(this, &listenerInfo);
-        mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher);
-        mListenerId = listenerInfo.listenerId;
+        composerService->addWindowInfosListener(this);
     }
 }
 
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 539a1c1..ec3266c 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -40,14 +40,12 @@
 import android.gui.ISurfaceComposerClient;
 import android.gui.ITunnelModeEnabledListener;
 import android.gui.IWindowInfosListener;
-import android.gui.IWindowInfosPublisher;
 import android.gui.LayerCaptureArgs;
 import android.gui.LayerDebugInfo;
 import android.gui.OverlayProperties;
 import android.gui.PullAtomData;
 import android.gui.ARect;
 import android.gui.StaticDisplayInfo;
-import android.gui.WindowInfosListenerInfo;
 
 /** @hide */
 interface ISurfaceComposer {
@@ -502,7 +500,7 @@
      */
     int getMaxAcquiredBufferCount();
 
-    WindowInfosListenerInfo addWindowInfosListener(IWindowInfosListener windowInfosListener);
+    void addWindowInfosListener(IWindowInfosListener windowInfosListener);
 
     void removeWindowInfosListener(IWindowInfosListener windowInfosListener);
 
diff --git a/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl b/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl
deleted file mode 100644
index 0ca13b7..0000000
--- a/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Copyright (c) 2023, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.gui;
-
-import android.gui.IWindowInfosPublisher;
-
-/** @hide */
-parcelable WindowInfosListenerInfo {
-    long listenerId;
-    IWindowInfosPublisher windowInfosPublisher;
-}
\ No newline at end of file
diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl
index 07cb5ed..400229d 100644
--- a/libs/gui/android/gui/IWindowInfosListener.aidl
+++ b/libs/gui/android/gui/IWindowInfosListener.aidl
@@ -16,9 +16,11 @@
 
 package android.gui;
 
+import android.gui.IWindowInfosReportedListener;
 import android.gui.WindowInfosUpdate;
 
 /** @hide */
 oneway interface IWindowInfosListener {
-    void onWindowInfosChanged(in WindowInfosUpdate update);
+    void onWindowInfosChanged(
+        in WindowInfosUpdate update, in @nullable IWindowInfosReportedListener windowInfosReportedListener);
 }
diff --git a/libs/gui/android/gui/IWindowInfosPublisher.aidl b/libs/gui/android/gui/IWindowInfosPublisher.aidl
deleted file mode 100644
index 5a9c328..0000000
--- a/libs/gui/android/gui/IWindowInfosPublisher.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Copyright (c) 2023, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.gui;
-
-/** @hide */
-oneway interface IWindowInfosPublisher
-{
-    void ackWindowInfosReceived(long vsyncId, long listenerId);
-}
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index 4c7d056..8c003d8 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -153,8 +153,8 @@
     MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override));
     MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override));
     MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override));
-    MOCK_METHOD(binder::Status, addWindowInfosListener,
-                (const sp<gui::IWindowInfosListener>&, gui::WindowInfosListenerInfo*), (override));
+    MOCK_METHOD(binder::Status, addWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
+                (override));
     MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
                 (override));
     MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override));
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 3ff6735..7c150d5 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -26,7 +26,6 @@
 #include <android/gui/IScreenCaptureListener.h>
 #include <android/gui/ITunnelModeEnabledListener.h>
 #include <android/gui/IWindowInfosListener.h>
-#include <android/gui/IWindowInfosPublisher.h>
 #include <binder/IBinder.h>
 #include <binder/IInterface.h>
 #include <gui/ITransactionCompletedListener.h>
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
index 684e21a..38cb108 100644
--- a/libs/gui/include/gui/WindowInfosListenerReporter.h
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -18,7 +18,7 @@
 
 #include <android/gui/BnWindowInfosListener.h>
 #include <android/gui/ISurfaceComposer.h>
-#include <android/gui/IWindowInfosPublisher.h>
+#include <android/gui/IWindowInfosReportedListener.h>
 #include <binder/IBinder.h>
 #include <gui/SpHash.h>
 #include <gui/WindowInfosListener.h>
@@ -30,7 +30,8 @@
 class WindowInfosListenerReporter : public gui::BnWindowInfosListener {
 public:
     static sp<WindowInfosListenerReporter> getInstance();
-    binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override;
+    binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update,
+                                        const sp<gui::IWindowInfosReportedListener>&) override;
     status_t addWindowInfosListener(
             const sp<gui::WindowInfosListener>& windowInfosListener,
             const sp<gui::ISurfaceComposer>&,
@@ -46,8 +47,5 @@
 
     std::vector<gui::WindowInfo> mLastWindowInfos GUARDED_BY(mListenersMutex);
     std::vector<gui::DisplayInfo> mLastDisplayInfos GUARDED_BY(mListenersMutex);
-
-    sp<gui::IWindowInfosPublisher> mWindowInfosPublisher;
-    int64_t mListenerId;
 };
 } // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8d7cf07..096a43c 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -998,8 +998,7 @@
     }
 
     binder::Status addWindowInfosListener(
-            const sp<gui::IWindowInfosListener>& /*windowInfosListener*/,
-            gui::WindowInfosListenerInfo* /*outInfo*/) override {
+            const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) override {
         return binder::Status::ok();
     }
 
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
index 5a1ec6f..6ddf790 100644
--- a/services/surfaceflinger/BackgroundExecutor.cpp
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -20,7 +20,6 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <utils/Log.h>
-#include <mutex>
 
 #include "BackgroundExecutor.h"
 
@@ -61,17 +60,4 @@
     LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
 }
 
-void BackgroundExecutor::flushQueue() {
-    std::mutex mutex;
-    std::condition_variable cv;
-    bool flushComplete = false;
-    sendCallbacks({[&]() {
-        std::scoped_lock lock{mutex};
-        flushComplete = true;
-        cv.notify_one();
-    }});
-    std::unique_lock<std::mutex> lock{mutex};
-    cv.wait(lock, [&]() { return flushComplete; });
-}
-
 } // namespace android
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
index 66b7d7a..0fae5a5 100644
--- a/services/surfaceflinger/BackgroundExecutor.h
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -34,7 +34,6 @@
     // Queues callbacks onto a work queue to be executed by a background thread.
     // This is safe to call from multiple threads.
     void sendCallbacks(Callbacks&& tasks);
-    void flushQueue();
 
 private:
     sem_t mSemaphore;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index db205b8..fe2db94 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -6158,7 +6158,8 @@
                   windowInfosDebug.maxSendDelayVsyncId.value);
     StringAppendF(&result, "  max send delay (ns): %" PRId64 " ns\n",
                   windowInfosDebug.maxSendDelayDuration);
-    StringAppendF(&result, "  unsent messages: %zu\n", windowInfosDebug.pendingMessageCount);
+    StringAppendF(&result, "  unsent messages: %" PRIu32 "\n",
+                  windowInfosDebug.pendingMessageCount);
     result.append("\n");
 }
 
@@ -7991,9 +7992,9 @@
                                    forceApplyPolicy);
 }
 
-status_t SurfaceFlinger::addWindowInfosListener(const sp<IWindowInfosListener>& windowInfosListener,
-                                                gui::WindowInfosListenerInfo* outInfo) {
-    mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener, outInfo);
+status_t SurfaceFlinger::addWindowInfosListener(
+        const sp<IWindowInfosListener>& windowInfosListener) {
+    mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener);
     setTransactionFlags(eInputInfoUpdateNeeded);
     return NO_ERROR;
 }
@@ -9075,8 +9076,7 @@
 }
 
 binder::Status SurfaceComposerAIDL::addWindowInfosListener(
-        const sp<gui::IWindowInfosListener>& windowInfosListener,
-        gui::WindowInfosListenerInfo* outInfo) {
+        const sp<gui::IWindowInfosListener>& windowInfosListener) {
     status_t status;
     const int pid = IPCThreadState::self()->getCallingPid();
     const int uid = IPCThreadState::self()->getCallingUid();
@@ -9084,7 +9084,7 @@
     // WindowInfosListeners
     if (uid == AID_SYSTEM || uid == AID_GRAPHICS ||
         checkPermission(sAccessSurfaceFlinger, pid, uid)) {
-        status = mFlinger->addWindowInfosListener(windowInfosListener, outInfo);
+        status = mFlinger->addWindowInfosListener(windowInfosListener);
     } else {
         status = PERMISSION_DENIED;
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index d4700a4..0bc506f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -612,8 +612,7 @@
 
     status_t getMaxAcquiredBufferCount(int* buffers) const;
 
-    status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener,
-                                    gui::WindowInfosListenerInfo* outResult);
+    status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
     status_t removeWindowInfosListener(
             const sp<gui::IWindowInfosListener>& windowInfosListener) const;
 
@@ -1557,8 +1556,8 @@
     binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override;
     binder::Status getGpuContextPriority(int32_t* outPriority) override;
     binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override;
-    binder::Status addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener,
-                                          gui::WindowInfosListenerInfo* outInfo) override;
+    binder::Status addWindowInfosListener(
+            const sp<gui::IWindowInfosListener>& windowInfosListener) override;
     binder::Status removeWindowInfosListener(
             const sp<gui::IWindowInfosListener>& windowInfosListener) override;
 
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 7062a4e..20699ef 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-#include <android/gui/BnWindowInfosPublisher.h>
-#include <android/gui/IWindowInfosPublisher.h>
-#include <android/gui/WindowInfosListenerInfo.h>
+#include <ftl/small_vector.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/TraceUtils.h>
 #include <gui/WindowInfosUpdate.h>
@@ -25,130 +23,162 @@
 #include "BackgroundExecutor.h"
 #include "WindowInfosListenerInvoker.h"
 
-#undef ATRACE_TAG
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
 namespace android {
 
 using gui::DisplayInfo;
 using gui::IWindowInfosListener;
 using gui::WindowInfo;
 
-void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener,
-                                                        gui::WindowInfosListenerInfo* outInfo) {
-    int64_t listenerId = mNextListenerId++;
-    outInfo->listenerId = listenerId;
-    outInfo->windowInfosPublisher = sp<gui::IWindowInfosPublisher>::fromExisting(this);
+using WindowInfosListenerVector = ftl::SmallVector<const sp<gui::IWindowInfosListener>, 3>;
 
-    BackgroundExecutor::getInstance().sendCallbacks(
-            {[this, listener = std::move(listener), listenerId]() {
-                ATRACE_NAME("WindowInfosListenerInvoker::addWindowInfosListener");
+struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener,
+                                            IBinder::DeathRecipient {
+    WindowInfosReportedListenerInvoker(WindowInfosListenerVector windowInfosListeners,
+                                       WindowInfosReportedListenerSet windowInfosReportedListeners)
+          : mCallbacksPending(windowInfosListeners.size()),
+            mWindowInfosListeners(std::move(windowInfosListeners)),
+            mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {}
+
+    binder::Status onWindowInfosReported() override {
+        if (--mCallbacksPending == 0) {
+            for (const auto& listener : mWindowInfosReportedListeners) {
                 sp<IBinder> asBinder = IInterface::asBinder(listener);
-                asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
-                mWindowInfosListeners.try_emplace(asBinder,
-                                                  std::make_pair(listenerId, std::move(listener)));
-            }});
+                if (asBinder->isBinderAlive()) {
+                    listener->onWindowInfosReported();
+                }
+            }
+
+            auto wpThis = wp<WindowInfosReportedListenerInvoker>::fromExisting(this);
+            for (const auto& listener : mWindowInfosListeners) {
+                sp<IBinder> binder = IInterface::asBinder(listener);
+                binder->unlinkToDeath(wpThis);
+            }
+        }
+        return binder::Status::ok();
+    }
+
+    void binderDied(const wp<IBinder>&) { onWindowInfosReported(); }
+
+private:
+    std::atomic<size_t> mCallbacksPending;
+    static constexpr size_t kStaticCapacity = 3;
+    const WindowInfosListenerVector mWindowInfosListeners;
+    WindowInfosReportedListenerSet mWindowInfosReportedListeners;
+};
+
+void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
+    sp<IBinder> asBinder = IInterface::asBinder(listener);
+    asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
+
+    std::scoped_lock lock(mListenersMutex);
+    mWindowInfosListeners.try_emplace(asBinder, std::move(listener));
 }
 
 void WindowInfosListenerInvoker::removeWindowInfosListener(
         const sp<IWindowInfosListener>& listener) {
-    BackgroundExecutor::getInstance().sendCallbacks({[this, listener]() {
-        ATRACE_NAME("WindowInfosListenerInvoker::removeWindowInfosListener");
-        sp<IBinder> asBinder = IInterface::asBinder(listener);
-        asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
-        mWindowInfosListeners.erase(asBinder);
-    }});
+    sp<IBinder> asBinder = IInterface::asBinder(listener);
+
+    std::scoped_lock lock(mListenersMutex);
+    asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
+    mWindowInfosListeners.erase(asBinder);
 }
 
 void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) {
-    BackgroundExecutor::getInstance().sendCallbacks({[this, who]() {
-        ATRACE_NAME("WindowInfosListenerInvoker::binderDied");
-        auto it = mWindowInfosListeners.find(who);
-        int64_t listenerId = it->second.first;
-        mWindowInfosListeners.erase(who);
-
-        std::vector<int64_t> vsyncIds;
-        for (auto& [vsyncId, state] : mUnackedState) {
-            if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(),
-                          listenerId) != state.unackedListenerIds.end()) {
-                vsyncIds.push_back(vsyncId);
-            }
-        }
-
-        for (int64_t vsyncId : vsyncIds) {
-            ackWindowInfosReceived(vsyncId, listenerId);
-        }
-    }});
+    std::scoped_lock lock(mListenersMutex);
+    mWindowInfosListeners.erase(who);
 }
 
 void WindowInfosListenerInvoker::windowInfosChanged(
         gui::WindowInfosUpdate update, WindowInfosReportedListenerSet reportedListeners,
         bool forceImmediateCall) {
-    if (!mDelayInfo) {
-        mDelayInfo = DelayInfo{
-                .vsyncId = update.vsyncId,
-                .frameTime = update.timestamp,
-        };
-    }
+    WindowInfosListenerVector listeners;
+    {
+        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 (!mUnackedState.empty() && !forceImmediateCall) {
-        mDelayedUpdate = std::move(update);
-        mReportedListeners.merge(reportedListeners);
-        return;
-    }
+        if (!mDelayInfo) {
+            mDelayInfo = DelayInfo{
+                    .vsyncId = update.vsyncId,
+                    .frameTime = update.timestamp,
+            };
+        }
 
-    if (mDelayedUpdate) {
-        mDelayedUpdate.reset();
-    }
+        // 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) {
+            mDelayedUpdate = std::move(update);
+            mReportedListeners.merge(reportedListeners);
+            return;
+        }
 
-    if (CC_UNLIKELY(mWindowInfosListeners.empty())) {
-        mReportedListeners.merge(reportedListeners);
+        if (mDelayedUpdate) {
+            mDelayedUpdate.reset();
+        }
+
+        {
+            std::scoped_lock lock{mListenersMutex};
+            for (const auto& [_, listener] : mWindowInfosListeners) {
+                listeners.push_back(listener);
+            }
+        }
+        if (CC_UNLIKELY(listeners.empty())) {
+            mReportedListeners.merge(reportedListeners);
+            mDelayInfo.reset();
+            return;
+        }
+
+        reportedListeners.insert(sp<WindowInfosListenerInvoker>::fromExisting(this));
+        reportedListeners.merge(mReportedListeners);
+        mReportedListeners.clear();
+
+        mActiveMessageCount++;
+        updateMaxSendDelay();
         mDelayInfo.reset();
-        return;
     }
 
-    reportedListeners.merge(mReportedListeners);
-    mReportedListeners.clear();
+    auto reportedInvoker =
+            sp<WindowInfosReportedListenerInvoker>::make(listeners, std::move(reportedListeners));
 
-    // Update mUnackedState to include the message we're about to send
-    auto [it, _] = mUnackedState.try_emplace(update.vsyncId,
-                                             UnackedState{.reportedListeners =
-                                                                  std::move(reportedListeners)});
-    auto& unackedState = it->second;
-    for (auto& pair : mWindowInfosListeners) {
-        int64_t listenerId = pair.second.first;
-        unackedState.unackedListenerIds.push_back(listenerId);
-    }
+    for (const auto& listener : listeners) {
+        sp<IBinder> asBinder = IInterface::asBinder(listener);
 
-    mDelayInfo.reset();
-    updateMaxSendDelay();
+        // linkToDeath is used here to ensure that the windowInfosReportedListeners
+        // are called even if one of the windowInfosListeners dies before
+        // calling onWindowInfosReported.
+        asBinder->linkToDeath(reportedInvoker);
 
-    // Call the listeners
-    for (auto& pair : mWindowInfosListeners) {
-        auto& [listenerId, listener] = pair.second;
-        auto status = listener->onWindowInfosChanged(update);
+        auto status = listener->onWindowInfosChanged(update, reportedInvoker);
         if (!status.isOk()) {
-            ackWindowInfosReceived(update.vsyncId, listenerId);
+            reportedInvoker->onWindowInfosReported();
         }
     }
 }
 
-WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() {
-    DebugInfo result;
-    BackgroundExecutor::getInstance().sendCallbacks({[&, this]() {
-        ATRACE_NAME("WindowInfosListenerInvoker::getDebugInfo");
-        updateMaxSendDelay();
-        result = mDebugInfo;
-        result.pendingMessageCount = mUnackedState.size();
+binder::Status WindowInfosListenerInvoker::onWindowInfosReported() {
+    BackgroundExecutor::getInstance().sendCallbacks({[this]() {
+        gui::WindowInfosUpdate update;
+        {
+            std::scoped_lock lock{mMessagesMutex};
+            mActiveMessageCount--;
+            if (!mDelayedUpdate || mActiveMessageCount > 0) {
+                return;
+            }
+            update = std::move(*mDelayedUpdate);
+            mDelayedUpdate.reset();
+        }
+        windowInfosChanged(std::move(update), {}, false);
     }});
-    BackgroundExecutor::getInstance().flushQueue();
-    return result;
+    return binder::Status::ok();
+}
+
+WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() {
+    std::scoped_lock lock{mMessagesMutex};
+    updateMaxSendDelay();
+    mDebugInfo.pendingMessageCount = mActiveMessageCount;
+    return mDebugInfo;
 }
 
 void WindowInfosListenerInvoker::updateMaxSendDelay() {
@@ -162,41 +192,4 @@
     }
 }
 
-binder::Status WindowInfosListenerInvoker::ackWindowInfosReceived(int64_t vsyncId,
-                                                                  int64_t listenerId) {
-    BackgroundExecutor::getInstance().sendCallbacks({[this, vsyncId, listenerId]() {
-        ATRACE_NAME("WindowInfosListenerInvoker::ackWindowInfosReceived");
-        auto it = mUnackedState.find(vsyncId);
-        if (it == mUnackedState.end()) {
-            return;
-        }
-
-        auto& state = it->second;
-        state.unackedListenerIds.unstable_erase(std::find(state.unackedListenerIds.begin(),
-                                                          state.unackedListenerIds.end(),
-                                                          listenerId));
-        if (!state.unackedListenerIds.empty()) {
-            return;
-        }
-
-        WindowInfosReportedListenerSet reportedListeners{std::move(state.reportedListeners)};
-        mUnackedState.erase(vsyncId);
-
-        for (const auto& reportedListener : reportedListeners) {
-            sp<IBinder> asBinder = IInterface::asBinder(reportedListener);
-            if (asBinder->isBinderAlive()) {
-                reportedListener->onWindowInfosReported();
-            }
-        }
-
-        if (!mDelayedUpdate || !mUnackedState.empty()) {
-            return;
-        }
-        gui::WindowInfosUpdate update{std::move(*mDelayedUpdate)};
-        mDelayedUpdate.reset();
-        windowInfosChanged(std::move(update), {}, false);
-    }});
-    return binder::Status::ok();
-}
-
 } // namespace android
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index f36b0ed..bc465a3 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -19,12 +19,11 @@
 #include <optional>
 #include <unordered_set>
 
-#include <android/gui/BnWindowInfosPublisher.h>
+#include <android/gui/BnWindowInfosReportedListener.h>
 #include <android/gui/IWindowInfosListener.h>
 #include <android/gui/IWindowInfosReportedListener.h>
 #include <binder/IBinder.h>
 #include <ftl/small_map.h>
-#include <ftl/small_vector.h>
 #include <gui/SpHash.h>
 #include <utils/Mutex.h>
 
@@ -36,22 +35,22 @@
         std::unordered_set<sp<gui::IWindowInfosReportedListener>,
                            gui::SpHash<gui::IWindowInfosReportedListener>>;
 
-class WindowInfosListenerInvoker : public gui::BnWindowInfosPublisher,
+class WindowInfosListenerInvoker : public gui::BnWindowInfosReportedListener,
                                    public IBinder::DeathRecipient {
 public:
-    void addWindowInfosListener(sp<gui::IWindowInfosListener>, gui::WindowInfosListenerInfo*);
+    void addWindowInfosListener(sp<gui::IWindowInfosListener>);
     void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
 
     void windowInfosChanged(gui::WindowInfosUpdate update,
                             WindowInfosReportedListenerSet windowInfosReportedListeners,
                             bool forceImmediateCall);
 
-    binder::Status ackWindowInfosReceived(int64_t, int64_t) override;
+    binder::Status onWindowInfosReported() override;
 
     struct DebugInfo {
         VsyncId maxSendDelayVsyncId;
         nsecs_t maxSendDelayDuration;
-        size_t pendingMessageCount;
+        uint32_t pendingMessageCount;
     };
     DebugInfo getDebugInfo();
 
@@ -59,28 +58,24 @@
     void binderDied(const wp<IBinder>& who) override;
 
 private:
-    static constexpr size_t kStaticCapacity = 3;
-    std::atomic<int64_t> mNextListenerId{0};
-    ftl::SmallMap<wp<IBinder>, const std::pair<int64_t, sp<gui::IWindowInfosListener>>,
-                  kStaticCapacity>
-            mWindowInfosListeners;
+    std::mutex mListenersMutex;
 
-    std::optional<gui::WindowInfosUpdate> mDelayedUpdate;
+    static constexpr size_t kStaticCapacity = 3;
+    ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity>
+            mWindowInfosListeners GUARDED_BY(mListenersMutex);
+
+    std::mutex mMessagesMutex;
+    uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0;
+    std::optional<gui::WindowInfosUpdate> mDelayedUpdate GUARDED_BY(mMessagesMutex);
     WindowInfosReportedListenerSet mReportedListeners;
 
-    struct UnackedState {
-        ftl::SmallVector<int64_t, kStaticCapacity> unackedListenerIds;
-        WindowInfosReportedListenerSet reportedListeners;
-    };
-    ftl::SmallMap<int64_t /* vsyncId */, UnackedState, 5> mUnackedState;
-
-    DebugInfo mDebugInfo;
+    DebugInfo mDebugInfo GUARDED_BY(mMessagesMutex);
     struct DelayInfo {
         int64_t vsyncId;
         nsecs_t frameTime;
     };
-    std::optional<DelayInfo> mDelayInfo;
-    void updateMaxSendDelay();
+    std::optional<DelayInfo> mDelayInfo GUARDED_BY(mMessagesMutex);
+    void updateMaxSendDelay() REQUIRES(mMessagesMutex);
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp
index c7b845e..af4971b 100644
--- a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp
@@ -15,23 +15,35 @@
     WindowInfosListenerInvokerTest() : mInvoker(sp<WindowInfosListenerInvoker>::make()) {}
 
     ~WindowInfosListenerInvokerTest() {
+        std::mutex mutex;
+        std::condition_variable cv;
+        bool flushComplete = false;
         // Flush the BackgroundExecutor thread to ensure any scheduled tasks are complete.
         // Otherwise, references those tasks hold may go out of scope before they are done
         // executing.
-        BackgroundExecutor::getInstance().flushQueue();
+        BackgroundExecutor::getInstance().sendCallbacks({[&]() {
+            std::scoped_lock lock{mutex};
+            flushComplete = true;
+            cv.notify_one();
+        }});
+        std::unique_lock<std::mutex> lock{mutex};
+        cv.wait(lock, [&]() { return flushComplete; });
     }
 
     sp<WindowInfosListenerInvoker> mInvoker;
 };
 
-using WindowInfosUpdateConsumer = std::function<void(const gui::WindowInfosUpdate&)>;
+using WindowInfosUpdateConsumer = std::function<void(const gui::WindowInfosUpdate&,
+                                                     const sp<gui::IWindowInfosReportedListener>&)>;
 
 class Listener : public gui::BnWindowInfosListener {
 public:
     Listener(WindowInfosUpdateConsumer consumer) : mConsumer(std::move(consumer)) {}
 
-    binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override {
-        mConsumer(update);
+    binder::Status onWindowInfosChanged(
+            const gui::WindowInfosUpdate& update,
+            const sp<gui::IWindowInfosReportedListener>& reportedListener) override {
+        mConsumer(update, reportedListener);
         return binder::Status::ok();
     }
 
@@ -46,17 +58,15 @@
 
     int callCount = 0;
 
-    gui::WindowInfosListenerInfo listenerInfo;
-    mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate& update) {
-                                         std::scoped_lock lock{mutex};
-                                         callCount++;
-                                         cv.notify_one();
+    mInvoker->addWindowInfosListener(
+            sp<Listener>::make([&](const gui::WindowInfosUpdate&,
+                                   const sp<gui::IWindowInfosReportedListener>& reportedListener) {
+                std::scoped_lock lock{mutex};
+                callCount++;
+                cv.notify_one();
 
-                                         listenerInfo.windowInfosPublisher
-                                                 ->ackWindowInfosReceived(update.vsyncId,
-                                                                          listenerInfo.listenerId);
-                                     }),
-                                     &listenerInfo);
+                reportedListener->onWindowInfosReported();
+            }));
 
     BackgroundExecutor::getInstance().sendCallbacks(
             {[this]() { mInvoker->windowInfosChanged({}, {}, false); }});
@@ -71,27 +81,21 @@
     std::mutex mutex;
     std::condition_variable cv;
 
-    size_t callCount = 0;
-    const size_t expectedCallCount = 3;
-    std::vector<gui::WindowInfosListenerInfo> listenerInfos{expectedCallCount,
-                                                            gui::WindowInfosListenerInfo{}};
+    int callCount = 0;
+    const int expectedCallCount = 3;
 
-    for (size_t i = 0; i < expectedCallCount; i++) {
-        mInvoker->addWindowInfosListener(sp<Listener>::make([&, &listenerInfo = listenerInfos[i]](
-                                                                    const gui::WindowInfosUpdate&
-                                                                            update) {
-                                             std::scoped_lock lock{mutex};
-                                             callCount++;
-                                             if (callCount == expectedCallCount) {
-                                                 cv.notify_one();
-                                             }
+    for (int i = 0; i < expectedCallCount; i++) {
+        mInvoker->addWindowInfosListener(sp<Listener>::make(
+                [&](const gui::WindowInfosUpdate&,
+                    const sp<gui::IWindowInfosReportedListener>& reportedListener) {
+                    std::scoped_lock lock{mutex};
+                    callCount++;
+                    if (callCount == expectedCallCount) {
+                        cv.notify_one();
+                    }
 
-                                             listenerInfo.windowInfosPublisher
-                                                     ->ackWindowInfosReceived(update.vsyncId,
-                                                                              listenerInfo
-                                                                                      .listenerId);
-                                         }),
-                                         &listenerInfos[i]);
+                    reportedListener->onWindowInfosReported();
+                }));
     }
 
     BackgroundExecutor::getInstance().sendCallbacks(
@@ -110,20 +114,17 @@
 
     int callCount = 0;
 
-    // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived
-    gui::WindowInfosListenerInfo listenerInfo;
-    mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate&) {
-                                         std::scoped_lock lock{mutex};
-                                         callCount++;
-                                         cv.notify_one();
-                                     }),
-                                     &listenerInfo);
+    // Simulate a slow ack by not calling the WindowInfosReportedListener.
+    mInvoker->addWindowInfosListener(sp<Listener>::make(
+            [&](const gui::WindowInfosUpdate&, const sp<gui::IWindowInfosReportedListener>&) {
+                std::scoped_lock lock{mutex};
+                callCount++;
+                cv.notify_one();
+            }));
 
     BackgroundExecutor::getInstance().sendCallbacks({[&]() {
-        mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {},
-                                     false);
-        mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {},
-                                     false);
+        mInvoker->windowInfosChanged({}, {}, false);
+        mInvoker->windowInfosChanged({}, {}, false);
     }});
 
     {
@@ -133,7 +134,7 @@
     EXPECT_EQ(callCount, 1);
 
     // Ack the first message.
-    listenerInfo.windowInfosPublisher->ackWindowInfosReceived(0, listenerInfo.listenerId);
+    mInvoker->onWindowInfosReported();
 
     {
         std::unique_lock lock{mutex};
@@ -151,21 +152,19 @@
     int callCount = 0;
     const int expectedCallCount = 2;
 
-    // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived
-    gui::WindowInfosListenerInfo listenerInfo;
-    mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate&) {
-                                         std::scoped_lock lock{mutex};
-                                         callCount++;
-                                         if (callCount == expectedCallCount) {
-                                             cv.notify_one();
-                                         }
-                                     }),
-                                     &listenerInfo);
+    // Simulate a slow ack by not calling the WindowInfosReportedListener.
+    mInvoker->addWindowInfosListener(sp<Listener>::make(
+            [&](const gui::WindowInfosUpdate&, const sp<gui::IWindowInfosReportedListener>&) {
+                std::scoped_lock lock{mutex};
+                callCount++;
+                if (callCount == expectedCallCount) {
+                    cv.notify_one();
+                }
+            }));
 
     BackgroundExecutor::getInstance().sendCallbacks({[&]() {
-        mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {},
-                                     false);
-        mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {}, true);
+        mInvoker->windowInfosChanged({}, {}, false);
+        mInvoker->windowInfosChanged({}, {}, true);
     }});
 
     {
@@ -183,14 +182,14 @@
 
     int64_t lastUpdateId = -1;
 
-    // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived
-    gui::WindowInfosListenerInfo listenerInfo;
-    mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate& update) {
-                                         std::scoped_lock lock{mutex};
-                                         lastUpdateId = update.vsyncId;
-                                         cv.notify_one();
-                                     }),
-                                     &listenerInfo);
+    // Simulate a slow ack by not calling the WindowInfosReportedListener.
+    mInvoker->addWindowInfosListener(
+            sp<Listener>::make([&](const gui::WindowInfosUpdate& update,
+                                   const sp<gui::IWindowInfosReportedListener>&) {
+                std::scoped_lock lock{mutex};
+                lastUpdateId = update.vsyncId;
+                cv.notify_one();
+            }));
 
     BackgroundExecutor::getInstance().sendCallbacks({[&]() {
         mInvoker->windowInfosChanged({{}, {}, /* vsyncId= */ 1, 0}, {}, false);
@@ -205,7 +204,7 @@
     EXPECT_EQ(lastUpdateId, 1);
 
     // Ack the first message. The third update should be sent.
-    listenerInfo.windowInfosPublisher->ackWindowInfosReceived(1, listenerInfo.listenerId);
+    mInvoker->onWindowInfosReported();
 
     {
         std::unique_lock lock{mutex};
@@ -226,17 +225,14 @@
     // delayed.
     BackgroundExecutor::getInstance().sendCallbacks({[&]() {
         mInvoker->windowInfosChanged({}, {}, false);
-        gui::WindowInfosListenerInfo listenerInfo;
-        mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate&) {
-                                             std::scoped_lock lock{mutex};
-                                             callCount++;
-                                             cv.notify_one();
-                                         }),
-                                         &listenerInfo);
+        mInvoker->addWindowInfosListener(sp<Listener>::make(
+                [&](const gui::WindowInfosUpdate&, const sp<gui::IWindowInfosReportedListener>&) {
+                    std::scoped_lock lock{mutex};
+                    callCount++;
+                    cv.notify_one();
+                }));
+        mInvoker->windowInfosChanged({}, {}, false);
     }});
-    BackgroundExecutor::getInstance().flushQueue();
-    BackgroundExecutor::getInstance().sendCallbacks(
-            {[&]() { mInvoker->windowInfosChanged({}, {}, false); }});
 
     {
         std::unique_lock lock{mutex};