Merge "Make sure all debug logs could be present after enabled" into tm-dev
diff --git a/include/ftl/details/future.h b/include/ftl/details/future.h
new file mode 100644
index 0000000..df1323e
--- /dev/null
+++ b/include/ftl/details/future.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2022 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
+
+namespace android::ftl {
+
+template <typename, template <typename> class>
+class Future;
+
+namespace details {
+
+template <typename T>
+struct future_result {
+  using type = T;
+};
+
+template <typename T>
+struct future_result<std::future<T>> {
+  using type = T;
+};
+
+template <typename T>
+struct future_result<std::shared_future<T>> {
+  using type = T;
+};
+
+template <typename T, template <typename> class FutureImpl>
+struct future_result<Future<T, FutureImpl>> {
+  using type = T;
+};
+
+template <typename T>
+using future_result_t = typename future_result<T>::type;
+
+struct ValueTag {};
+
+template <typename, typename T, template <typename> class>
+class BaseFuture;
+
+template <typename Self, typename T>
+class BaseFuture<Self, T, std::future> {
+  using Impl = std::future<T>;
+
+ public:
+  Future<T, std::shared_future> share() {
+    if (T* value = std::get_if<T>(&self())) {
+      return {ValueTag{}, std::move(*value)};
+    }
+
+    return std::get<Impl>(self()).share();
+  }
+
+ protected:
+  T get() {
+    if (T* value = std::get_if<T>(&self())) {
+      return std::move(*value);
+    }
+
+    return std::get<Impl>(self()).get();
+  }
+
+ private:
+  auto& self() { return static_cast<Self&>(*this).future_; }
+};
+
+template <typename Self, typename T>
+class BaseFuture<Self, T, std::shared_future> {
+  using Impl = std::shared_future<T>;
+
+ protected:
+  const T& get() const {
+    if (const T* value = std::get_if<T>(&self())) {
+      return *value;
+    }
+
+    return std::get<Impl>(self()).get();
+  }
+
+ private:
+  const auto& self() const { return static_cast<const Self&>(*this).future_; }
+};
+
+}  // namespace details
+}  // namespace android::ftl
diff --git a/include/ftl/future.h b/include/ftl/future.h
index dd6358f..c78f9b7 100644
--- a/include/ftl/future.h
+++ b/include/ftl/future.h
@@ -19,18 +19,87 @@
 #include <future>
 #include <type_traits>
 #include <utility>
+#include <variant>
+
+#include <ftl/details/future.h>
 
 namespace android::ftl {
 
-// Creates a future that defers a function call until its result is queried.
+// Thin wrapper around FutureImpl<T> (concretely std::future<T> or std::shared_future<T>) with
+// extensions for pure values (created via ftl::yield) and continuations.
 //
-//   auto future = ftl::defer([](int x) { return x + 1; }, 99);
-//   assert(future.get() == 100);
+// See also SharedFuture<T> shorthand below.
 //
-template <typename F, typename... Args>
-inline auto defer(F&& f, Args&&... args) {
-  return std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...);
-}
+template <typename T, template <typename> class FutureImpl = std::future>
+class Future final : public details::BaseFuture<Future<T, FutureImpl>, T, FutureImpl> {
+  using Base = details::BaseFuture<Future, T, FutureImpl>;
+
+  friend Base;                                            // For BaseFuture<...>::self.
+  friend details::BaseFuture<Future<T>, T, std::future>;  // For BaseFuture<...>::share.
+
+ public:
+  // Constructs an invalid future.
+  Future() : future_(std::in_place_type<FutureImpl<T>>) {}
+
+  // Constructs a future from its standard counterpart, implicitly.
+  Future(FutureImpl<T>&& f) : future_(std::move(f)) {}
+
+  bool valid() const {
+    return std::holds_alternative<T>(future_) || std::get<FutureImpl<T>>(future_).valid();
+  }
+
+  // Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the
+  // following are defined for either FutureImpl:
+  using Base::get;
+
+  // Attaches a continuation to the future. The continuation is a function that maps T to either R
+  // or ftl::Future<R>. In the former case, the chain wraps the result in a future as if by
+  // ftl::yield.
+  //
+  //   auto future = ftl::yield(123);
+  //   ftl::Future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+  //
+  //   auto chain =
+  //       ftl::Future(std::move(future))
+  //           .then([](int x) { return static_cast<std::size_t>(x % 2); })
+  //           .then([&futures](std::size_t i) { return std::move(futures[i]); });
+  //
+  //   assert(chain.get() == 'b');
+  //
+  template <typename F, typename R = std::invoke_result_t<F, T>>
+  auto then(F&& op) && -> Future<details::future_result_t<R>> {
+    return defer(
+        [](auto&& f, F&& op) {
+          R r = op(f.get());
+          if constexpr (std::is_same_v<R, details::future_result_t<R>>) {
+            return r;
+          } else {
+            return r.get();
+          }
+        },
+        std::move(*this), std::forward<F>(op));
+  }
+
+ private:
+  template <typename V>
+  friend Future<V> yield(V&&);
+
+  template <typename V, typename... Args>
+  friend Future<V> yield(Args&&...);
+
+  template <typename... Args>
+  Future(details::ValueTag, Args&&... args)
+      : future_(std::in_place_type<T>, std::forward<Args>(args)...) {}
+
+  std::variant<T, FutureImpl<T>> future_;
+};
+
+template <typename T>
+using SharedFuture = Future<T, std::shared_future>;
+
+// Deduction guide for implicit conversion.
+template <typename T, template <typename> class FutureImpl>
+Future(FutureImpl<T>&&) -> Future<T, FutureImpl>;
 
 // Creates a future that wraps a value.
 //
