Merge "TransactionCallbackInvoker: Send callbacks on thread"
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 4b12a26..c1eb896 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -49,6 +49,31 @@
     return !callbacks.empty() && callbacks.front().type == CallbackId::Type::ON_COMMIT;
 }
 
+TransactionCallbackInvoker::TransactionCallbackInvoker() {
+    mThread = std::thread([&]() {
+          std::unique_lock lock(mCallbackThreadMutex);
+
+        while (mKeepRunning) {
+          while (mCallbackThreadWork.size() > 0) {
+              mCallbackThreadWork.front()();
+              mCallbackThreadWork.pop();
+          }
+          mCallbackConditionVariable.wait(lock);
+        }
+    });
+}
+
+TransactionCallbackInvoker::~TransactionCallbackInvoker() {
+    {
+          std::unique_lock lock(mCallbackThreadMutex);
+          mKeepRunning = false;
+          mCallbackConditionVariable.notify_all();
+    }
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
 void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) {
     auto& [listener, callbackIds] = listenerCallbacks;
     auto& transactionStatsDeque = mCompletedTransactions[listener];
@@ -180,8 +205,15 @@
                 // keep it as an IBinder due to consistency reasons: if we
                 // interface_cast at the IPC boundary when reading a Parcel,
                 // we get pointers that compare unequal in the SF process.
-                interface_cast<ITransactionCompletedListener>(listenerStats.listener)
-                        ->onTransactionCompleted(listenerStats);
+                {
+                    std::unique_lock lock(mCallbackThreadMutex);
+                    mCallbackThreadWork.push(
+                        [stats = std::move(listenerStats)]() {
+                          interface_cast<ITransactionCompletedListener>(stats.listener)
+                              ->onTransactionCompleted(stats);
+                    });
+                    mCallbackConditionVariable.notify_all();
+                }
             }
         }
         completedTransactionsItr++;
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 71ca6e5..7e879e1 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -18,6 +18,7 @@
 
 #include <condition_variable>
 #include <deque>
+#include <queue>
 #include <mutex>
 #include <thread>
 #include <unordered_map>
@@ -56,8 +57,11 @@
 
 class TransactionCallbackInvoker {
 public:
+    TransactionCallbackInvoker();
+    ~TransactionCallbackInvoker();
+
     status_t addCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
-                                            const std::vector<JankData>& jankData);
+                                const std::vector<JankData>& jankData);
     status_t addOnCommitCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
                                              std::deque<sp<CallbackHandle>>& outRemainingHandles);
 
@@ -88,6 +92,12 @@
         mCompletedTransactions;
 
     sp<Fence> mPresentFence;
+
+    std::mutex mCallbackThreadMutex;
+    std::condition_variable mCallbackConditionVariable;
+    std::thread mThread;
+    bool mKeepRunning = true;
+    std::queue<std::function<void()>> mCallbackThreadWork;
 };
 
 } // namespace android