Merge "SF: Introduce background task executor"
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index c9fb7bc..c453d62 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -144,6 +144,7 @@
 filegroup {
     name: "libsurfaceflinger_sources",
     srcs: [
+        "BackgroundExecutor.cpp",
         "BufferLayer.cpp",
         "BufferLayerConsumer.cpp",
         "BufferQueueLayer.cpp",
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
new file mode 100644
index 0000000..3663cdb
--- /dev/null
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2021 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.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "BackgroundExecutor"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BackgroundExecutor.h"
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BackgroundExecutor);
+
+BackgroundExecutor::BackgroundExecutor() : Singleton<BackgroundExecutor>() {
+    mThread = std::thread([&]() {
+        bool done = false;
+        while (!done) {
+            std::vector<std::function<void()>> tasks;
+            {
+                std::unique_lock lock(mMutex);
+                mWorkAvailableCv.wait(lock, [&]() { return mDone || !mTasks.empty(); });
+                tasks = std::move(mTasks);
+                mTasks.clear();
+                done = mDone;
+            } // unlock mMutex
+
+            for (auto& task : tasks) {
+                task();
+            }
+        }
+    });
+}
+
+BackgroundExecutor::~BackgroundExecutor() {
+    {
+        std::unique_lock lock(mMutex);
+        mDone = true;
+        mWorkAvailableCv.notify_all();
+    }
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void BackgroundExecutor::execute(std::function<void()> task) {
+    std::unique_lock lock(mMutex);
+    mTasks.emplace_back(std::move(task));
+    mWorkAvailableCv.notify_all();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
new file mode 100644
index 0000000..6f6d305
--- /dev/null
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#pragma once
+
+#include <utils/Singleton.h>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+namespace android {
+
+// Executes tasks off the main thread.
+class BackgroundExecutor : public Singleton<BackgroundExecutor> {
+public:
+    BackgroundExecutor();
+    ~BackgroundExecutor();
+    void execute(std::function<void()>);
+
+private:
+    std::mutex mMutex;
+    std::condition_variable mWorkAvailableCv;
+    std::thread mThread;
+    bool mDone = false;
+    std::vector<std::function<void()>> mTasks;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index f3d46ea..b705d9c 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -24,6 +24,7 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include "TransactionCallbackInvoker.h"
+#include "BackgroundExecutor.h"
 
 #include <cinttypes>
 
@@ -49,31 +50,6 @@
     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];
@@ -242,15 +218,10 @@
                 // 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.
-                {
-                    std::unique_lock lock(mCallbackThreadMutex);
-                    mCallbackThreadWork.push(
-                        [stats = std::move(listenerStats)]() {
-                          interface_cast<ITransactionCompletedListener>(stats.listener)
-                              ->onTransactionCompleted(stats);
-                    });
-                    mCallbackConditionVariable.notify_all();
-                }
+                BackgroundExecutor::getInstance().execute([stats = std::move(listenerStats)]() {
+                    interface_cast<ITransactionCompletedListener>(stats.listener)
+                            ->onTransactionCompleted(stats);
+                });
             }
         }
         completedTransactionsItr++;
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index e203d41..5ef5475 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -61,9 +61,6 @@
 
 class TransactionCallbackInvoker {
 public:
-    TransactionCallbackInvoker();
-    ~TransactionCallbackInvoker();
-
     status_t addCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
                                 const std::vector<JankData>& jankData);
     status_t addOnCommitCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
@@ -94,12 +91,6 @@
         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