@@ -41,69 +110,24 @@
 //   auto future = ftl::yield(std::move(ptr));
 //   assert(*future.get() == '!');
 //
-template <typename T>
-inline std::future<T> yield(T&& v) {
-  return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v));
+template <typename V>
+inline Future<V> yield(V&& value) {
+  return {details::ValueTag{}, std::move(value)};
 }
 
-namespace details {
+template <typename V, typename... Args>
+inline Future<V> yield(Args&&... args) {
+  return {details::ValueTag{}, std::forward<Args>(args)...};
+}
 
-template <typename T>
-struct future_result {
-  using type = T;
-};
-
-template <typename T>
-struct future_result<std::future<T>> {
-  using type = T;
-};
-
-template <typename T>
-using future_result_t = typename future_result<T>::type;
-
-// Attaches a continuation to a future. The continuation is a function that maps T to either R or
-// std::future<R>. In the former case, the chain wraps the result in a future as if by ftl::yield.
+// Creates a future that defers a function call until its result is queried.
 //
-//   auto future = ftl::yield(123);
-//   std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+//   auto future = ftl::defer([](int x) { return x + 1; }, 99);
+//   assert(future.get() == 100);
 //
-//   std::future<char> chain =
-//       ftl::chain(std::move(future))
-//           .then([](int x) { return static_cast<std::size_t>(x % 2); })
-//           .then([&futures](std::size_t i) { return std::move(futures[i]); });
-//
-//   assert(chain.get() == 'b');
-//
-template <typename T>
-struct Chain {
-  // Implicit conversion.
-  Chain(std::future<T>&& f) : future(std::move(f)) {}
-  operator std::future<T>&&() && { return std::move(future); }
-
-  T get() && { return future.get(); }
-
-  template <typename F, typename R = std::invoke_result_t<F, T>>
-  auto then(F&& op) && -> Chain<future_result_t<R>> {
-    return defer(
-        [](auto&& f, F&& op) {
-          R r = op(f.get());
-          if constexpr (std::is_same_v<R, future_result_t<R>>) {
-            return r;
-          } else {
-            return r.get();
-          }
-        },
-        std::move(future), std::forward<F>(op));
-  }
-
-  std::future<T> future;
-};
-
-}  // namespace details
-
-template <typename T>
-inline auto chain(std::future<T>&& f) -> details::Chain<T> {
-  return std::move(f);
+template <typename F, typename... Args>
+inline auto defer(F&& f, Args&&... args) {
+  return Future(std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...));
 }
 
 }  // namespace android::ftl
diff --git a/libs/ftl/future_test.cpp b/libs/ftl/future_test.cpp
index 9b3e936..5a245b6 100644
--- a/libs/ftl/future_test.cpp
+++ b/libs/ftl/future_test.cpp
@@ -42,9 +42,9 @@
   }
   {
     auto future = ftl::yield(123);
-    std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
+    ftl::Future<char> futures[] = {ftl::yield('a'), ftl::yield('b')};
 
-    std::future<char> chain = ftl::chain(std::move(future))
+    ftl::Future<char> chain = ftl::Future(std::move(future))
                                   .then([](int x) { return static_cast<size_t>(x % 2); })
                                   .then([&futures](size_t i) { return std::move(futures[i]); });
 
@@ -71,7 +71,7 @@
     return ByteVector{str.begin(), str.end()};
   });
 
-  std::packaged_task<std::future<ByteVector>(ByteVector)> decrement_bytes(
+  std::packaged_task<ftl::Future<ByteVector>(ByteVector)> decrement_bytes(
       [](ByteVector bytes) { return ftl::defer(decrement, std::move(bytes)); });
 
   auto fetch = fetch_string.get_future();
@@ -81,7 +81,7 @@
 
   EXPECT_EQ(
       "hello, world",
-      ftl::chain(std::move(fetch))
+      ftl::Future(std::move(fetch))
           .then([](const char* str) { return std::string(str); })
           .then([&](std::string str) {
             auto append = append_string.get_future();
@@ -93,7 +93,7 @@
             decrement_thread = std::thread(std::move(decrement_bytes), std::move(bytes));
             return decrement;
           })
-          .then([](std::future<ByteVector> bytes) { return bytes; })
+          .then([](ftl::Future<ByteVector> bytes) { return bytes; })
           .then([](const ByteVector& bytes) { return std::string(bytes.begin(), bytes.end()); })
           .get());
 
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
index de8e6b3..a15de2b 100644
--- a/services/surfaceflinger/BackgroundExecutor.cpp
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -19,6 +19,8 @@
 #define LOG_TAG "BackgroundExecutor"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
+#include <utils/Log.h>
+
 #include "BackgroundExecutor.h"
 
 namespace android {
@@ -27,41 +29,49 @@
 
 BackgroundExecutor::BackgroundExecutor() : Singleton<BackgroundExecutor>() {
     mThread = std::thread([&]() {
-        bool done = false;
-        while (!done) {
-            std::vector<std::function<void()>> tasks;
-            {
-                std::unique_lock lock(mMutex);
-                android::base::ScopedLockAssertion assumeLock(mMutex);
-                mWorkAvailableCv.wait(lock,
-                                      [&]() REQUIRES(mMutex) { return mDone || !mTasks.empty(); });
-                tasks = std::move(mTasks);
-                mTasks.clear();
-                done = mDone;
-            } // unlock mMutex
+        LOG_ALWAYS_FATAL_IF(sem_init(&mSemaphore, 0, 0), "sem_init failed");
+        while (!mDone) {
+            LOG_ALWAYS_FATAL_IF(sem_wait(&mSemaphore), "sem_wait failed (%d)", errno);
 
-            for (auto& task : tasks) {
-                task();
+            ftl::SmallVector<Work*, 10> workItems;
+
+            Work* work = mWorks.pop();
+            while (work) {
+                workItems.push_back(work);
+                work = mWorks.pop();
+            }
+
+            // Sequence numbers are guaranteed to be in intended order, as we assume a single
+            // producer and single consumer.
+            std::stable_sort(workItems.begin(), workItems.end(), [](Work* left, Work* right) {
+                return left->sequence < right->sequence;
+            });
+            for (Work* work : workItems) {
+                for (auto& task : work->tasks) {
+                    task();
+                }
+                delete work;
             }
         }
     });
 }
 
 BackgroundExecutor::~BackgroundExecutor() {
-    {
-        std::scoped_lock lock(mMutex);
-        mDone = true;
-        mWorkAvailableCv.notify_all();
-    }
+    mDone = true;
+    LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
     if (mThread.joinable()) {
         mThread.join();
+        LOG_ALWAYS_FATAL_IF(sem_destroy(&mSemaphore), "sem_destroy failed");
     }
 }
 
-void BackgroundExecutor::execute(std::function<void()> task) {
-    std::scoped_lock lock(mMutex);
-    mTasks.emplace_back(std::move(task));
-    mWorkAvailableCv.notify_all();
+void BackgroundExecutor::sendCallbacks(Callbacks&& tasks) {
+    Work* work = new Work();
+    work->sequence = mSequence;
+    work->tasks = std::move(tasks);
+    mWorks.push(work);
+    mSequence++;
+    LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
 }
 
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
index 6db7dda..eeaf3bd 100644
--- a/services/surfaceflinger/BackgroundExecutor.h
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -16,9 +16,11 @@
 
 #pragma once
 
+#include <Tracing/LocklessStack.h>
 #include <android-base/thread_annotations.h>
+#include <ftl/small_vector.h>
+#include <semaphore.h>
 #include <utils/Singleton.h>
-#include <condition_variable>
 #include <mutex>
 #include <queue>
 #include <thread>
@@ -30,13 +32,26 @@
 public:
     BackgroundExecutor();
     ~BackgroundExecutor();
-    void execute(std::function<void()>);
+    using Callbacks = ftl::SmallVector<std::function<void()>, 10>;
+    // Queues callbacks onto a work queue to be executed by a background thread.
+    // Note that this is not thread-safe - a single producer is assumed.
+    void sendCallbacks(Callbacks&& tasks);
 
 private:
-    std::mutex mMutex;
-    std::condition_variable mWorkAvailableCv GUARDED_BY(mMutex);
-    bool mDone GUARDED_BY(mMutex) = false;
-    std::vector<std::function<void()>> mTasks GUARDED_BY(mMutex);
+    sem_t mSemaphore;
+    std::atomic_bool mDone = false;
+
+    // Sequence number for work items.
+    // Work items are batched by sequence number. Work items for earlier sequence numbers are
+    // executed first. Work items with the same sequence number are executed in the same order they
+    // were added to the stack (meaning the stack must reverse the order after popping from the
+    // queue)
+    int32_t mSequence = 0;
+    struct Work {
+        int32_t sequence = 0;
+        Callbacks tasks;
+    };
+    LocklessStack<Work> mWorks;
     std::thread mThread;
 };
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index f487aab..bee4de3 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -48,7 +48,7 @@
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
 
-void BufferQueueLayer::onLayerDisplayed(std::shared_future<FenceResult> futureFenceResult) {
+void BufferQueueLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
     const sp<Fence> releaseFence = futureFenceResult.get().value_or(Fence::NO_FENCE);
     mConsumer->setReleaseFence(releaseFence);
 
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 649da2c..e1c80d5 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -42,7 +42,7 @@
     // Implements Layer.
     const char* getType() const override { return "BufferQueueLayer"; }
 
-    void onLayerDisplayed(std::shared_future<FenceResult>) override;
+    void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
 
     // If a buffer was replaced this frame, release the former buffer
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e58b65e..1a5b925 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -73,7 +73,7 @@
 // -----------------------------------------------------------------------
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(std::shared_future<FenceResult> futureFenceResult) {
+void BufferStateLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
     // If we are displayed on multiple displays in a single composition cycle then we would
     // need to do careful tracking to enable the use of the mLastClientCompositionFence.
     //  For example we can only use it if all the displays are client comp, and we need
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index bbf058c..3f0dbe4 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -39,7 +39,7 @@
     // Implements Layer.
     const char* getType() const override { return "BufferStateLayer"; }
 
-    void onLayerDisplayed(std::shared_future<FenceResult>) override;
+    void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
 
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index b7fc62f..ec610c1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <future>
 #include <optional>
 #include <ostream>
 #include <unordered_set>
@@ -33,6 +32,7 @@
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
 
+#include <ftl/future.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
@@ -157,7 +157,7 @@
             ClientCompositionTargetSettings&) = 0;
 
     // Called after the layer is displayed to update the presentation fence
-    virtual void onLayerDisplayed(std::shared_future<FenceResult>) = 0;
+    virtual void onLayerDisplayed(ftl::SharedFuture<FenceResult>) = 0;
 
     // Gets some kind of identifier for the layer for debug purposes.
     virtual const char* getDebugName() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 871599d..1c5c10f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -49,7 +49,7 @@
                  std::vector<compositionengine::LayerFE::LayerSettings>(
                          compositionengine::LayerFE::ClientCompositionTargetSettings&));
 
-    MOCK_METHOD1(onLayerDisplayed, void(std::shared_future<FenceResult>));
+    MOCK_METHOD(void, onLayerDisplayed, (ftl::SharedFuture<FenceResult>), (override));
 
     MOCK_CONST_METHOD0(getDebugName, const char*());
     MOCK_CONST_METHOD0(getSequence, int32_t());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 2d2b3df..aac478d 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1365,7 +1365,10 @@
                 }
             }
 
-            outLayerFEs.push_back(&layerFE);
+            if (clientComposition) {
+                outLayerFEs.push_back(&layerFE);
+            }
+
             clientCompositionLayers.insert(clientCompositionLayers.end(),
                                            std::make_move_iterator(results.begin()),
                                            std::make_move_iterator(results.end()));
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 8d26747..0918510 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -401,19 +401,6 @@
     return true;
 }
 
-namespace {
-bool isDisplayDecoration(const CachedSet& cachedSet) {
-    return cachedSet.getLayerCount() == 1 &&
-            cachedSet.getFirstLayer()
-                    .getState()
-                    ->getOutputLayer()
-                    ->getLayerFE()
-                    .getCompositionState()
-                    ->compositionType ==
-            aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
-}
-} // namespace
-
 std::vector<Flattener::Run> Flattener::findCandidateRuns(time_point now) const {
     ATRACE_CALL();
     std::vector<Run> runs;
@@ -437,7 +424,7 @@
         }
 
         if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
-            !currentSet->hasUnsupportedDataspace() && !isDisplayDecoration(*currentSet)) {
+            !currentSet->hasUnsupportedDataspace()) {
             if (isPartOfRun) {
                 builder.increment();
             } else {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index ff2aa15..9b12b08 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -84,9 +84,9 @@
     MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t));
     MOCK_METHOD4(getDisplayedContentSample,
                  status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
-    MOCK_METHOD4(setDisplayBrightness,
-                 std::future<status_t>(PhysicalDisplayId, float, float,
-                                       const Hwc2::Composer::DisplayBrightnessOptions&));
+    MOCK_METHOD(ftl::Future<status_t>, setDisplayBrightness,
+                (PhysicalDisplayId, float, float, const Hwc2::Composer::DisplayBrightnessOptions&),
+                (override));
     MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*));
 
     MOCK_METHOD2(onHotplug,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index b907129..063726b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3218,15 +3218,15 @@
     // would not survive certain calls like Fence::merge() which would return a
     // new instance.
     EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_))
-            .WillOnce([&layer1Fence](std::shared_future<FenceResult> futureFenceResult) {
+            .WillOnce([&layer1Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
                 EXPECT_EQ(FenceResult(layer1Fence), futureFenceResult.get());
             });
     EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_))
-            .WillOnce([&layer2Fence](std::shared_future<FenceResult> futureFenceResult) {
+            .WillOnce([&layer2Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
                 EXPECT_EQ(FenceResult(layer2Fence), futureFenceResult.get());
             });
     EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_))
-            .WillOnce([&layer3Fence](std::shared_future<FenceResult> futureFenceResult) {
+            .WillOnce([&layer3Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
                 EXPECT_EQ(FenceResult(layer3Fence), futureFenceResult.get());
             });
 
@@ -3285,15 +3285,15 @@
 
     // Each released layer should be given the presentFence.
     EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_))
-            .WillOnce([&presentFence](std::shared_future<FenceResult> futureFenceResult) {
+            .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
                 EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
             });
     EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_))
-            .WillOnce([&presentFence](std::shared_future<FenceResult> futureFenceResult) {
+            .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
                 EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
             });
     EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_))
-            .WillOnce([&presentFence](std::shared_future<FenceResult> futureFenceResult) {
+            .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
                 EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
             });
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 96c28c9..50e3a28 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -1340,14 +1340,14 @@
     EXPECT_NE(nullptr, overrideBuffer4);
 }
 
-TEST_F(FlattenerTest, flattenLayers_skips_DISPLAY_DECORATION) {
+TEST_F(FlattenerTest, flattenLayers_includes_DISPLAY_DECORATION) {
     auto& layerState1 = mTestLayers[0]->layerState;
     const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
 
     auto& layerState2 = mTestLayers[1]->layerState;
     const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer;
 
-    // The third layer uses DISPLAY_DECORATION, which should never be cached.
+    // The third layer uses DISPLAY_DECORATION, which should be cached.
     auto& layerState3 = mTestLayers[2]->layerState;
     const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
     mTestLayers[2]->layerFECompositionState.compositionType =
@@ -1388,7 +1388,7 @@
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
-    EXPECT_EQ(nullptr, overrideBuffer3);
+    EXPECT_EQ(overrideBuffer1, overrideBuffer3);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index adf4be3..c52e96d 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -27,7 +27,6 @@
 #include "HWC2.h"
 
 #include <android/configuration.h>
-#include <ftl/future.h>
 #include <ui/Fence.h>
 #include <ui/FloatRect.h>
 #include <ui/GraphicBuffer.h>
@@ -543,7 +542,7 @@
     return error;
 }
 
-std::future<Error> Display::setDisplayBrightness(
+ftl::Future<Error> Display::setDisplayBrightness(
         float brightness, float brightnessNits,
         const Hwc2::Composer::DisplayBrightnessOptions& options) {
     return ftl::defer([composer = &mComposer, id = mId, brightness, brightnessNits, options] {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index cca20bd..24aef9b 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -18,6 +18,7 @@
 
 #include <android-base/expected.h>
 #include <android-base/thread_annotations.h>
+#include <ftl/future.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
 #include <ui/HdrCapabilities.h>
@@ -28,7 +29,6 @@
 #include <utils/Timers.h>
 
 #include <functional>
-#include <future>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
@@ -147,7 +147,7 @@
                                                        uint32_t* outNumRequests,
                                                        android::sp<android::Fence>* outPresentFence,
                                                        uint32_t* state) = 0;
-    [[nodiscard]] virtual std::future<hal::Error> setDisplayBrightness(
+    [[nodiscard]] virtual ftl::Future<hal::Error> setDisplayBrightness(
             float brightness, float brightnessNits,
             const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
     [[nodiscard]] virtual hal::Error setActiveConfigWithConstraints(
@@ -229,7 +229,7 @@
                                  uint32_t* outNumRequests,
                                  android::sp<android::Fence>* outPresentFence,
                                  uint32_t* state) override;
-    std::future<hal::Error> setDisplayBrightness(
+    ftl::Future<hal::Error> setDisplayBrightness(
             float brightness, float brightnessNits,
             const Hwc2::Composer::DisplayBrightnessOptions& options) override;
     hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 79e4c75..0da8ece 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -30,7 +30,6 @@
 #include <compositionengine/Output.h>
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
-#include <ftl/future.h>
 #include <log/log.h>
 #include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
@@ -720,13 +719,13 @@
     return NO_ERROR;
 }
 
-std::future<status_t> HWComposer::setDisplayBrightness(
+ftl::Future<status_t> HWComposer::setDisplayBrightness(
         PhysicalDisplayId displayId, float brightness, float brightnessNits,
         const Hwc2::Composer::DisplayBrightnessOptions& options) {
     RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX));
     auto& display = mDisplayData[displayId].hwcDisplay;
 
-    return ftl::chain(display->setDisplayBrightness(brightness, brightnessNits, options))
+    return display->setDisplayBrightness(brightness, brightnessNits, options)
             .then([displayId](hal::Error error) -> status_t {
                 if (error == hal::Error::UNSUPPORTED) {
                     RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 7dc10ea..4c0ecd8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -17,7 +17,6 @@
 #pragma once
 
 #include <cstdint>
-#include <future>
 #include <memory>
 #include <mutex>
 #include <optional>
@@ -26,6 +25,7 @@
 #include <vector>
 
 #include <android-base/thread_annotations.h>
+#include <ftl/future.h>
 #include <ui/DisplayIdentification.h>
 #include <ui/FenceTime.h>
 
@@ -195,7 +195,7 @@
                                                DisplayedFrameStats* outStats) = 0;
 
     // Sets the brightness of a display.
-    virtual std::future<status_t> setDisplayBrightness(
+    virtual ftl::Future<status_t> setDisplayBrightness(
             PhysicalDisplayId, float brightness, float brightnessNits,
             const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
 
@@ -372,7 +372,7 @@
                                               uint64_t maxFrames) override;
     status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp,
                                        DisplayedFrameStats* outStats) override;
-    std::future<status_t> setDisplayBrightness(
+    ftl::Future<status_t> setDisplayBrightness(
             PhysicalDisplayId, float brightness, float brightnessNits,
             const Hwc2::Composer::DisplayBrightnessOptions&) override;
 
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index bfdf667..b5678b4 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -64,9 +64,10 @@
 PowerAdvisor::~PowerAdvisor() = default;
 
 namespace {
-int32_t getUpdateTimeout() {
+std::chrono::milliseconds getUpdateTimeout() {
     // Default to a timeout of 80ms if nothing else is specified
-    static int32_t timeout = sysprop::display_update_imminent_timeout_ms(80);
+    static std::chrono::milliseconds timeout =
+            std::chrono::milliseconds(sysprop::display_update_imminent_timeout_ms(80));
     return timeout;
 }
 
@@ -81,21 +82,23 @@
 } // namespace
 
 PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) : mFlinger(flinger) {
-    if (getUpdateTimeout()) {
-        mScreenUpdateTimer.emplace("UpdateImminentTimer",
-                                   OneShotTimer::Interval(getUpdateTimeout()),
+    if (getUpdateTimeout() > 0ms) {
+        mScreenUpdateTimer.emplace("UpdateImminentTimer", getUpdateTimeout(),
                                    /* resetCallback */ nullptr,
                                    /* timeoutCallback */
                                    [this] {
-                                       const nsecs_t timeSinceLastUpdate =
-                                               systemTime() - mLastScreenUpdatedTime.load();
-                                       if (timeSinceLastUpdate < getUpdateTimeout()) {
+                                       while (true) {
+                                           auto timeSinceLastUpdate = std::chrono::nanoseconds(
+                                                   systemTime() - mLastScreenUpdatedTime.load());
+                                           if (timeSinceLastUpdate >= getUpdateTimeout()) {
+                                               break;
+                                           }
                                            // We may try to disable expensive rendering and allow
                                            // for sending DISPLAY_UPDATE_IMMINENT hints too early if
                                            // we idled very shortly after updating the screen, so
                                            // make sure we wait enough time.
-                                           std::this_thread::sleep_for(std::chrono::nanoseconds(
-                                                   getUpdateTimeout() - timeSinceLastUpdate));
+                                           std::this_thread::sleep_for(getUpdateTimeout() -
+                                                                       timeSinceLastUpdate);
                                        }
                                        mSendUpdateImminent.store(true);
                                        mFlinger.disableExpensiveRendering();
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 39686e0..b1de966 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -211,7 +211,7 @@
  * Layer.  So, the implementation is done in BufferLayer.  When called on a
  * EffectLayer object, it's essentially a NOP.
  */
-void Layer::onLayerDisplayed(std::shared_future<FenceResult>) {}
+void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult>) {}
 
 void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
     if (mDrawingState.zOrderRelativeOf == nullptr) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ca46abc..3988e51 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -616,7 +616,7 @@
     void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
     std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
             compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
-    void onLayerDisplayed(std::shared_future<FenceResult>) override;
+    void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
 
     void setWasClientComposed(const sp<Fence>& fence) override {
         mLastClientCompositionFence = fence;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 787ccd7..97d8aef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1693,7 +1693,7 @@
     }
 
     const char* const whence = __func__;
-    return ftl::chain(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
+    return ftl::Future(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
                if (const auto display = getDisplayDeviceLocked(displayToken)) {
                    const bool supportsDisplayBrightnessCommand =
                            getHwComposer().getComposer()->isSupported(
@@ -1731,7 +1731,7 @@
                    return ftl::yield<status_t>(NAME_NOT_FOUND);
                }
            }))
-            .then([](std::future<status_t> task) { return task; })
+            .then([](ftl::Future<status_t> task) { return task; })
             .get();
 }
 
@@ -3226,12 +3226,12 @@
     if (!updateWindowInfo && mInputWindowCommands.empty()) {
         return;
     }
-    BackgroundExecutor::getInstance().execute([updateWindowInfo,
-                                               windowInfos = std::move(windowInfos),
-                                               displayInfos = std::move(displayInfos),
-                                               inputWindowCommands =
-                                                       std::move(mInputWindowCommands),
-                                               inputFlinger = mInputFlinger, this]() {
+    BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo,
+                                                      windowInfos = std::move(windowInfos),
+                                                      displayInfos = std::move(displayInfos),
+                                                      inputWindowCommands =
+                                                              std::move(mInputWindowCommands),
+                                                      inputFlinger = mInputFlinger, this]() {
         ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
         if (updateWindowInfo) {
             mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
@@ -3244,7 +3244,7 @@
         for (const auto& focusRequest : inputWindowCommands.focusRequests) {
             inputFlinger->setFocusedWindow(focusRequest);
         }
-    });
+    }});
 
     mInputWindowCommands.clear();
 }
@@ -6578,7 +6578,7 @@
     return fenceStatus(future.get());
 }
 
-std::shared_future<FenceResult> SurfaceFlinger::captureScreenCommon(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
         RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
         ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale,
         const sp<IScreenCaptureListener>& captureListener) {
@@ -6630,7 +6630,7 @@
                                false /* regionSampling */, grayscale, captureListener);
 }
 
-std::shared_future<FenceResult> SurfaceFlinger::captureScreenCommon(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
         RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
         const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
         bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
@@ -6639,7 +6639,7 @@
     bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
 
     auto future = mScheduler->schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable
-                                       -> std::shared_future<FenceResult> {
+                                       -> ftl::SharedFuture<FenceResult> {
         ScreenCaptureResults captureResults;
         std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
         if (!renderArea) {
@@ -6649,7 +6649,7 @@
             return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
         }
 
-        std::shared_future<FenceResult> renderFuture;
+        ftl::SharedFuture<FenceResult> renderFuture;
         renderArea->render([&] {
             renderFuture =
                     renderScreenImpl(*renderArea, traverseLayers, buffer, canCaptureBlackoutContent,
@@ -6676,15 +6676,14 @@
     }
 
     // Flatten nested futures.
-    std::future<FenceResult> chain =
-            ftl::chain(std::move(future)).then([](std::shared_future<FenceResult> future) {
-                return future.get();
-            });
+    auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture<FenceResult> future) {
+        return future;
+    });
 
     return chain.share();
 }
 
-std::shared_future<FenceResult> SurfaceFlinger::renderScreenImpl(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
         const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
         const std::shared_ptr<renderengine::ExternalTexture>& buffer,
         bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
@@ -6825,10 +6824,10 @@
     getRenderEngine().useProtectedContext(useProtected);
 
     constexpr bool kUseFramebufferCache = false;
-    std::future<FenceResult> chain =
-            ftl::chain(getRenderEngine().drawLayers(clientCompositionDisplay,
-                                                    clientRenderEngineLayers, buffer,
-                                                    kUseFramebufferCache, std::move(bufferFence)))
+    auto chain =
+            ftl::Future(getRenderEngine().drawLayers(clientCompositionDisplay,
+                                                     clientRenderEngineLayers, buffer,
+                                                     kUseFramebufferCache, std::move(bufferFence)))
                     .then(&toFenceResult);
 
     const auto future = chain.share();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index aeaa01e..f14c755 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -27,6 +27,7 @@
 #include <android/gui/DisplayState.h>
 #include <cutils/atomic.h>
 #include <cutils/compiler.h>
+#include <ftl/future.h>
 #include <ftl/small_map.h>
 #include <gui/BufferQueue.h>
 #include <gui/FrameTimestamps.h>
@@ -77,7 +78,6 @@
 #include <atomic>
 #include <cstdint>
 #include <functional>
-#include <future>
 #include <map>
 #include <memory>
 #include <mutex>
@@ -395,7 +395,7 @@
     using VsyncModulator = scheduler::VsyncModulator;
     using TransactionSchedule = scheduler::TransactionSchedule;
     using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>;
-    using RenderAreaFuture = std::future<std::unique_ptr<RenderArea>>;
+    using RenderAreaFuture = ftl::Future<std::unique_ptr<RenderArea>>;
     using DumpArgs = Vector<String16>;
     using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>;
 
@@ -865,15 +865,15 @@
     // Boot animation, on/off animations and screen capture
     void startBootAnim();
 
-    std::shared_future<FenceResult> captureScreenCommon(RenderAreaFuture, TraverseLayersFunction,
-                                                        ui::Size bufferSize, ui::PixelFormat,
-                                                        bool allowProtected, bool grayscale,
-                                                        const sp<IScreenCaptureListener>&);
-    std::shared_future<FenceResult> captureScreenCommon(
+    ftl::SharedFuture<FenceResult> captureScreenCommon(RenderAreaFuture, TraverseLayersFunction,
+                                                       ui::Size bufferSize, ui::PixelFormat,
+                                                       bool allowProtected, bool grayscale,
+                                                       const sp<IScreenCaptureListener>&);
+    ftl::SharedFuture<FenceResult> captureScreenCommon(
             RenderAreaFuture, TraverseLayersFunction,
             const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
             bool grayscale, const sp<IScreenCaptureListener>&);
-    std::shared_future<FenceResult> renderScreenImpl(
+    ftl::SharedFuture<FenceResult> renderScreenImpl(
             const RenderArea&, TraverseLayersFunction,
             const std::shared_ptr<renderengine::ExternalTexture>&, bool canCaptureBlackoutContent,
             bool regionSampling, bool grayscale, ScreenCaptureResults&) EXCLUDES(mStateLock);
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index fa8cffc..d2c2e29 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -185,6 +185,7 @@
 void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) {
     // For each listener
     auto completedTransactionsItr = mCompletedTransactions.begin();
+    BackgroundExecutor::Callbacks callbacks;
     while (completedTransactionsItr != mCompletedTransactions.end()) {
         auto& [listener, transactionStatsDeque] = *completedTransactionsItr;
         ListenerStats listenerStats;
@@ -219,7 +220,7 @@
                 // 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.
-                BackgroundExecutor::getInstance().execute([stats = std::move(listenerStats)]() {
+                callbacks.emplace_back([stats = std::move(listenerStats)]() {
                     interface_cast<ITransactionCompletedListener>(stats.listener)
                             ->onTransactionCompleted(stats);
                 });
@@ -231,6 +232,8 @@
     if (mPresentFence) {
         mPresentFence.clear();
     }
+
+    BackgroundExecutor::getInstance().sendCallbacks(std::move(callbacks));
 }
 
 // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index b96444d..81d79f0 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -18,7 +18,6 @@
 
 #include <condition_variable>
 #include <deque>
-#include <future>
 #include <mutex>
 #include <queue>
 #include <thread>
@@ -26,9 +25,9 @@
 #include <unordered_set>
 
 #include <android-base/thread_annotations.h>
-
 #include <binder/IBinder.h>
 #include <compositionengine/FenceResult.h>
+#include <ftl/future.h>
 #include <gui/ITransactionCompletedListener.h>
 #include <ui/Fence.h>
 
@@ -46,7 +45,7 @@
     bool releasePreviousBuffer = false;
     std::string name;
     sp<Fence> previousReleaseFence;
-    std::vector<std::shared_future<FenceResult>> previousReleaseFences;
+    std::vector<ftl::SharedFuture<FenceResult>> previousReleaseFences;
     std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1;
     nsecs_t latchTime = -1;
     uint32_t transformHint = 0;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 3e0d6d3..07cd15d 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -80,7 +80,7 @@
     MOCK_METHOD(hal::Error, presentOrValidate,
                 (nsecs_t, uint32_t *, uint32_t *, android::sp<android::Fence> *, uint32_t *),
                 (override));
-    MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness,
+    MOCK_METHOD(ftl::Future<hal::Error>, setDisplayBrightness,
                 (float, float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
     MOCK_METHOD(hal::Error, setActiveConfigWithConstraints,
                 (hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &,