Merge "Plumb through dimming stage into RenderEngine."
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 1c3a4f2..13c09a3 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -179,6 +179,8 @@
     chmod 0666 /sys/kernel/tracing/events/clk/clk_enable/enable
     chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_set_rate/enable
     chmod 0666 /sys/kernel/tracing/events/clk/clk_set_rate/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/printk/console/enable
+    chmod 0666 /sys/kernel/tracing/events/printk/console/enable
 
     # disk
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 24b201f..890c15f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2733,8 +2733,8 @@
                                         const android::base::unique_fd& screenshot_fd_in,
                                         bool is_screenshot_requested) {
     // Duplicate the fds because the passed in fds don't outlive the binder transaction.
-    bugreport_fd.reset(dup(bugreport_fd_in.get()));
-    screenshot_fd.reset(dup(screenshot_fd_in.get()));
+    bugreport_fd.reset(fcntl(bugreport_fd_in.get(), F_DUPFD_CLOEXEC, 0));
+    screenshot_fd.reset(fcntl(screenshot_fd_in.get(), F_DUPFD_CLOEXEC, 0));
 
     SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested);
 }
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index c104fea..4e12579 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1176,6 +1176,25 @@
     return res;
 }
 
+binder::Status InstalldNativeService::deleteReferenceProfile(const std::string& packageName,
+                                                             const std::string& profileName) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    LOCK_PACKAGE();
+
+    // This function only supports primary dex'es.
+    std::string path =
+            create_reference_profile_path(packageName, profileName, /*is_secondary_dex=*/false);
+    if (unlink(path.c_str()) != 0) {
+        if (errno == ENOENT) {
+            return ok();
+        } else {
+            return error("Failed to delete profile " + profileName + " for " + packageName);
+        }
+    }
+    return ok();
+}
+
 binder::Status InstalldNativeService::destroyAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
     ENFORCE_UID(AID_SYSTEM);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 87a9206..0432222 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -140,6 +140,8 @@
             bool* _aidl_return);
     binder::Status clearAppProfiles(const std::string& packageName, const std::string& profileName);
     binder::Status destroyAppProfiles(const std::string& packageName);
+    binder::Status deleteReferenceProfile(const std::string& packageName,
+                                          const std::string& profileName);
 
     binder::Status createProfileSnapshot(int32_t appId, const std::string& packageName,
             const std::string& profileName, const std::string& classpath, bool* _aidl_return);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 79c02e8..db03411 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -82,6 +82,7 @@
             @utf8InCpp String packageName, @utf8InCpp String profileName);
     void clearAppProfiles(@utf8InCpp String packageName, @utf8InCpp String profileName);
     void destroyAppProfiles(@utf8InCpp String packageName);
+    void deleteReferenceProfile(@utf8InCpp String packageName, @utf8InCpp String profileName);
 
     boolean createProfileSnapshot(int appId, @utf8InCpp String packageName,
             @utf8InCpp String profileName, @utf8InCpp String classpath);
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 9801a9b..45aeab6 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -707,16 +707,16 @@
     auto temp_dir_path =
             base::StringPrintf("%s/%s", Dirname(pathname).c_str(), temp_dir_name.c_str());
 
-    if (::rename(pathname.c_str(), temp_dir_path.c_str())) {
+    auto dir_to_delete = temp_dir_path.c_str();
+    if (::rename(pathname.c_str(), dir_to_delete)) {
         if (ignore_if_missing && (errno == ENOENT)) {
             return 0;
         }
-        ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), temp_dir_path.c_str(),
-              strerror(errno));
-        return -errno;
+        ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), dir_to_delete, strerror(errno));
+        dir_to_delete = pathname.c_str();
     }
 
-    return delete_dir_contents(temp_dir_path.c_str(), 1, exclusion_predicate, ignore_if_missing);
+    return delete_dir_contents(dir_to_delete, 1, exclusion_predicate, ignore_if_missing);
 }
 
 bool is_renamed_deleted_dir(const std::string& path) {
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 4c83a14..ee392fc 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -235,7 +235,7 @@
  *
  * Available since API level 33.
  */
-int android_tag_socket_with_uid(int sockfd, int tag, uid_t uid) __INTRODUCED_IN(33);
+int android_tag_socket_with_uid(int sockfd, uint32_t tag, uid_t uid) __INTRODUCED_IN(33);
 
 /*
  * Set the socket tag for traffic statistics on the specified socket.
@@ -245,14 +245,26 @@
  * opened by another UID or was previously tagged by another UID. Subsequent
  * calls always replace any existing parameters. The socket tag is kept when the
  * socket is sent to another process using binder IPCs or other mechanisms such
- * as UNIX socket fd passing.
+ * as UNIX socket fd passing. The tag is a value defined by the caller and used
+ * together with uid for data traffic accounting, so that the function callers
+ * can account different types of data usage for a uid.
  *
  * Returns 0 on success, or a negative POSIX error code (see errno.h) on
  * failure.
  *
+ * Some possible error codes:
+ * -EBADF           Bad socketfd.
+ * -EPERM           No permission.
+ * -EAFNOSUPPORT    Socket family is neither AF_INET nor AF_INET6.
+ * -EPROTONOSUPPORT Socket protocol is neither IPPROTO_UDP nor IPPROTO_TCP.
+ * -EMFILE          Too many stats entries.
+ * There are still other error codes that may provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF maps read/write sys calls, which are set appropriately.
+ *
  * Available since API level 33.
  */
-int android_tag_socket(int sockfd, int tag) __INTRODUCED_IN(33);
+int android_tag_socket(int sockfd, uint32_t tag) __INTRODUCED_IN(33);
 
 /*
  * Untag a network socket.
@@ -267,6 +279,12 @@
  * Returns 0 on success, or a negative POSIX error code (see errno.h) on
  * failure.
  *
+ * One of possible error code:
+ * -EBADF           Bad socketfd.
+ * Other error codes are either provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF map element deletion sys call, which are set appropriately.
+ *
  * Available since API level 33.
  */
 int android_untag_socket(int sockfd) __INTRODUCED_IN(33);
diff --git a/include/ftl/enum.h b/include/ftl/enum.h
index 5234c05..82af1d6 100644
--- a/include/ftl/enum.h
+++ b/include/ftl/enum.h
@@ -261,10 +261,10 @@
   const auto value = to_underlying(v);
 
   // TODO: Replace with std::popcount and std::countr_zero in C++20.
-  if (__builtin_popcountl(value) != 1) return {};
+  if (__builtin_popcountll(value) != 1) return {};
 
   constexpr auto kRange = details::EnumRange<E, details::FlagName>{};
-  return kRange.values[__builtin_ctzl(value)];
+  return kRange.values[__builtin_ctzll(value)];
 }
 
 // Returns a stringified enumerator, or its integral value if not named.
diff --git a/include/ftl/fake_guard.h b/include/ftl/fake_guard.h
new file mode 100644
index 0000000..bacd1b2
--- /dev/null
+++ b/include/ftl/fake_guard.h
@@ -0,0 +1,90 @@
+/*
+ * 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
+
+#define FTL_ATTRIBUTE(a) __attribute__((a))
+
+namespace android::ftl {
+
+// Granular alternative to [[clang::no_thread_safety_analysis]]. Given a std::mutex-like object,
+// FakeGuard suppresses enforcement of thread-safe access to guarded variables within its scope.
+// While FakeGuard is scoped to a block, there are macro shorthands for a single expression, as
+// well as function/lambda scope (though calls must be indirect, e.g. virtual or std::function):
+//
+//   struct {
+//     std::mutex mutex;
+//     int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1;
+//
+//     int f() {
+//       {
+//         ftl::FakeGuard guard(mutex);
+//         x = 0;
+//       }
+//
+//       return FTL_FAKE_GUARD(mutex, x + 1);
+//     }
+//
+//      std::function<int()> g() const {
+//        return [this]() FTL_FAKE_GUARD(mutex) { return x; };
+//      }
+//   } s;
+//
+//   assert(s.f() == 1);
+//   assert(s.g()() == 0);
+//
+// An example of a situation where FakeGuard helps is a mutex that guards writes on Thread 1, and
+// reads on Thread 2. Reads on Thread 1, which is the only writer, need not be under lock, so can
+// use FakeGuard to appease the thread safety analyzer. Another example is enforcing and documenting
+// exclusive access by a single thread. This is done by defining a global constant that represents a
+// thread context, and annotating guarded variables as if it were a mutex (though without any effect
+// at run time):
+//
+//   constexpr class [[clang::capability("mutex")]] {
+//   } kMainThreadContext;
+//
+template <typename Mutex>
+struct [[clang::scoped_lockable]] FakeGuard final {
+  explicit FakeGuard(const Mutex& mutex) FTL_ATTRIBUTE(acquire_capability(mutex)) {}
+  [[clang::release_capability()]] ~FakeGuard() {}
+
+  FakeGuard(const FakeGuard&) = delete;
+  FakeGuard& operator=(const FakeGuard&) = delete;
+};
+
+}  // namespace android::ftl
+
+// TODO: Enable in C++23 once standard attributes can be used on lambdas.
+#if 0
+#define FTL_FAKE_GUARD1(mutex) [[using clang: acquire_capability(mutex), release_capability(mutex)]]
+#else
+#define FTL_FAKE_GUARD1(mutex)             \
+  FTL_ATTRIBUTE(acquire_capability(mutex)) \
+  FTL_ATTRIBUTE(release_capability(mutex))
+#endif
+
+// The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
+#define FTL_FAKE_GUARD2(mutex, expr)            \
+  [&]() -> decltype(auto) {                     \
+    const android::ftl::FakeGuard guard(mutex); \
+    return (expr);                              \
+  }()
+
+#define FTL_MAKE_FAKE_GUARD(arg1, arg2, guard, ...) guard
+
+// The void argument suppresses a warning about zero variadic macro arguments.
+#define FTL_FAKE_GUARD(...) \
+  FTL_MAKE_FAKE_GUARD(__VA_ARGS__, FTL_FAKE_GUARD2, FTL_FAKE_GUARD1, void)(__VA_ARGS__)
diff --git a/include/ftl/Flags.h b/include/ftl/flags.h
similarity index 81%
rename from include/ftl/Flags.h
rename to include/ftl/flags.h
index 708eaf5..70aaa0e 100644
--- a/include/ftl/Flags.h
+++ b/include/ftl/flags.h
@@ -19,16 +19,15 @@
 #include <ftl/enum.h>
 #include <ftl/string.h>
 
+#include <bitset>
 #include <cstdint>
 #include <iterator>
 #include <string>
 #include <type_traits>
 
-#include "utils/BitSet.h"
+// TODO(b/185536303): Align with FTL style.
 
-// TODO(b/185536303): Align with FTL style and namespace.
-
-namespace android {
+namespace android::ftl {
 
 /* A class for handling flags defined by an enum or enum class in a type-safe way. */
 template <typename F>
@@ -49,28 +48,29 @@
     // should force them to be explicitly constructed from their underlying types to make full use
     // of the type checker.
     template <typename T = U>
-    constexpr Flags(T t, std::enable_if_t<!ftl::is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {}
+    constexpr Flags(T t, std::enable_if_t<!is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {}
 
     template <typename T = U>
-    explicit constexpr Flags(T t, std::enable_if_t<ftl::is_scoped_enum_v<F>, T>* = nullptr)
+    explicit constexpr Flags(T t, std::enable_if_t<is_scoped_enum_v<F>, T>* = nullptr)
           : mFlags(t) {}
 
     class Iterator {
-        // The type can't be larger than 64-bits otherwise it won't fit in BitSet64.
-        static_assert(sizeof(U) <= sizeof(uint64_t));
+        using Bits = std::uint64_t;
+        static_assert(sizeof(U) <= sizeof(Bits));
 
     public:
+        constexpr Iterator() = default;
         Iterator(Flags<F> flags) : mRemainingFlags(flags.mFlags) { (*this)++; }
-        Iterator() : mRemainingFlags(0), mCurrFlag(static_cast<F>(0)) {}
 
         // Pre-fix ++
         Iterator& operator++() {
-            if (mRemainingFlags.isEmpty()) {
-                mCurrFlag = static_cast<F>(0);
+            if (mRemainingFlags.none()) {
+                mCurrFlag = 0;
             } else {
-                uint64_t bit = mRemainingFlags.clearLastMarkedBit(); // counts from left
-                const U flag = 1 << (64 - bit - 1);
-                mCurrFlag = static_cast<F>(flag);
+                // TODO: Replace with std::countr_zero in C++20.
+                const Bits bit = static_cast<Bits>(__builtin_ctzll(mRemainingFlags.to_ullong()));
+                mRemainingFlags.reset(static_cast<std::size_t>(bit));
+                mCurrFlag = static_cast<U>(static_cast<Bits>(1) << bit);
             }
             return *this;
         }
@@ -88,7 +88,7 @@
 
         bool operator!=(Iterator other) const { return !(*this == other); }
 
-        F operator*() { return mCurrFlag; }
+        F operator*() const { return F{mCurrFlag}; }
 
         // iterator traits
 
@@ -107,8 +107,8 @@
         using pointer = void;
 
     private:
-        BitSet64 mRemainingFlags;
-        F mCurrFlag;
+        std::bitset<sizeof(Bits) * 8> mRemainingFlags;
+        U mCurrFlag = 0;
     };
 
     /*
@@ -175,7 +175,7 @@
         bool first = true;
         U unstringified = 0;
         for (const F f : *this) {
-            if (const auto flagName = ftl::flag_name(f)) {
+            if (const auto flagName = flag_name(f)) {
                 appendFlag(result, flagName.value(), first);
             } else {
                 unstringified |= static_cast<U>(f);
@@ -183,8 +183,8 @@
         }
 
         if (unstringified != 0) {
-            constexpr auto radix = sizeof(U) == 1 ? ftl::Radix::kBin : ftl::Radix::kHex;
-            appendFlag(result, ftl::to_string(unstringified, radix), first);
+            constexpr auto radix = sizeof(U) == 1 ? Radix::kBin : Radix::kHex;
+            appendFlag(result, to_string(unstringified, radix), first);
         }
 
         if (first) {
@@ -211,15 +211,15 @@
 // as flags. In order to use these, add them via a `using namespace` declaration.
 namespace flag_operators {
 
-template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>>
+template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>>
 inline Flags<F> operator~(F f) {
-    return static_cast<F>(~ftl::to_underlying(f));
+    return static_cast<F>(~to_underlying(f));
 }
 
-template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>>
+template <typename F, typename = std::enable_if_t<is_scoped_enum_v<F>>>
 Flags<F> operator|(F lhs, F rhs) {
-    return static_cast<F>(ftl::to_underlying(lhs) | ftl::to_underlying(rhs));
+    return static_cast<F>(to_underlying(lhs) | to_underlying(rhs));
 }
 
 } // namespace flag_operators
-} // namespace android
+} // namespace android::ftl
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
new file mode 100644
index 0000000..7c3b29b
--- /dev/null
+++ b/include/input/PrintTools.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 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
+
+#include <map>
+#include <set>
+#include <string>
+
+namespace android {
+
+template <typename T>
+std::string constToString(const T& v) {
+    return std::to_string(v);
+}
+
+/**
+ * Convert a set of integral types to string.
+ */
+template <typename T>
+std::string dumpSet(const std::set<T>& v, std::string (*toString)(const T&) = constToString) {
+    std::string out;
+    for (const T& entry : v) {
+        out += out.empty() ? "{" : ", ";
+        out += toString(entry);
+    }
+    return out.empty() ? "{}" : (out + "}");
+}
+
+/**
+ * Convert a map to string. Both keys and values of the map should be integral type.
+ */
+template <typename K, typename V>
+std::string dumpMap(const std::map<K, V>& map, std::string (*keyToString)(const K&) = constToString,
+                    std::string (*valueToString)(const V&) = constToString) {
+    std::string out;
+    for (const auto& [k, v] : map) {
+        if (!out.empty()) {
+            out += "\n";
+        }
+        out += keyToString(k) + ":" + valueToString(v);
+    }
+    return out;
+}
+
+const char* toString(bool value);
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 01b25d3..39befbe 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -582,6 +582,10 @@
 
 BBinder::~BBinder()
 {
+    if (!wasParceled() && getExtension()) {
+        ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+    }
+
     Extras* e = mExtras.load(std::memory_order_relaxed);
     if (e) delete e;
 }
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
index a1b08db..d952dc7 100644
--- a/libs/binder/IUidObserver.cpp
+++ b/libs/binder/IUidObserver.cpp
@@ -57,8 +57,7 @@
     }
 
     virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
-            int32_t capability)
-    {
+                                   int32_t capability) {
         Parcel data, reply;
         data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
         data.writeInt32((int32_t) uid);
@@ -67,6 +66,12 @@
         data.writeInt32(capability);
         remote()->transact(ON_UID_STATE_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual void onUidProcAdjChanged(uid_t uid) {
+        Parcel data, reply;
+        data.writeInt32((int32_t)uid);
+        remote()->transact(ON_UID_PROC_ADJ_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 // ----------------------------------------------------------------------
@@ -102,6 +107,7 @@
             onUidIdle(uid, disabled);
             return NO_ERROR;
         } break;
+
         case ON_UID_STATE_CHANGED_TRANSACTION: {
             CHECK_INTERFACE(IUidObserver, data, reply);
             uid_t uid = data.readInt32();
@@ -111,6 +117,14 @@
             onUidStateChanged(uid, procState, procStateSeq, capability);
             return NO_ERROR;
         } break;
+
+        case ON_UID_PROC_ADJ_CHANGED_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            onUidProcAdjChanged(uid);
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index be50a75..58b0b35 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1584,6 +1584,7 @@
 template<class T>
 status_t Parcel::readAligned(T *pArg) const {
     static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+    static_assert(std::is_trivially_copyable_v<T>);
 
     if ((mDataPos+sizeof(T)) <= mDataSize) {
         if (mObjectsSize > 0) {
@@ -1595,9 +1596,8 @@
             }
         }
 
-        const void* data = mData+mDataPos;
+        memcpy(pArg, mData + mDataPos, sizeof(T));
         mDataPos += sizeof(T);
-        *pArg =  *reinterpret_cast<const T*>(data);
         return NO_ERROR;
     } else {
         return NOT_ENOUGH_DATA;
@@ -1617,10 +1617,11 @@
 template<class T>
 status_t Parcel::writeAligned(T val) {
     static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+    static_assert(std::is_trivially_copyable_v<T>);
 
     if ((mDataPos+sizeof(val)) <= mDataCapacity) {
 restart_write:
-        *reinterpret_cast<T*>(mData+mDataPos) = val;
+        memcpy(mData + mDataPos, &val, sizeof(val));
         return finishWrite(sizeof(val));
     }
 
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 2e7084e..6d89064 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -313,7 +313,8 @@
                            const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs,
                            const std::function<status_t()>& altPoll) {
     for (int i = 0; i < niovs; i++) {
-        LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+        LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s",
+                       what, i + 1, niovs, connection->rpcTransport.get(),
                        android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
     }
 
@@ -343,7 +344,8 @@
     }
 
     for (int i = 0; i < niovs; i++) {
-        LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+        LOG_RPC_DETAIL("Received %s (part %d of %d) on RpcTransport %p: %s",
+                       what, i + 1, niovs, connection->rpcTransport.get(),
                        android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
     }
     return OK;
@@ -660,8 +662,14 @@
 status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
                                  const sp<RpcSession>& session, CommandType type) {
     uint8_t buf;
-    while (connection->rpcTransport->peek(&buf, sizeof(buf)).value_or(0) > 0) {
-        status_t status = getAndExecuteCommand(connection, session, type);
+    while (true) {
+        size_t num_bytes;
+        status_t status = connection->rpcTransport->peek(&buf, sizeof(buf), &num_bytes);
+        if (status == WOULD_BLOCK) break;
+        if (status != OK) return status;
+        if (!num_bytes) break;
+
+        status = getAndExecuteCommand(connection, session, type);
         if (status != OK) return status;
     }
     return OK;
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 636e5d0..7cfc780 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -24,9 +24,6 @@
 #include "FdTrigger.h"
 #include "RpcState.h"
 
-using android::base::ErrnoError;
-using android::base::Result;
-
 namespace android {
 
 namespace {
@@ -35,12 +32,20 @@
 class RpcTransportRaw : public RpcTransport {
 public:
     explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
-    Result<size_t> peek(void *buf, size_t size) override {
+    status_t peek(void* buf, size_t size, size_t* out_size) override {
         ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_PEEK));
         if (ret < 0) {
-            return ErrnoError() << "recv(MSG_PEEK)";
+            int savedErrno = errno;
+            if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
+                return WOULD_BLOCK;
+            }
+
+            LOG_RPC_DETAIL("RpcTransport peek(): %s", strerror(savedErrno));
+            return -savedErrno;
         }
-        return ret;
+
+        *out_size = static_cast<size_t>(ret);
+        return OK;
     }
 
     template <typename SendOrReceive>
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index 3936204..bc68c37 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -37,10 +37,6 @@
 #define LOG_TLS_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
 #endif
 
-using android::base::ErrnoError;
-using android::base::Error;
-using android::base::Result;
-
 namespace android {
 namespace {
 
@@ -165,17 +161,8 @@
         return ret;
     }
 
-    // |sslError| should be from Ssl::getError().
-    // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
-    // return error. Also return error if |fdTrigger| is triggered before or during poll().
-    status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
-                             const char* fnString, int additionalEvent,
-                             const std::function<status_t()>& altPoll) {
+    status_t toStatus(int sslError, const char* fnString) {
         switch (sslError) {
-            case SSL_ERROR_WANT_READ:
-                return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
-            case SSL_ERROR_WANT_WRITE:
-                return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
             case SSL_ERROR_SYSCALL: {
                 auto queue = toString();
                 LOG_TLS_DETAIL("%s(): %s. Treating as DEAD_OBJECT. Error queue: %s", fnString,
@@ -191,6 +178,22 @@
         }
     }
 
+    // |sslError| should be from Ssl::getError().
+    // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
+    // return error. Also return error if |fdTrigger| is triggered before or during poll().
+    status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
+                             const char* fnString, int additionalEvent,
+                             const std::function<status_t()>& altPoll) {
+        switch (sslError) {
+            case SSL_ERROR_WANT_READ:
+                return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
+            case SSL_ERROR_WANT_WRITE:
+                return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
+            default:
+                return toStatus(sslError, fnString);
+        }
+    }
+
 private:
     bool mHandled = false;
 
@@ -274,7 +277,7 @@
 public:
     RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
           : mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
-    Result<size_t> peek(void* buf, size_t size) override;
+    status_t peek(void* buf, size_t size, size_t* out_size) override;
     status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
                                      const std::function<status_t()>& altPoll) override;
     status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
@@ -286,7 +289,7 @@
 };
 
 // Error code is errno.
-Result<size_t> RpcTransportTls::peek(void* buf, size_t size) {
+status_t RpcTransportTls::peek(void* buf, size_t size, size_t* out_size) {
     size_t todo = std::min<size_t>(size, std::numeric_limits<int>::max());
     auto [ret, errorQueue] = mSsl.call(SSL_peek, buf, static_cast<int>(todo));
     if (ret < 0) {
@@ -294,13 +297,15 @@
         if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
             // Seen EAGAIN / EWOULDBLOCK on recv(2) / send(2).
             // Like RpcTransportRaw::peek(), don't handle it here.
-            return Error(EWOULDBLOCK) << "SSL_peek(): " << errorQueue.toString();
+            errorQueue.clear();
+            return WOULD_BLOCK;
         }
-        return Error() << "SSL_peek(): " << errorQueue.toString();
+        return errorQueue.toStatus(err, "SSL_peek");
     }
     errorQueue.clear();
     LOG_TLS_DETAIL("TLS: Peeked %d bytes!", ret);
-    return ret;
+    *out_size = static_cast<size_t>(ret);
+    return OK;
 }
 
 status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index ade2d94..751c4f9 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -22,7 +22,6 @@
 #include <memory>
 #include <string>
 
-#include <android-base/result.h>
 #include <android-base/unique_fd.h>
 #include <utils/Errors.h>
 
@@ -41,7 +40,7 @@
     virtual ~RpcTransport() = default;
 
     // replacement of ::recv(MSG_PEEK). Error code may not be set if TLS is enabled.
-    [[nodiscard]] virtual android::base::Result<size_t> peek(void *buf, size_t size) = 0;
+    [[nodiscard]] virtual status_t peek(void *buf, size_t size, size_t *out_size) = 0;
 
     /**
      * Read (or write), but allow to be interrupted by a trigger.
diff --git a/libs/binder/include_activitymanager/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h
index abc7f1d..5dfbd44 100644
--- a/libs/binder/include_activitymanager/binder/ActivityManager.h
+++ b/libs/binder/include_activitymanager/binder/ActivityManager.h
@@ -31,20 +31,21 @@
 class ActivityManager
 {
 public:
-
     enum {
         // Flag for registerUidObserver: report uid state changed
-        UID_OBSERVER_PROCSTATE = 1<<0,
+        UID_OBSERVER_PROCSTATE = 1 << 0,
         // Flag for registerUidObserver: report uid gone
-        UID_OBSERVER_GONE = 1<<1,
+        UID_OBSERVER_GONE = 1 << 1,
         // Flag for registerUidObserver: report uid has become idle
-        UID_OBSERVER_IDLE = 1<<2,
+        UID_OBSERVER_IDLE = 1 << 2,
         // Flag for registerUidObserver: report uid has become active
-        UID_OBSERVER_ACTIVE = 1<<3,
+        UID_OBSERVER_ACTIVE = 1 << 3,
         // Flag for registerUidObserver: report uid cached state has changed
-        UID_OBSERVER_CACHED = 1<<4,
+        UID_OBSERVER_CACHED = 1 << 4,
         // Flag for registerUidObserver: report uid capability has changed
-        UID_OBSERVER_CAPABILITY = 1<<5,
+        UID_OBSERVER_CAPABILITY = 1 << 5,
+        // Flag for registerUidObserver: report pid oom adj has changed
+        UID_OBSERVER_PROC_OOM_ADJ = 1 << 6,
     };
 
     // PROCESS_STATE_* must come from frameworks/base/core/java/android/app/ProcessStateEnum.aidl.
diff --git a/libs/binder/include_activitymanager/binder/IUidObserver.h b/libs/binder/include_activitymanager/binder/IUidObserver.h
index 9291c0b..17f03a9 100644
--- a/libs/binder/include_activitymanager/binder/IUidObserver.h
+++ b/libs/binder/include_activitymanager/binder/IUidObserver.h
@@ -33,13 +33,15 @@
     virtual void onUidActive(uid_t uid) = 0;
     virtual void onUidIdle(uid_t uid, bool disabled) = 0;
     virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
-            int32_t capability) = 0;
+                                   int32_t capability) = 0;
+    virtual void onUidProcAdjChanged(uid_t uid) = 0;
 
     enum {
         ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
         ON_UID_ACTIVE_TRANSACTION,
         ON_UID_IDLE_TRANSACTION,
-        ON_UID_STATE_CHANGED_TRANSACTION
+        ON_UID_STATE_CHANGED_TRANSACTION,
+        ON_UID_PROC_ADJ_CHANGED_TRANSACTION
     };
 };
 
diff --git a/libs/binder/tests/binderBinderUnitTest.cpp b/libs/binder/tests/binderBinderUnitTest.cpp
index 1be0c59..ce2770f 100644
--- a/libs/binder/tests/binderBinderUnitTest.cpp
+++ b/libs/binder/tests/binderBinderUnitTest.cpp
@@ -41,3 +41,10 @@
     EXPECT_EQ(kObject1, binder->detachObject(kObjectId1));
     EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject2, nullptr, nullptr));
 }
+
+TEST(Binder, AttachExtension) {
+    auto binder = sp<BBinder>::make();
+    auto ext = sp<BBinder>::make();
+    binder->setExtension(ext);
+    EXPECT_EQ(ext, binder->getExtension());
+}
diff --git a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
index 094addd..50d12c4 100644
--- a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
+++ b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
@@ -18,6 +18,7 @@
 
 #include <memory>
 #include <mutex>
+#include <vector>
 
 #include <binder/RpcAuth.h>
 #include <binder/RpcCertificateFormat.h>
diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp
index c5d3a32..5f145a1 100644
--- a/libs/bufferqueueconverter/Android.bp
+++ b/libs/bufferqueueconverter/Android.bp
@@ -22,6 +22,7 @@
     double_loadable: true,
 
     srcs: [
+        ":libgui_frame_event_aidl",
         "BufferQueueConverter.cpp",
     ],
 
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index bc2eb23..c010a2e 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -14,10 +14,11 @@
         address: true,
     },
     srcs: [
-        "Flags_test.cpp",
         "cast_test.cpp",
         "concat_test.cpp",
         "enum_test.cpp",
+        "fake_guard_test.cpp",
+        "flags_test.cpp",
         "future_test.cpp",
         "small_map_test.cpp",
         "small_vector_test.cpp",
@@ -29,13 +30,6 @@
         "-Werror",
         "-Wextra",
         "-Wpedantic",
-    ],
-
-    header_libs: [
-        "libbase_headers",
-    ],
-
-    shared_libs: [
-        "libbase",
+        "-Wthread-safety",
     ],
 }
diff --git a/libs/ftl/enum_test.cpp b/libs/ftl/enum_test.cpp
index d8ce7a5..5592a01 100644
--- a/libs/ftl/enum_test.cpp
+++ b/libs/ftl/enum_test.cpp
@@ -143,6 +143,16 @@
     EXPECT_EQ(ftl::flag_string(Flags::kNone), "0b0");
     EXPECT_EQ(ftl::flag_string(Flags::kMask), "0b10010010");
     EXPECT_EQ(ftl::flag_string(Flags::kAll), "0b11111111");
+
+    enum class Flags64 : std::uint64_t {
+      kFlag0 = 0b1ull,
+      kFlag63 = 0x8000'0000'0000'0000ull,
+      kMask = kFlag0 | kFlag63
+    };
+
+    EXPECT_EQ(ftl::flag_string(Flags64::kFlag0), "kFlag0");
+    EXPECT_EQ(ftl::flag_string(Flags64::kFlag63), "kFlag63");
+    EXPECT_EQ(ftl::flag_string(Flags64::kMask), "0x8000000000000001");
   }
   {
     EXPECT_EQ(ftl::enum_string(Planet::kEarth), "kEarth");
diff --git a/libs/ftl/fake_guard_test.cpp b/libs/ftl/fake_guard_test.cpp
new file mode 100644
index 0000000..9d36e69
--- /dev/null
+++ b/libs/ftl/fake_guard_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#include <ftl/fake_guard.h>
+#include <gtest/gtest.h>
+
+#include <functional>
+#include <mutex>
+
+namespace android::test {
+
+// Keep in sync with example usage in header file.
+TEST(FakeGuard, Example) {
+  struct {
+    std::mutex mutex;
+    int x FTL_ATTRIBUTE(guarded_by(mutex)) = -1;
+
+    int f() {
+      {
+        ftl::FakeGuard guard(mutex);
+        x = 0;
+      }
+
+      return FTL_FAKE_GUARD(mutex, x + 1);
+    }
+
+    std::function<int()> g() const {
+      return [this]() FTL_FAKE_GUARD(mutex) { return x; };
+    }
+  } s;
+
+  EXPECT_EQ(s.f(), 1);
+  EXPECT_EQ(s.g()(), 0);
+}
+
+}  // namespace android::test
diff --git a/libs/ftl/Flags_test.cpp b/libs/ftl/flags_test.cpp
similarity index 98%
rename from libs/ftl/Flags_test.cpp
rename to libs/ftl/flags_test.cpp
index d241fa2..eea052b 100644
--- a/libs/ftl/Flags_test.cpp
+++ b/libs/ftl/flags_test.cpp
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
+#include <ftl/flags.h>
 #include <gtest/gtest.h>
-#include <ftl/Flags.h>
 
 #include <type_traits>
 
 namespace android::test {
 
-using namespace android::flag_operators;
+using ftl::Flags;
+using namespace ftl::flag_operators;
 
 enum class TestFlags : uint8_t { ONE = 0x1, TWO = 0x2, THREE = 0x4 };
 
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index d634c58..6b64ac8 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -120,6 +120,12 @@
     path: "aidl/",
 }
 
+filegroup {
+    name: "libgui_frame_event_aidl",
+    srcs: ["aidl/android/gui/FrameEvent.aidl"],
+    path: "aidl/",
+}
+
 cc_library_static {
     name: "libgui_aidl_static",
     vendor_available: true,
@@ -405,6 +411,7 @@
     ],
 
     srcs: [
+        ":libgui_frame_event_aidl",
         "mock/GraphicBufferConsumer.cpp",
         "mock/GraphicBufferProducer.cpp",
     ],
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index c5de09a..a10a2f0 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -26,7 +26,6 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
-#include <gui/LayerDebugInfo.h>
 #include <gui/LayerState.h>
 #include <private/gui/ParcelUtils.h>
 #include <stdint.h>
@@ -159,49 +158,6 @@
         return result != 0;
     }
 
-    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override {
-        if (!outSupported) {
-            return UNEXPECTED_NULL;
-        }
-        outSupported->clear();
-
-        Parcel data, reply;
-
-        status_t err = data.writeInterfaceToken(
-                ISurfaceComposer::getInterfaceDescriptor());
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        err = remote()->transact(
-                BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS,
-                data, &reply);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        int32_t result = 0;
-        err = reply.readInt32(&result);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        if (result != NO_ERROR) {
-            return result;
-        }
-
-        std::vector<int32_t> supported;
-        err = reply.readInt32Vector(&supported);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        outSupported->reserve(supported.size());
-        for (int32_t s : supported) {
-            outSupported->push_back(static_cast<FrameEvent>(s));
-        }
-        return NO_ERROR;
-    }
-
     sp<IDisplayEventConnection> createDisplayEventConnection(
             VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) override {
         Parcel data, reply;
@@ -225,316 +181,6 @@
         return result;
     }
 
-    status_t getDynamicDisplayInfo(const sp<IBinder>& display,
-                                   ui::DynamicDisplayInfo* info) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO, data, &reply);
-        const status_t result = reply.readInt32();
-        if (result != NO_ERROR) return result;
-        return reply.read(*info);
-    }
-
-    status_t getDisplayNativePrimaries(const sp<IBinder>& display,
-                                       ui::DisplayPrimaries& primaries) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayNativePrimaries failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayNativePrimaries failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayNativePrimaries failed to transact: %d", result);
-            return result;
-        }
-        result = reply.readInt32();
-        if (result == NO_ERROR) {
-            memcpy(&primaries, reply.readInplace(sizeof(ui::DisplayPrimaries)),
-                    sizeof(ui::DisplayPrimaries));
-        }
-        return result;
-    }
-
-    status_t setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("setActiveColorMode failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = data.writeInt32(static_cast<int32_t>(colorMode));
-        if (result != NO_ERROR) {
-            ALOGE("setActiveColorMode failed to writeInt32: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_COLOR_MODE, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("setActiveColorMode failed to transact: %d", result);
-            return result;
-        }
-        return static_cast<status_t>(reply.readInt32());
-    }
-
-    status_t setBootDisplayMode(const sp<IBinder>& display,
-                                ui::DisplayModeId displayModeId) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("setBootDisplayMode failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("setBootDisplayMode failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = data.writeInt32(displayModeId);
-        if (result != NO_ERROR) {
-            ALOGE("setBootDisplayMode failed to writeIint32: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::SET_BOOT_DISPLAY_MODE, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("setBootDisplayMode failed to transact: %d", result);
-        }
-        return result;
-    }
-
-    status_t clearAnimationFrameStats() override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("clearAnimationFrameStats failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("clearAnimationFrameStats failed to transact: %d", result);
-            return result;
-        }
-        return reply.readInt32();
-    }
-
-    status_t getAnimationFrameStats(FrameStats* outStats) const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply);
-        reply.read(*outStats);
-        return reply.readInt32();
-    }
-
-    virtual status_t overrideHdrTypes(const sp<IBinder>& display,
-                                      const std::vector<ui::Hdr>& hdrTypes) {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeStrongBinder, display);
-
-        std::vector<int32_t> hdrTypesVector;
-        for (ui::Hdr i : hdrTypes) {
-            hdrTypesVector.push_back(static_cast<int32_t>(i));
-        }
-        SAFE_PARCEL(data.writeInt32Vector, hdrTypesVector);
-
-        status_t result = remote()->transact(BnSurfaceComposer::OVERRIDE_HDR_TYPES, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("overrideHdrTypes failed to transact: %d", result);
-            return result;
-        }
-        return result;
-    }
-
-    status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) {
-        Parcel data, reply;
-        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeInt32, atomId);
-
-        status_t err = remote()->transact(BnSurfaceComposer::ON_PULL_ATOM, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGE("onPullAtom failed to transact: %d", err);
-            return err;
-        }
-
-        int32_t size = 0;
-        SAFE_PARCEL(reply.readInt32, &size);
-        const void* dataPtr = reply.readInplace(size);
-        if (dataPtr == nullptr) {
-            return UNEXPECTED_NULL;
-        }
-        pulledData->assign((const char*)dataPtr, size);
-        SAFE_PARCEL(reply.readBool, success);
-        return NO_ERROR;
-    }
-
-    status_t enableVSyncInjections(bool enable) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("enableVSyncInjections failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeBool(enable);
-        if (result != NO_ERROR) {
-            ALOGE("enableVSyncInjections failed to writeBool: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS, data, &reply,
-                                    IBinder::FLAG_ONEWAY);
-        if (result != NO_ERROR) {
-            ALOGE("enableVSyncInjections failed to transact: %d", result);
-            return result;
-        }
-        return result;
-    }
-
-    status_t injectVSync(nsecs_t when) override {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("injectVSync failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeInt64(when);
-        if (result != NO_ERROR) {
-            ALOGE("injectVSync failed to writeInt64: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply,
-                                    IBinder::FLAG_ONEWAY);
-        if (result != NO_ERROR) {
-            ALOGE("injectVSync failed to transact: %d", result);
-            return result;
-        }
-        return result;
-    }
-
-    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override {
-        if (!outLayers) {
-            return UNEXPECTED_NULL;
-        }
-
-        Parcel data, reply;
-
-        status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        int32_t result = 0;
-        err = reply.readInt32(&result);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        if (result != NO_ERROR) {
-            return result;
-        }
-
-        outLayers->clear();
-        return reply.readParcelableVector(outLayers);
-    }
-
-    status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
-                                      ui::PixelFormat* defaultPixelFormat,
-                                      ui::Dataspace* wideColorGamutDataspace,
-                                      ui::PixelFormat* wideColorGamutPixelFormat) const override {
-        Parcel data, reply;
-        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = remote()->transact(BnSurfaceComposer::GET_COMPOSITION_PREFERENCE, data, &reply);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = static_cast<status_t>(reply.readInt32());
-        if (error == NO_ERROR) {
-            *defaultDataspace = static_cast<ui::Dataspace>(reply.readInt32());
-            *defaultPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
-            *wideColorGamutDataspace = static_cast<ui::Dataspace>(reply.readInt32());
-            *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
-        }
-        return error;
-    }
-
-    status_t getColorManagement(bool* outGetColorManagement) const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply);
-        bool result;
-        status_t err = reply.readBool(&result);
-        if (err == NO_ERROR) {
-            *outGetColorManagement = result;
-        }
-        return err;
-    }
-
-    status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
-                                                   ui::PixelFormat* outFormat,
-                                                   ui::Dataspace* outDataspace,
-                                                   uint8_t* outComponentMask) const override {
-        if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE;
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-
-        status_t error =
-                remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
-                                   data, &reply);
-        if (error != NO_ERROR) {
-            return error;
-        }
-
-        uint32_t value = 0;
-        error = reply.readUint32(&value);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        *outFormat = static_cast<ui::PixelFormat>(value);
-
-        error = reply.readUint32(&value);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        *outDataspace = static_cast<ui::Dataspace>(value);
-
-        error = reply.readUint32(&value);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        *outComponentMask = static_cast<uint8_t>(value);
-        return error;
-    }
-
-    status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
-                                              uint8_t componentMask, uint64_t maxFrames) override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        data.writeBool(enable);
-        data.writeByte(static_cast<int8_t>(componentMask));
-        data.writeUint64(maxFrames);
-        status_t result =
-                remote()->transact(BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED, data,
-                                   &reply);
-        return result;
-    }
-
     status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
                                        uint64_t timestamp,
                                        DisplayedFrameStats* outStats) const override {
@@ -574,18 +220,6 @@
         return result;
     }
 
-    status_t getProtectedContentSupport(bool* outSupported) const override {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        status_t error =
-                remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply);
-        if (error != NO_ERROR) {
-            return error;
-        }
-        error = reply.readBool(outSupported);
-        return error;
-    }
-
     status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
                                        const sp<IRegionSamplingListener>& listener) override {
         Parcel data, reply;
@@ -1103,25 +737,6 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case GET_SUPPORTED_FRAME_TIMESTAMPS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            std::vector<FrameEvent> supportedTimestamps;
-            status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
-            status_t err = reply->writeInt32(result);
-            if (err != NO_ERROR) {
-                return err;
-            }
-            if (result != NO_ERROR) {
-                return result;
-            }
-
-            std::vector<int32_t> supported;
-            supported.reserve(supportedTimestamps.size());
-            for (FrameEvent s : supportedTimestamps) {
-                supported.push_back(static_cast<int32_t>(s));
-            }
-            return reply->writeInt32Vector(supported);
-        }
         case CREATE_DISPLAY_EVENT_CONNECTION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32());
@@ -1133,195 +748,6 @@
             reply->writeStrongBinder(IInterface::asBinder(connection));
             return NO_ERROR;
         }
-        case GET_DYNAMIC_DISPLAY_INFO: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::DynamicDisplayInfo info;
-            const sp<IBinder> display = data.readStrongBinder();
-            const status_t result = getDynamicDisplayInfo(display, &info);
-            SAFE_PARCEL(reply->writeInt32, result);
-            if (result != NO_ERROR) return result;
-            SAFE_PARCEL(reply->write, info);
-            return NO_ERROR;
-        }
-        case GET_DISPLAY_NATIVE_PRIMARIES: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::DisplayPrimaries primaries;
-            sp<IBinder> display = nullptr;
-
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("getDisplayNativePrimaries failed to readStrongBinder: %d", result);
-                return result;
-            }
-
-            result = getDisplayNativePrimaries(display, primaries);
-            reply->writeInt32(result);
-            if (result == NO_ERROR) {
-                memcpy(reply->writeInplace(sizeof(ui::DisplayPrimaries)), &primaries,
-                        sizeof(ui::DisplayPrimaries));
-            }
-
-            return NO_ERROR;
-        }
-        case SET_ACTIVE_COLOR_MODE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("getActiveColorMode failed to readStrongBinder: %d", result);
-                return result;
-            }
-            int32_t colorModeInt = 0;
-            result = data.readInt32(&colorModeInt);
-            if (result != NO_ERROR) {
-                ALOGE("setActiveColorMode failed to readInt32: %d", result);
-                return result;
-            }
-            result = setActiveColorMode(display,
-                    static_cast<ColorMode>(colorModeInt));
-            result = reply->writeInt32(result);
-            return result;
-        }
-        case SET_BOOT_DISPLAY_MODE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("setBootDisplayMode failed to readStrongBinder: %d", result);
-                return result;
-            }
-            ui::DisplayModeId displayModeId;
-            result = data.readInt32(&displayModeId);
-            if (result != NO_ERROR) {
-                ALOGE("setBootDisplayMode failed to readInt32: %d", result);
-                return result;
-            }
-            return setBootDisplayMode(display, displayModeId);
-        }
-        case CLEAR_ANIMATION_FRAME_STATS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            status_t result = clearAnimationFrameStats();
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case GET_ANIMATION_FRAME_STATS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            FrameStats stats;
-            status_t result = getAnimationFrameStats(&stats);
-            reply->write(stats);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case ENABLE_VSYNC_INJECTIONS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            bool enable = false;
-            status_t result = data.readBool(&enable);
-            if (result != NO_ERROR) {
-                ALOGE("enableVSyncInjections failed to readBool: %d", result);
-                return result;
-            }
-            return enableVSyncInjections(enable);
-        }
-        case INJECT_VSYNC: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int64_t when = 0;
-            status_t result = data.readInt64(&when);
-            if (result != NO_ERROR) {
-                ALOGE("enableVSyncInjections failed to readInt64: %d", result);
-                return result;
-            }
-            return injectVSync(when);
-        }
-        case GET_LAYER_DEBUG_INFO: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            std::vector<LayerDebugInfo> outLayers;
-            status_t result = getLayerDebugInfo(&outLayers);
-            reply->writeInt32(result);
-            if (result == NO_ERROR)
-            {
-                result = reply->writeParcelableVector(outLayers);
-            }
-            return result;
-        }
-        case GET_COMPOSITION_PREFERENCE: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            ui::Dataspace defaultDataspace;
-            ui::PixelFormat defaultPixelFormat;
-            ui::Dataspace wideColorGamutDataspace;
-            ui::PixelFormat wideColorGamutPixelFormat;
-            status_t error =
-                    getCompositionPreference(&defaultDataspace, &defaultPixelFormat,
-                                             &wideColorGamutDataspace, &wideColorGamutPixelFormat);
-            reply->writeInt32(error);
-            if (error == NO_ERROR) {
-                reply->writeInt32(static_cast<int32_t>(defaultDataspace));
-                reply->writeInt32(static_cast<int32_t>(defaultPixelFormat));
-                reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
-                reply->writeInt32(static_cast<int32_t>(wideColorGamutPixelFormat));
-            }
-            return error;
-        }
-        case GET_COLOR_MANAGEMENT: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            bool result;
-            status_t error = getColorManagement(&result);
-            if (error == NO_ERROR) {
-                reply->writeBool(result);
-            }
-            return error;
-        }
-        case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
-            sp<IBinder> display = data.readStrongBinder();
-            ui::PixelFormat format;
-            ui::Dataspace dataspace;
-            uint8_t component = 0;
-            auto result =
-                    getDisplayedContentSamplingAttributes(display, &format, &dataspace, &component);
-            if (result == NO_ERROR) {
-                reply->writeUint32(static_cast<uint32_t>(format));
-                reply->writeUint32(static_cast<uint32_t>(dataspace));
-                reply->writeUint32(static_cast<uint32_t>(component));
-            }
-            return result;
-        }
-        case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
-            sp<IBinder> display = nullptr;
-            bool enable = false;
-            int8_t componentMask = 0;
-            uint64_t maxFrames = 0;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("setDisplayContentSamplingEnabled failure in reading Display token: %d",
-                      result);
-                return result;
-            }
-
-            result = data.readBool(&enable);
-            if (result != NO_ERROR) {
-                ALOGE("setDisplayContentSamplingEnabled failure in reading enable: %d", result);
-                return result;
-            }
-
-            result = data.readByte(static_cast<int8_t*>(&componentMask));
-            if (result != NO_ERROR) {
-                ALOGE("setDisplayContentSamplingEnabled failure in reading component mask: %d",
-                      result);
-                return result;
-            }
-
-            result = data.readUint64(&maxFrames);
-            if (result != NO_ERROR) {
-                ALOGE("setDisplayContentSamplingEnabled failure in reading max frames: %d", result);
-                return result;
-            }
-
-            return setDisplayContentSamplingEnabled(display, enable,
-                                                    static_cast<uint8_t>(componentMask), maxFrames);
-        }
         case GET_DISPLAYED_CONTENT_SAMPLE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
 
@@ -1352,15 +778,6 @@
             }
             return result;
         }
-        case GET_PROTECTED_CONTENT_SUPPORT: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            bool result;
-            status_t error = getProtectedContentSupport(&result);
-            if (error == NO_ERROR) {
-                reply->writeBool(result);
-            }
-            return error;
-        }
         case ADD_REGION_SAMPLING_LISTENER: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             Rect samplingArea;
@@ -1664,33 +1081,6 @@
             SAFE_PARCEL(reply->writeInt32, buffers);
             return NO_ERROR;
         }
-        case OVERRIDE_HDR_TYPES: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> display = nullptr;
-            SAFE_PARCEL(data.readStrongBinder, &display);
-
-            std::vector<int32_t> hdrTypes;
-            SAFE_PARCEL(data.readInt32Vector, &hdrTypes);
-
-            std::vector<ui::Hdr> hdrTypesVector;
-            for (int i : hdrTypes) {
-                hdrTypesVector.push_back(static_cast<ui::Hdr>(i));
-            }
-            return overrideHdrTypes(display, hdrTypesVector);
-        }
-        case ON_PULL_ATOM: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int32_t atomId = 0;
-            SAFE_PARCEL(data.readInt32, &atomId);
-
-            std::string pulledData;
-            bool success;
-            status_t err = onPullAtom(atomId, &pulledData, &success);
-            SAFE_PARCEL(reply->writeByteArray, pulledData.size(),
-                        reinterpret_cast<const uint8_t*>(pulledData.data()));
-            SAFE_PARCEL(reply->writeBool, success);
-            return err;
-        }
         case ADD_WINDOW_INFOS_LISTENER: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IWindowInfosListener> listener;
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index ea5fb29..15b2221 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -27,7 +27,7 @@
 
 #define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false)
 
-namespace android {
+namespace android::gui {
 
 status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const {
     RETURN_ON_ERROR(parcel->writeCString(mName.c_str()));
@@ -149,4 +149,4 @@
     return result;
 }
 
-} // android
+} // namespace android::gui
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 34db5b1..f7cd5c4 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -134,6 +134,7 @@
     SAFE_PARCEL(output.writeByte, changeFrameRateStrategy);
     SAFE_PARCEL(output.writeUint32, fixedTransformHint);
     SAFE_PARCEL(output.writeBool, autoRefresh);
+    SAFE_PARCEL(output.writeBool, dimmingEnabled);
 
     SAFE_PARCEL(output.writeUint32, blurRegions.size());
     for (auto region : blurRegions) {
@@ -243,6 +244,7 @@
     SAFE_PARCEL(input.readUint32, &tmpUint32);
     fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
     SAFE_PARCEL(input.readBool, &autoRefresh);
+    SAFE_PARCEL(input.readBool, &dimmingEnabled);
 
     uint32_t numRegions = 0;
     SAFE_PARCEL(input.readUint32, &numRegions);
@@ -598,6 +600,10 @@
         what |= eColorSpaceAgnosticChanged;
         colorSpaceAgnostic = other.colorSpaceAgnostic;
     }
+    if (other.what & eDimmingEnabledChanged) {
+        what |= eDimmingEnabledChanged;
+        dimmingEnabled = other.dimmingEnabled;
+    }
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
               "other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64,
@@ -815,7 +821,7 @@
 status_t BufferData::readFromParcel(const Parcel* input) {
     int32_t tmpInt32;
     SAFE_PARCEL(input->readInt32, &tmpInt32);
-    flags = Flags<BufferDataChange>(tmpInt32);
+    flags = ftl::Flags<BufferDataChange>(tmpInt32);
 
     bool tmpBool = false;
     SAFE_PARCEL(input->readBool, &tmpBool);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 0f0a5c8..a40837c 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -366,12 +366,13 @@
         return NAME_NOT_FOUND;
     }
 
-    ui::DynamicDisplayInfo info;
-    if (status_t err = composerService()->getDynamicDisplayInfo(display, &info); err != NO_ERROR) {
-        return err;
+    gui::DynamicDisplayInfo info;
+    if (binder::Status status = composerServiceAIDL()->getDynamicDisplayInfo(display, &info);
+        !status.isOk()) {
+        return status.transactionError();
     }
 
-    *supported = !info.hdrCapabilities.getSupportedHdrTypes().empty();
+    *supported = !info.hdrCapabilities.supportedHdrTypes.empty();
     return NO_ERROR;
 }
 
@@ -1101,6 +1102,17 @@
     *out = input;
 }
 
+void Surface::applyGrallocMetadataLocked(
+        android_native_buffer_t* buffer,
+        const IGraphicBufferProducer::QueueBufferInput& queueBufferInput) {
+    ATRACE_CALL();
+    auto& mapper = GraphicBufferMapper::get();
+    mapper.setDataspace(buffer->handle, static_cast<ui::Dataspace>(queueBufferInput.dataSpace));
+    mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086());
+    mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613());
+    mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus());
+}
+
 void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence,
         const IGraphicBufferProducer::QueueBufferOutput& output) {
     mDequeuedSlots.erase(slot);
@@ -1171,9 +1183,11 @@
     IGraphicBufferProducer::QueueBufferOutput output;
     IGraphicBufferProducer::QueueBufferInput input;
     getQueueBufferInputLocked(buffer, fenceFd, mTimestamp, &input);
+    applyGrallocMetadataLocked(buffer, input);
     sp<Fence> fence = input.fence;
 
     nsecs_t now = systemTime();
+
     status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
     mLastQueueDuration = systemTime() - now;
     if (err != OK)  {
@@ -1243,10 +1257,10 @@
     mQueriedSupportedTimestamps = true;
 
     std::vector<FrameEvent> supportedFrameTimestamps;
-    status_t err = composerService()->getSupportedFrameTimestamps(
-            &supportedFrameTimestamps);
+    binder::Status status =
+            composerServiceAIDL()->getSupportedFrameTimestamps(&supportedFrameTimestamps);
 
-    if (err != NO_ERROR) {
+    if (!status.isOk()) {
         return;
     }
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 23a94fc..ca48ce6 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1224,6 +1224,20 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDimmingEnabled(
+        const sp<SurfaceControl>& sc, bool dimmingEnabled) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eDimmingEnabledChanged;
+    s->dimmingEnabled = dimmingEnabled;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha(
         const sp<SurfaceControl>& sc, float alpha) {
     layer_state_t* s = getLayerState(sc);
@@ -2104,13 +2118,15 @@
 // ----------------------------------------------------------------------------
 
 status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    return sf->enableVSyncInjections(enable);
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+    binder::Status status = sf->enableVSyncInjections(enable);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::injectVSync(nsecs_t when) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    return sf->injectVSync(when);
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+    binder::Status status = sf->injectVSync(when);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
@@ -2173,8 +2189,53 @@
 }
 
 status_t SurfaceComposerClient::getDynamicDisplayInfo(const sp<IBinder>& display,
-                                                      ui::DynamicDisplayInfo* info) {
-    return ComposerService::getComposerService()->getDynamicDisplayInfo(display, info);
+                                                      ui::DynamicDisplayInfo* outInfo) {
+    gui::DynamicDisplayInfo ginfo;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getDynamicDisplayInfo(display, &ginfo);
+    if (status.isOk()) {
+        // convert gui::DynamicDisplayInfo to ui::DynamicDisplayInfo
+        outInfo->supportedDisplayModes.clear();
+        outInfo->supportedDisplayModes.reserve(ginfo.supportedDisplayModes.size());
+        for (const auto& mode : ginfo.supportedDisplayModes) {
+            ui::DisplayMode outMode;
+            outMode.id = mode.id;
+            outMode.resolution.width = mode.resolution.width;
+            outMode.resolution.height = mode.resolution.height;
+            outMode.xDpi = mode.xDpi;
+            outMode.yDpi = mode.yDpi;
+            outMode.refreshRate = mode.refreshRate;
+            outMode.appVsyncOffset = mode.appVsyncOffset;
+            outMode.sfVsyncOffset = mode.sfVsyncOffset;
+            outMode.presentationDeadline = mode.presentationDeadline;
+            outMode.group = mode.group;
+            outInfo->supportedDisplayModes.push_back(outMode);
+        }
+
+        outInfo->activeDisplayModeId = ginfo.activeDisplayModeId;
+
+        outInfo->supportedColorModes.clear();
+        outInfo->supportedColorModes.reserve(ginfo.supportedColorModes.size());
+        for (const auto& cmode : ginfo.supportedColorModes) {
+            outInfo->supportedColorModes.push_back(static_cast<ui::ColorMode>(cmode));
+        }
+
+        outInfo->activeColorMode = static_cast<ui::ColorMode>(ginfo.activeColorMode);
+
+        std::vector<ui::Hdr> types;
+        types.reserve(ginfo.hdrCapabilities.supportedHdrTypes.size());
+        for (const auto& hdr : ginfo.hdrCapabilities.supportedHdrTypes) {
+            types.push_back(static_cast<ui::Hdr>(hdr));
+        }
+        outInfo->hdrCapabilities = HdrCapabilities(types, ginfo.hdrCapabilities.maxLuminance,
+                                                   ginfo.hdrCapabilities.maxAverageLuminance,
+                                                   ginfo.hdrCapabilities.minLuminance);
+
+        outInfo->autoLowLatencyModeSupported = ginfo.autoLowLatencyModeSupported;
+        outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported;
+        outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode;
+    }
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::getActiveDisplayMode(const sp<IBinder>& display,
@@ -2219,12 +2280,35 @@
 
 status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp<IBinder>& display,
         ui::DisplayPrimaries& outPrimaries) {
-    return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries);
+    gui::DisplayPrimaries primaries;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getDisplayNativePrimaries(display,
+                                                                                 &primaries);
+    if (status.isOk()) {
+        outPrimaries.red.X = primaries.red.X;
+        outPrimaries.red.Y = primaries.red.Y;
+        outPrimaries.red.Z = primaries.red.Z;
+
+        outPrimaries.green.X = primaries.green.X;
+        outPrimaries.green.Y = primaries.green.Y;
+        outPrimaries.green.Z = primaries.green.Z;
+
+        outPrimaries.blue.X = primaries.blue.X;
+        outPrimaries.blue.Y = primaries.blue.Y;
+        outPrimaries.blue.Z = primaries.blue.Z;
+
+        outPrimaries.white.X = primaries.white.X;
+        outPrimaries.white.Y = primaries.white.Y;
+        outPrimaries.white.Z = primaries.white.Z;
+    }
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display,
         ColorMode colorMode) {
-    return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
+    binder::Status status = ComposerServiceAIDL::getComposerService()
+                                    ->setActiveColorMode(display, static_cast<int>(colorMode));
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) {
@@ -2235,7 +2319,9 @@
 
 status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display,
                                                    ui::DisplayModeId displayModeId) {
-    return ComposerService::getComposerService()->setBootDisplayMode(display, displayModeId);
+    binder::Status status = ComposerServiceAIDL::getComposerService()
+                                    ->setBootDisplayMode(display, static_cast<int>(displayModeId));
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) {
@@ -2264,50 +2350,103 @@
 status_t SurfaceComposerClient::getCompositionPreference(
         ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat,
         ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) {
-    return ComposerService::getComposerService()
-            ->getCompositionPreference(defaultDataspace, defaultPixelFormat,
-                                       wideColorGamutDataspace, wideColorGamutPixelFormat);
+    gui::CompositionPreference pref;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getCompositionPreference(&pref);
+    if (status.isOk()) {
+        *defaultDataspace = static_cast<ui::Dataspace>(pref.defaultDataspace);
+        *defaultPixelFormat = static_cast<ui::PixelFormat>(pref.defaultPixelFormat);
+        *wideColorGamutDataspace = static_cast<ui::Dataspace>(pref.wideColorGamutDataspace);
+        *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(pref.wideColorGamutPixelFormat);
+    }
+    return status.transactionError();
 }
 
 bool SurfaceComposerClient::getProtectedContentSupport() {
     bool supported = false;
-    ComposerService::getComposerService()->getProtectedContentSupport(&supported);
+    ComposerServiceAIDL::getComposerService()->getProtectedContentSupport(&supported);
     return supported;
 }
 
 status_t SurfaceComposerClient::clearAnimationFrameStats() {
-    return ComposerService::getComposerService()->clearAnimationFrameStats();
+    binder::Status status = ComposerServiceAIDL::getComposerService()->clearAnimationFrameStats();
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) {
-    return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
+    gui::FrameStats stats;
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->getAnimationFrameStats(&stats);
+    if (status.isOk()) {
+        outStats->refreshPeriodNano = stats.refreshPeriodNano;
+        outStats->desiredPresentTimesNano.setCapacity(stats.desiredPresentTimesNano.size());
+        for (const auto& t : stats.desiredPresentTimesNano) {
+            outStats->desiredPresentTimesNano.add(t);
+        }
+        outStats->actualPresentTimesNano.setCapacity(stats.actualPresentTimesNano.size());
+        for (const auto& t : stats.actualPresentTimesNano) {
+            outStats->actualPresentTimesNano.add(t);
+        }
+        outStats->frameReadyTimesNano.setCapacity(stats.frameReadyTimesNano.size());
+        for (const auto& t : stats.frameReadyTimesNano) {
+            outStats->frameReadyTimesNano.add(t);
+        }
+    }
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::overrideHdrTypes(const sp<IBinder>& display,
                                                  const std::vector<ui::Hdr>& hdrTypes) {
-    return ComposerService::getComposerService()->overrideHdrTypes(display, hdrTypes);
+    std::vector<int32_t> hdrTypesVector;
+    hdrTypesVector.reserve(hdrTypes.size());
+    for (auto t : hdrTypes) {
+        hdrTypesVector.push_back(static_cast<int32_t>(t));
+    }
+
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()->overrideHdrTypes(display, hdrTypesVector);
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::onPullAtom(const int32_t atomId, std::string* outData,
                                            bool* success) {
-    return ComposerService::getComposerService()->onPullAtom(atomId, outData, success);
+    gui::PullAtomData pad;
+    binder::Status status = ComposerServiceAIDL::getComposerService()->onPullAtom(atomId, &pad);
+    if (status.isOk()) {
+        outData->assign((const char*)pad.data.data(), pad.data.size());
+        *success = pad.success;
+    }
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
                                                                       ui::PixelFormat* outFormat,
                                                                       ui::Dataspace* outDataspace,
                                                                       uint8_t* outComponentMask) {
-    return ComposerService::getComposerService()
-            ->getDisplayedContentSamplingAttributes(display, outFormat, outDataspace,
-                                                    outComponentMask);
+    if (!outFormat || !outDataspace || !outComponentMask) {
+        return BAD_VALUE;
+    }
+
+    gui::ContentSamplingAttributes attrs;
+    binder::Status status = ComposerServiceAIDL::getComposerService()
+                                    ->getDisplayedContentSamplingAttributes(display, &attrs);
+    if (status.isOk()) {
+        *outFormat = static_cast<ui::PixelFormat>(attrs.format);
+        *outDataspace = static_cast<ui::Dataspace>(attrs.dataspace);
+        *outComponentMask = static_cast<uint8_t>(attrs.componentMask);
+    }
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::setDisplayContentSamplingEnabled(const sp<IBinder>& display,
                                                                  bool enable, uint8_t componentMask,
                                                                  uint64_t maxFrames) {
-    return ComposerService::getComposerService()->setDisplayContentSamplingEnabled(display, enable,
-                                                                                   componentMask,
-                                                                                   maxFrames);
+    binder::Status status =
+            ComposerServiceAIDL::getComposerService()
+                    ->setDisplayContentSamplingEnabled(display, enable,
+                                                       static_cast<int8_t>(componentMask),
+                                                       static_cast<int64_t>(maxFrames));
+    return status.transactionError();
 }
 
 status_t SurfaceComposerClient::getDisplayedContentSample(const sp<IBinder>& display,
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 2312a8c..804ce4f 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#include <type_traits>
 #define LOG_TAG "WindowInfo"
 #define LOG_NDEBUG 0
 
+#include <type_traits>
+
 #include <binder/Parcel.h>
 #include <gui/WindowInfo.h>
 
@@ -25,8 +26,7 @@
 
 namespace android::gui {
 
-// --- WindowInfo ---
-void WindowInfo::setInputConfig(Flags<InputConfig> config, bool value) {
+void WindowInfo::setInputConfig(ftl::Flags<InputConfig> config, bool value) {
     if (value) {
         inputConfig |= config;
         return;
@@ -182,18 +182,16 @@
         return status;
     }
 
-    layoutParamsFlags = Flags<Flag>(lpFlags);
+    layoutParamsFlags = ftl::Flags<Flag>(lpFlags);
     layoutParamsType = static_cast<Type>(lpType);
     transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1});
     touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt);
-    inputConfig = Flags<InputConfig>(inputConfigInt);
+    inputConfig = ftl::Flags<InputConfig>(inputConfigInt);
     touchableRegionCropHandle = touchableRegionCropHandleSp;
 
     return OK;
 }
 
-// --- WindowInfoHandle ---
-
 WindowInfoHandle::WindowInfoHandle() {}
 
 WindowInfoHandle::~WindowInfoHandle() {}
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/libs/gui/aidl/android/gui/CompositionPreference.aidl
similarity index 69%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to libs/gui/aidl/android/gui/CompositionPreference.aidl
index d75777b..b615824 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/libs/gui/aidl/android/gui/CompositionPreference.aidl
@@ -16,11 +16,10 @@
 
 package android.gui;
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
-
 /** @hide */
-parcelable DisplayModelId {
-    int id;
+parcelable CompositionPreference {
+    int /*ui::Dataspace*/   defaultDataspace;
+    int /*ui::PixelFormat*/ defaultPixelFormat;
+    int /*ui::Dataspace*/   wideColorGamutDataspace;
+    int /*ui::PixelFormat*/ wideColorGamutPixelFormat;
 }
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl
similarity index 69%
rename from libs/gui/aidl/android/gui/DisplayModelId.aidl
rename to libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl
index d75777b..5d913b1 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl
@@ -16,11 +16,9 @@
 
 package android.gui;
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
-
 /** @hide */
-parcelable DisplayModelId {
-    int id;
+parcelable ContentSamplingAttributes {
+    int /*ui::PixelFormat*/ format;
+    int /*ui::Dataspace*/ dataspace;
+    byte componentMask;
 }
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/libs/gui/aidl/android/gui/DisplayMode.aidl
similarity index 65%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to libs/gui/aidl/android/gui/DisplayMode.aidl
index d75777b..3cd77f8 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/libs/gui/aidl/android/gui/DisplayMode.aidl
@@ -16,11 +16,21 @@
 
 package android.gui;
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
+import android.gui.Size;
+
+// Mode supported by physical display.
+// Make sure to sync with libui DisplayMode.h
 
 /** @hide */
-parcelable DisplayModelId {
+parcelable DisplayMode {
     int id;
+    Size resolution;
+    float xDpi = 0.0f;
+    float yDpi = 0.0f;
+
+    float refreshRate = 0.0f;
+    long appVsyncOffset = 0;
+    long sfVsyncOffset = 0;
+    long presentationDeadline = 0;
+    int group = -1;
 }
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/libs/gui/aidl/android/gui/DisplayPrimaries.aidl
similarity index 69%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to libs/gui/aidl/android/gui/DisplayPrimaries.aidl
index d75777b..dbf668c 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/libs/gui/aidl/android/gui/DisplayPrimaries.aidl
@@ -16,11 +16,18 @@
 
 package android.gui;
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
+// copied from libui ConfigStoreTypes.h
 
 /** @hide */
-parcelable DisplayModelId {
-    int id;
+parcelable DisplayPrimaries {
+    parcelable CieXyz {
+        float X;
+        float Y;
+        float Z;
+    }
+
+    CieXyz red;
+    CieXyz green;
+    CieXyz blue;
+    CieXyz white;
 }
diff --git a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl
new file mode 100644
index 0000000..57e6081
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+import android.gui.DisplayMode;
+import android.gui.HdrCapabilities;
+
+// Information about a physical display which may change on hotplug reconnect.
+// Make sure to sync with libui DynamicDisplayInfo.h
+
+/** @hide */
+parcelable DynamicDisplayInfo {
+    List<DisplayMode> supportedDisplayModes;
+
+    int activeDisplayModeId;
+
+    int[] supportedColorModes;
+    int activeColorMode;
+    HdrCapabilities hdrCapabilities;
+
+    // True if the display reports support for HDMI 2.1 Auto Low Latency Mode.
+    // For more information, see the HDMI 2.1 specification.
+    boolean autoLowLatencyModeSupported;
+
+    // True if the display reports support for Game Content Type.
+    // For more information, see the HDMI 1.4 specification.
+    boolean gameContentTypeSupported;
+
+    // The boot display mode preferred by the implementation.
+    int preferredBootDisplayMode;
+}
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/libs/gui/aidl/android/gui/FrameEvent.aidl
similarity index 63%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to libs/gui/aidl/android/gui/FrameEvent.aidl
index d75777b..aaabdb5 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/libs/gui/aidl/android/gui/FrameEvent.aidl
@@ -16,11 +16,20 @@
 
 package android.gui;
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
+// Identifiers for all the events that may be recorded or reported.
 
 /** @hide */
-parcelable DisplayModelId {
-    int id;
+@Backing(type="int")
+enum FrameEvent {
+    POSTED = 0,
+    REQUESTED_PRESENT = 1,
+    LATCH = 2,
+    ACQUIRE = 3,
+    FIRST_REFRESH_START = 4,
+    LAST_REFRESH_START = 5,
+    GPU_COMPOSITION_DONE = 6,
+    DISPLAY_PRESENT = 7,
+    DEQUEUE_READY = 8,
+    RELEASE = 9,
+    EVENT_COUNT = 10 // Not an actual event.
 }
diff --git a/libs/gui/aidl/android/gui/FrameStats.aidl b/libs/gui/aidl/android/gui/FrameStats.aidl
new file mode 100644
index 0000000..a145e74
--- /dev/null
+++ b/libs/gui/aidl/android/gui/FrameStats.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package android.gui;
+
+// Make sure to sync with libui FrameStats.h
+
+/** @hide */
+parcelable FrameStats {
+    /*
+     * Approximate refresh time, in nanoseconds.
+     */
+    long refreshPeriodNano;
+
+    /*
+     * The times in nanoseconds for when the frame contents were posted by the producer (e.g.
+     * the application). They are either explicitly set or defaulted to the time when
+     * Surface::queueBuffer() was called.
+     */
+    long[] desiredPresentTimesNano;
+
+    /*
+     * The times in milliseconds for when the frame contents were presented on the screen.
+     */
+    long[] actualPresentTimesNano;
+
+    /*
+     * The times in nanoseconds for when the frame contents were ready to be presented. Note that
+     * a frame can be posted and still it contents being rendered asynchronously in GL. In such a
+     * case these are the times when the frame contents were completely rendered (i.e. their fences
+     * signaled).
+     */
+    long[] frameReadyTimesNano;
+}
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/libs/gui/aidl/android/gui/HdrCapabilities.aidl
similarity index 69%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to libs/gui/aidl/android/gui/HdrCapabilities.aidl
index d75777b..9d06da9 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/libs/gui/aidl/android/gui/HdrCapabilities.aidl
@@ -16,11 +16,12 @@
 
 package android.gui;
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
+// Make sure to sync with libui HdrCapabilities.h
 
 /** @hide */
-parcelable DisplayModelId {
-    int id;
+parcelable HdrCapabilities {
+    int[] supportedHdrTypes;
+    float maxLuminance;
+    float maxAverageLuminance;
+    float minLuminance;
 }
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index f6cd5ec..dc77416 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -16,50 +16,69 @@
 
 package android.gui;
 
+import android.gui.CompositionPreference;
+import android.gui.ContentSamplingAttributes;
 import android.gui.DisplayCaptureArgs;
 import android.gui.DisplayBrightness;
+import android.gui.DisplayPrimaries;
 import android.gui.DisplayState;
 import android.gui.DisplayStatInfo;
+import android.gui.FrameEvent;
+import android.gui.FrameStats;
+import android.gui.LayerDebugInfo;
+import android.gui.PullAtomData;
 import android.gui.StaticDisplayInfo;
+import android.gui.DynamicDisplayInfo;
 import android.gui.IHdrLayerInfoListener;
 import android.gui.LayerCaptureArgs;
 import android.gui.IScreenCaptureListener;
 
 /** @hide */
 interface ISurfaceComposer {
-    /* create a virtual display
+    /**
+     * Create a virtual display
      * requires ACCESS_SURFACE_FLINGER permission.
      */
     @nullable IBinder createDisplay(@utf8InCpp String displayName, boolean secure);
 
-    /* destroy a virtual display
+    /**
+     * Destroy a virtual display
      * requires ACCESS_SURFACE_FLINGER permission.
      */
     void destroyDisplay(IBinder display);
 
-    /* get stable IDs for connected physical displays.
+    /**
+     * Get stable IDs for connected physical displays.
      */
     long[] getPhysicalDisplayIds();
 
     long getPrimaryPhysicalDisplayId();
 
-    /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
-     * DisplayEventReceiver hotplug event.
+    /**
+     * Get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or
+     * a DisplayEventReceiver hotplug event.
      */
     @nullable IBinder getPhysicalDisplayToken(long displayId);
 
-    /* set display power mode. depending on the mode, it can either trigger
+    /**
+     * Returns the frame timestamps supported by SurfaceFlinger.
+     */
+    FrameEvent[] getSupportedFrameTimestamps();
+
+    /**
+     * Set display power mode. depending on the mode, it can either trigger
      * screen on, off or low power mode and wait for it to complete.
      * requires ACCESS_SURFACE_FLINGER permission.
      */
     void setPowerMode(IBinder display, int mode);
 
-    /* returns display statistics for a given display
+    /**
+     * Returns display statistics for a given display
      * intended to be used by the media framework to properly schedule
      * video frames */
     DisplayStatInfo getDisplayStats(IBinder display);
 
-     /**
+    /**
      * Get transactional state of given display.
      */
     DisplayState getDisplayState(IBinder display);
@@ -70,6 +89,20 @@
     StaticDisplayInfo getStaticDisplayInfo(IBinder display);
 
     /**
+     * Gets dynamic information about given physical display.
+     */
+    DynamicDisplayInfo getDynamicDisplayInfo(IBinder display);
+
+    DisplayPrimaries getDisplayNativePrimaries(IBinder display);
+
+    void setActiveColorMode(IBinder display, int colorMode);
+
+    /**
+     * Sets the user-preferred display mode that a device should boot in.
+     */
+    void setBootDisplayMode(IBinder display, int displayModeId);
+
+    /**
      * Clears the user-preferred display mode. The device should now boot in system preferred
      * display mode.
      */
@@ -114,7 +147,9 @@
      * match the size of the output buffer.
      */
     void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener);
+
     void captureDisplayById(long displayId, IScreenCaptureListener listener);
+
     /**
      * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
      * This requires READ_FRAME_BUFFER permission. This function will fail if there
@@ -122,13 +157,80 @@
      */
     void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
 
-    /*
+    /**
+     * Clears the frame statistics for animations.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    void clearAnimationFrameStats();
+
+    /**
+     * Gets the frame statistics for animations.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    FrameStats getAnimationFrameStats();
+
+    /**
+     * Overrides the supported HDR modes for the given display device.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    void overrideHdrTypes(IBinder display, in int[] hdrTypes);
+
+    /**
+     * Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd.
+     *
+     * Requires the calling uid be from system server.
+     */
+    PullAtomData onPullAtom(int atomId);
+
+    oneway void enableVSyncInjections(boolean enable);
+
+    oneway void injectVSync(long when);
+
+    /**
+     * Gets the list of active layers in Z order for debugging purposes
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    List<LayerDebugInfo> getLayerDebugInfo();
+
+    boolean getColorManagement();
+
+    /**
+     * Gets the composition preference of the default data space and default pixel format,
+     * as well as the wide color gamut data space and wide color gamut pixel format.
+     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+     * has no wide color gamut support.
+     *
+     */
+    CompositionPreference getCompositionPreference();
+
+    /**
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    ContentSamplingAttributes getDisplayedContentSamplingAttributes(IBinder display);
+
+    /**
+     * Turns on the color sampling engine on the display.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    void setDisplayContentSamplingEnabled(IBinder display, boolean enable, byte componentMask, long maxFrames);
+
+    /**
+     * Gets whether SurfaceFlinger can support protected content in GPU composition.
+     */
+    boolean getProtectedContentSupport();
+
+    /**
      * Queries whether the given display is a wide color display.
      * Requires the ACCESS_SURFACE_FLINGER permission.
      */
     boolean isWideColorDisplay(IBinder token);
 
-    /*
+    /**
      * Gets whether brightness operations are supported on a display.
      *
      * displayToken
@@ -142,7 +244,7 @@
      */
     boolean getDisplayBrightnessSupport(IBinder displayToken);
 
-    /*
+    /**
      * Sets the brightness of a display.
      *
      * displayToken
@@ -157,7 +259,7 @@
      */
     void setDisplayBrightness(IBinder displayToken, in DisplayBrightness brightness);
 
-    /*
+    /**
      * Adds a listener that receives HDR layer information. This is used in combination
      * with setDisplayBrightness to adjust the display brightness depending on factors such
      * as whether or not HDR is in use.
@@ -166,7 +268,7 @@
      */
     void addHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
 
-    /*
+    /**
      * Removes a listener that was added with addHdrLayerInfoListener.
      *
      * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if
@@ -175,7 +277,7 @@
      */
     void removeHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener);
 
-    /*
+    /**
      * Sends a power boost to the composer. This function is asynchronous.
      *
      * boostId
@@ -183,5 +285,5 @@
      *
      * Returns NO_ERROR upon success.
      */
-    void notifyPowerBoost(int boostId);
+    oneway void notifyPowerBoost(int boostId);
 }
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/libs/gui/aidl/android/gui/LayerDebugInfo.aidl
similarity index 68%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to libs/gui/aidl/android/gui/LayerDebugInfo.aidl
index d75777b..faca980 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/libs/gui/aidl/android/gui/LayerDebugInfo.aidl
@@ -16,11 +16,4 @@
 
 package android.gui;
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
-
-/** @hide */
-parcelable DisplayModelId {
-    int id;
-}
+parcelable LayerDebugInfo cpp_header "gui/LayerDebugInfo.h";
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/libs/gui/aidl/android/gui/PullAtomData.aidl
similarity index 69%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to libs/gui/aidl/android/gui/PullAtomData.aidl
index d75777b..14d33c6 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/libs/gui/aidl/android/gui/PullAtomData.aidl
@@ -16,11 +16,8 @@
 
 package android.gui;
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
-
 /** @hide */
-parcelable DisplayModelId {
-    int id;
+parcelable PullAtomData {
+    @utf8InCpp String data;
+    boolean success;
 }
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index dd3de58..f73bc3b 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_GUI_FRAMETIMESTAMPS_H
 #define ANDROID_GUI_FRAMETIMESTAMPS_H
 
+#include <android/gui/FrameEvent.h>
+
 #include <ui/FenceTime.h>
 #include <utils/Flattenable.h>
 #include <utils/StrongPointer.h>
@@ -31,22 +33,7 @@
 struct FrameEvents;
 class FrameEventHistoryDelta;
 
-
-// Identifiers for all the events that may be recorded or reported.
-enum class FrameEvent {
-    POSTED,
-    REQUESTED_PRESENT,
-    LATCH,
-    ACQUIRE,
-    FIRST_REFRESH_START,
-    LAST_REFRESH_START,
-    GPU_COMPOSITION_DONE,
-    DISPLAY_PRESENT,
-    DEQUEUE_READY,
-    RELEASE,
-    EVENT_COUNT, // Not an actual event.
-};
-
+using gui::FrameEvent;
 
 // A collection of timestamps corresponding to a single frame.
 struct FrameEvents {
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
index 0bdffac..98a07a3 100644
--- a/libs/gui/include/gui/HdrMetadata.h
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -17,6 +17,8 @@
 #pragma once
 
 #include <stdint.h>
+#include <ui/GraphicTypes.h>
+#include <optional>
 #include <vector>
 
 #include <system/graphics.h>
@@ -43,6 +45,27 @@
     status_t flatten(void* buffer, size_t size) const;
     status_t unflatten(void const* buffer, size_t size);
 
+    std::optional<ui::Smpte2086> getSmpte2086() const {
+        if (validTypes & Type::SMPTE2086) {
+            return ui::translate(smpte2086);
+        }
+        return {};
+    }
+
+    std::optional<ui::Cta861_3> getCta8613() const {
+        if (validTypes & Type::CTA861_3) {
+            return ui::translate(cta8613);
+        }
+        return {};
+    }
+
+    std::optional<std::vector<uint8_t>> getHdr10Plus() const {
+        if (validTypes & Type::HDR10PLUS) {
+            return hdr10plus;
+        }
+        return {};
+    }
+
     bool operator==(const HdrMetadata& rhs) const;
     bool operator!=(const HdrMetadata& rhs) const { return !(*this == rhs); }
 };
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 29e38b8..7f59a5a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -27,7 +27,7 @@
 #include <android/gui/IWindowInfosListener.h>
 #include <binder/IBinder.h>
 #include <binder/IInterface.h>
-#include <ftl/Flags.h>
+#include <ftl/flags.h>
 #include <gui/FrameTimelineInfo.h>
 #include <gui/ITransactionCompletedListener.h>
 #include <gui/SpHash.h>
@@ -61,12 +61,10 @@
 struct DisplayStatInfo;
 struct DisplayState;
 struct InputWindowCommands;
-class LayerDebugInfo;
 class HdrCapabilities;
 class IGraphicBufferProducer;
 class ISurfaceComposerClient;
 class Rect;
-enum class FrameEvent;
 
 using gui::IDisplayEventConnection;
 using gui::IRegionSamplingListener;
@@ -77,6 +75,7 @@
 
 struct DisplayCaptureArgs;
 struct LayerCaptureArgs;
+class LayerDebugInfo;
 
 } // namespace gui
 
@@ -125,7 +124,7 @@
         frameRateOverride = 1 << 1,
     };
 
-    using EventRegistrationFlags = Flags<EventRegistration>;
+    using EventRegistrationFlags = ftl::Flags<EventRegistration>;
 
     /*
      * Create a connection with SurfaceFlinger.
@@ -155,90 +154,6 @@
     virtual bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& surface) const = 0;
 
-    /* Returns the frame timestamps supported by SurfaceFlinger.
-     */
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const = 0;
-
-    /**
-     * Gets dynamic information about given physical display.
-     */
-    virtual status_t getDynamicDisplayInfo(const sp<IBinder>& display, ui::DynamicDisplayInfo*) = 0;
-
-    virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
-            ui::DisplayPrimaries& primaries) = 0;
-    virtual status_t setActiveColorMode(const sp<IBinder>& display,
-            ui::ColorMode colorMode) = 0;
-
-    /**
-     * Sets the user-preferred display mode that a device should boot in.
-     */
-    virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0;
-
-    /* Clears the frame statistics for animations.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t clearAnimationFrameStats() = 0;
-
-    /* Gets the frame statistics for animations.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
-
-    /* Overrides the supported HDR modes for the given display device.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t overrideHdrTypes(const sp<IBinder>& display,
-                                      const std::vector<ui::Hdr>& hdrTypes) = 0;
-
-    /* Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd.
-     *
-     * Requires the calling uid be from system server.
-     */
-    virtual status_t onPullAtom(const int32_t atomId, std::string* outData, bool* success) = 0;
-
-    virtual status_t enableVSyncInjections(bool enable) = 0;
-
-    virtual status_t injectVSync(nsecs_t when) = 0;
-
-    /* Gets the list of active layers in Z order for debugging purposes
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) = 0;
-
-    virtual status_t getColorManagement(bool* outGetColorManagement) const = 0;
-
-    /* Gets the composition preference of the default data space and default pixel format,
-     * as well as the wide color gamut data space and wide color gamut pixel format.
-     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
-     * has no wide color gamut support.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
-                                              ui::PixelFormat* defaultPixelFormat,
-                                              ui::Dataspace* wideColorGamutDataspace,
-                                              ui::PixelFormat* wideColorGamutPixelFormat) const = 0;
-    /*
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
-                                                           ui::PixelFormat* outFormat,
-                                                           ui::Dataspace* outDataspace,
-                                                           uint8_t* outComponentMask) const = 0;
-
-    /* Turns on the color sampling engine on the display.
-     *
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
-                                                      uint8_t componentMask,
-                                                      uint64_t maxFrames) = 0;
-
     /* Returns statistics on the color profile of the last frame displayed for a given display
      *
      * Requires the ACCESS_SURFACE_FLINGER permission.
@@ -247,12 +162,6 @@
                                                uint64_t timestamp,
                                                DisplayedFrameStats* outStats) const = 0;
 
-    /*
-     * Gets whether SurfaceFlinger can support protected content in GPU composition.
-     * Requires the ACCESS_SURFACE_FLINGER permission.
-     */
-    virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
-
     /* Registers a listener to stream median luma updates from SurfaceFlinger.
      *
      * The sampling area is bounded by both samplingArea and the given stopLayerHandle
@@ -444,32 +353,32 @@
         GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now.
         SET_TRANSACTION_STATE,
         AUTHENTICATE_SURFACE,
-        GET_SUPPORTED_FRAME_TIMESTAMPS,
-        GET_DISPLAY_MODES,       // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_SUPPORTED_FRAME_TIMESTAMPS, // Deprecated. Autogenerated by .aidl now.
+        GET_DISPLAY_MODES,              // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_ACTIVE_DISPLAY_MODE,        // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
         GET_DISPLAY_STATE,
-        CAPTURE_DISPLAY, // Deprecated. Autogenerated by .aidl now.
-        CAPTURE_LAYERS,  // Deprecated. Autogenerated by .aidl now.
-        CLEAR_ANIMATION_FRAME_STATS,
-        GET_ANIMATION_FRAME_STATS,
-        SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now.
+        CAPTURE_DISPLAY,             // Deprecated. Autogenerated by .aidl now.
+        CAPTURE_LAYERS,              // Deprecated. Autogenerated by .aidl now.
+        CLEAR_ANIMATION_FRAME_STATS, // Deprecated. Autogenerated by .aidl now.
+        GET_ANIMATION_FRAME_STATS,   // Deprecated. Autogenerated by .aidl now.
+        SET_POWER_MODE,              // Deprecated. Autogenerated by .aidl now.
         GET_DISPLAY_STATS,
-        GET_HDR_CAPABILITIES,    // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        GET_ACTIVE_COLOR_MODE,   // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
-        SET_ACTIVE_COLOR_MODE,
-        ENABLE_VSYNC_INJECTIONS,
-        INJECT_VSYNC,
-        GET_LAYER_DEBUG_INFO,
-        GET_COMPOSITION_PREFERENCE,
-        GET_COLOR_MANAGEMENT,
-        GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
-        SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
+        GET_HDR_CAPABILITIES,       // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_DISPLAY_COLOR_MODES,    // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        GET_ACTIVE_COLOR_MODE,      // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead.
+        SET_ACTIVE_COLOR_MODE,      // Deprecated. Autogenerated by .aidl now.
+        ENABLE_VSYNC_INJECTIONS,    // Deprecated. Autogenerated by .aidl now.
+        INJECT_VSYNC,               // Deprecated. Autogenerated by .aidl now.
+        GET_LAYER_DEBUG_INFO,       // Deprecated. Autogenerated by .aidl now.
+        GET_COMPOSITION_PREFERENCE, // Deprecated. Autogenerated by .aidl now.
+        GET_COLOR_MANAGEMENT,       // Deprecated. Autogenerated by .aidl now.
+        GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, // Deprecated. Autogenerated by .aidl now.
+        SET_DISPLAY_CONTENT_SAMPLING_ENABLED,      // Deprecated. Autogenerated by .aidl now.
         GET_DISPLAYED_CONTENT_SAMPLE,
-        GET_PROTECTED_CONTENT_SUPPORT,
-        IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now.
-        GET_DISPLAY_NATIVE_PRIMARIES,
-        GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now.
+        GET_PROTECTED_CONTENT_SUPPORT, // Deprecated. Autogenerated by .aidl now.
+        IS_WIDE_COLOR_DISPLAY,         // Deprecated. Autogenerated by .aidl now.
+        GET_DISPLAY_NATIVE_PRIMARIES,  // Deprecated. Autogenerated by .aidl now.
+        GET_PHYSICAL_DISPLAY_IDS,      // Deprecated. Autogenerated by .aidl now.
         ADD_REGION_SAMPLING_LISTENER,
         REMOVE_REGION_SAMPLING_LISTENER,
         SET_DESIRED_DISPLAY_MODE_SPECS,
@@ -490,13 +399,13 @@
         ADD_TRANSACTION_TRACE_LISTENER,
         GET_GPU_CONTEXT_PRIORITY,
         GET_MAX_ACQUIRED_BUFFER_COUNT,
-        GET_DYNAMIC_DISPLAY_INFO,
+        GET_DYNAMIC_DISPLAY_INFO, // Deprecated. Autogenerated by .aidl now.
         ADD_FPS_LISTENER,
         REMOVE_FPS_LISTENER,
-        OVERRIDE_HDR_TYPES,
+        OVERRIDE_HDR_TYPES,             // Deprecated. Autogenerated by .aidl now.
         ADD_HDR_LAYER_INFO_LISTENER,    // Deprecated. Autogenerated by .aidl now.
         REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now.
-        ON_PULL_ATOM,
+        ON_PULL_ATOM,                   // Deprecated. Autogenerated by .aidl now.
         ADD_TUNNEL_MODE_ENABLED_LISTENER,
         REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
         ADD_WINDOW_INFOS_LISTENER,
@@ -504,8 +413,8 @@
         GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now.
         GET_DISPLAY_DECORATION_SUPPORT,
         GET_BOOT_DISPLAY_MODE_SUPPORT, // Deprecated. Autogenerated by .aidl now.
-        SET_BOOT_DISPLAY_MODE,
-        CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now.
+        SET_BOOT_DISPLAY_MODE,         // Deprecated. Autogenerated by .aidl now.
+        CLEAR_BOOT_DISPLAY_MODE,       // Deprecated. Autogenerated by .aidl now.
         SET_OVERRIDE_FRAME_RATE,
         // Always append new enum to the end.
     };
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index af834d7..1c1bbef 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -25,7 +25,7 @@
 #include <string>
 #include <math/vec4.h>
 
-namespace android {
+namespace android::gui {
 
 /* Class for transporting debug info from SurfaceFlinger to authorized
  * recipients.  The class is intended to be a data container. There are
@@ -71,4 +71,4 @@
 
 std::string to_string(const LayerDebugInfo& info);
 
-} // namespace android
+} // namespace android::gui
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 0f37dab..0a9b75a 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -29,6 +29,7 @@
 #include <android/gui/DropInputMode.h>
 #include <android/gui/FocusRequest.h>
 
+#include <ftl/flags.h>
 #include <gui/DisplayCaptureArgs.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/LayerCaptureArgs.h>
@@ -102,7 +103,7 @@
     // was called with.
     sp<IBinder> releaseBufferEndpoint;
 
-    Flags<BufferDataChange> flags;
+    ftl::Flags<BufferDataChange> flags;
 
     client_cache_t cachedBuffer;
 
@@ -150,7 +151,7 @@
         eTransparentRegionChanged = 0x00000020,
         eFlagsChanged = 0x00000040,
         eLayerStackChanged = 0x00000080,
-        /* unused 0x00000400, */
+        eDimmingEnabledChanged = 0x00000400,
         eShadowRadiusChanged = 0x00000800,
         /* unused 0x00001000, */
         eBufferCropChanged = 0x00002000,
@@ -187,7 +188,7 @@
         eAutoRefreshChanged = 0x1000'00000000,
         eStretchChanged = 0x2000'00000000,
         eTrustedOverlayChanged = 0x4000'00000000,
-        eDropInputModeChanged = 0x8000'00000000,
+        eDropInputModeChanged = 0x8000'00000000
     };
 
     layer_state_t();
@@ -298,6 +299,8 @@
 
     // Force inputflinger to drop all input events for the layer and its children.
     gui::DropInputMode dropInputMode;
+
+    bool dimmingEnabled;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index ba9ee6c..ab9ebaa 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -403,6 +403,13 @@
     void getQueueBufferInputLocked(android_native_buffer_t* buffer, int fenceFd, nsecs_t timestamp,
             IGraphicBufferProducer::QueueBufferInput* out);
 
+    // For easing in adoption of gralloc4 metadata by vendor components, as well as for supporting
+    // the public ANativeWindow api, allow setting relevant metadata when queueing a buffer through
+    // a native window
+    void applyGrallocMetadataLocked(
+            android_native_buffer_t* buffer,
+            const IGraphicBufferProducer::QueueBufferInput& queueBufferInput);
+
     void onBufferQueuedLocked(int slot, sp<Fence> fence,
             const IGraphicBufferProducer::QueueBufferOutput& output);
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index b17902d..a30a3fa 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -492,6 +492,7 @@
                 uint32_t flags, uint32_t mask);
         Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc,
                 const Region& transparentRegion);
+        Transaction& setDimmingEnabled(const sp<SurfaceControl>& sc, bool dimmingEnabled);
         Transaction& setAlpha(const sp<SurfaceControl>& sc,
                 float alpha);
         Transaction& setMatrix(const sp<SurfaceControl>& sc,
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index ef0b98b..0e1d258 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -20,7 +20,7 @@
 #include <android/os/InputConfig.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
-#include <ftl/Flags.h>
+#include <ftl/flags.h>
 #include <gui/constants.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -224,7 +224,7 @@
     int32_t ownerPid = -1;
     int32_t ownerUid = -1;
     std::string packageName;
-    Flags<InputConfig> inputConfig;
+    ftl::Flags<InputConfig> inputConfig;
     int32_t displayId = ADISPLAY_ID_NONE;
     InputApplicationInfo applicationInfo;
     bool replaceTouchableRegionWithCrop = false;
@@ -232,9 +232,9 @@
 
     // The window's layout params flags and type set by WM.
     Type layoutParamsType = Type::UNKNOWN;
-    Flags<Flag> layoutParamsFlags;
+    ftl::Flags<Flag> layoutParamsFlags;
 
-    void setInputConfig(Flags<InputConfig> config, bool value);
+    void setInputConfig(ftl::Flags<InputConfig> config, bool value);
 
     void addTouchableRegion(const Rect& region);
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index e02299d..58964d6 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -714,84 +714,12 @@
         return false;
     }
 
-    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported)
-            const override {
-        *outSupported = {
-                FrameEvent::REQUESTED_PRESENT,
-                FrameEvent::ACQUIRE,
-                FrameEvent::LATCH,
-                FrameEvent::FIRST_REFRESH_START,
-                FrameEvent::LAST_REFRESH_START,
-                FrameEvent::GPU_COMPOSITION_DONE,
-                FrameEvent::DEQUEUE_READY,
-                FrameEvent::RELEASE
-        };
-        if (mSupportsPresent) {
-            outSupported->push_back(
-                        FrameEvent::DISPLAY_PRESENT);
-        }
-        return NO_ERROR;
-    }
-
-    status_t getDynamicDisplayInfo(const sp<IBinder>& /*display*/,
-                                   ui::DynamicDisplayInfo*) override {
-        return NO_ERROR;
-    }
-    status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
-            ui::DisplayPrimaries& /*primaries*/) override {
-        return NO_ERROR;
-    }
-    status_t setActiveColorMode(const sp<IBinder>& /*display*/,
-        ColorMode /*colorMode*/) override { return NO_ERROR; }
-    status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override {
-        return NO_ERROR;
-    }
-
-    status_t clearAnimationFrameStats() override { return NO_ERROR; }
-    status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
-        return NO_ERROR;
-    }
-    status_t overrideHdrTypes(const sp<IBinder>& /*display*/,
-                              const std::vector<ui::Hdr>& /*hdrTypes*/) override {
-        return NO_ERROR;
-    }
-    status_t onPullAtom(const int32_t /*atomId*/, std::string* /*outData*/,
-                        bool* /*success*/) override {
-        return NO_ERROR;
-    }
-    status_t enableVSyncInjections(bool /*enable*/) override {
-        return NO_ERROR;
-    }
-    status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; }
-    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) override {
-        return NO_ERROR;
-    }
-    status_t getCompositionPreference(
-            ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/,
-            ui::Dataspace* /*outWideColorGamutDataspace*/,
-            ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override {
-        return NO_ERROR;
-    }
-    status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& /*display*/,
-                                                   ui::PixelFormat* /*outFormat*/,
-                                                   ui::Dataspace* /*outDataspace*/,
-                                                   uint8_t* /*outComponentMask*/) const override {
-        return NO_ERROR;
-    }
-    status_t setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/,
-                                              uint8_t /*componentMask*/,
-                                              uint64_t /*maxFrames*/) override {
-        return NO_ERROR;
-    }
     status_t getDisplayedContentSample(const sp<IBinder>& /*display*/, uint64_t /*maxFrames*/,
                                        uint64_t /*timestamp*/,
                                        DisplayedFrameStats* /*outStats*/) const override {
         return NO_ERROR;
     }
 
-    status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
-    status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
-
     status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
                                        const sp<IBinder>& /*stopLayerHandle*/,
                                        const sp<IRegionSamplingListener>& /*listener*/) override {
@@ -916,6 +844,21 @@
         return binder::Status::ok();
     }
 
+    binder::Status getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) override {
+        *outSupported = {FrameEvent::REQUESTED_PRESENT,
+                         FrameEvent::ACQUIRE,
+                         FrameEvent::LATCH,
+                         FrameEvent::FIRST_REFRESH_START,
+                         FrameEvent::LAST_REFRESH_START,
+                         FrameEvent::GPU_COMPOSITION_DONE,
+                         FrameEvent::DEQUEUE_READY,
+                         FrameEvent::RELEASE};
+        if (mSupportsPresent) {
+            outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
+        }
+        return binder::Status::ok();
+    }
+
     binder::Status getDisplayStats(const sp<IBinder>& /*display*/,
                                    gui::DisplayStatInfo* /*outStatInfo*/) override {
         return binder::Status::ok();
@@ -931,6 +874,25 @@
         return binder::Status::ok();
     }
 
+    binder::Status getDynamicDisplayInfo(const sp<IBinder>& /*display*/,
+                                         gui::DynamicDisplayInfo* /*outInfo*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
+                                             gui::DisplayPrimaries* /*outPrimaries*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setActiveColorMode(const sp<IBinder>& /*display*/, int /*colorMode*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setBootDisplayMode(const sp<IBinder>& /*display*/,
+                                      int /*displayModeId*/) override {
+        return binder::Status::ok();
+    }
+
     binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override {
         return binder::Status::ok();
     }
@@ -961,6 +923,52 @@
         return binder::Status::ok();
     }
 
+    binder::Status clearAnimationFrameStats() override { return binder::Status::ok(); }
+
+    binder::Status getAnimationFrameStats(gui::FrameStats* /*outStats*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status overrideHdrTypes(const sp<IBinder>& /*display*/,
+                                    const std::vector<int32_t>& /*hdrTypes*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status onPullAtom(int32_t /*atomId*/, gui::PullAtomData* /*outPullData*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status enableVSyncInjections(bool /*enable*/) override { return binder::Status::ok(); }
+
+    binder::Status injectVSync(int64_t /*when*/) override { return binder::Status::ok(); }
+
+    binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* /*outLayers*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getColorManagement(bool* /*outGetColorManagement*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getCompositionPreference(gui::CompositionPreference* /*outPref*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getDisplayedContentSamplingAttributes(
+            const sp<IBinder>& /*display*/, gui::ContentSamplingAttributes* /*outAttrs*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/,
+                                                    int8_t /*componentMask*/,
+                                                    int64_t /*maxFrames*/) override {
+        return binder::Status::ok();
+    }
+
+    binder::Status getProtectedContentSupport(bool* /*outSupporte*/) override {
+        return binder::Status::ok();
+    }
+
     binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/,
                                       bool* /*outIsWideColorDisplay*/) override {
         return binder::Status::ok();
@@ -1035,10 +1043,10 @@
 
 class TestSurface : public Surface {
 public:
-    TestSurface(const sp<IGraphicBufferProducer>& bufferProducer,
-            FenceToFenceTimeMap* fenceMap)
-        : Surface(bufferProducer),
-          mFakeSurfaceComposer(new FakeSurfaceComposer) {
+    TestSurface(const sp<IGraphicBufferProducer>& bufferProducer, FenceToFenceTimeMap* fenceMap)
+          : Surface(bufferProducer),
+            mFakeSurfaceComposer(new FakeSurfaceComposer),
+            mFakeSurfaceComposerAIDL(new FakeSurfaceComposerAIDL) {
         mFakeFrameEventHistory = new FakeProducerFrameEventHistory(fenceMap);
         mFrameEventHistory.reset(mFakeFrameEventHistory);
     }
@@ -1049,6 +1057,10 @@
         return mFakeSurfaceComposer;
     }
 
+    sp<gui::ISurfaceComposer> composerServiceAIDL() const override {
+        return mFakeSurfaceComposerAIDL;
+    }
+
     nsecs_t now() const override {
         return mNow;
     }
@@ -1059,6 +1071,7 @@
 
 public:
     sp<FakeSurfaceComposer> mFakeSurfaceComposer;
+    sp<FakeSurfaceComposerAIDL> mFakeSurfaceComposerAIDL;
     nsecs_t mNow = 0;
 
     // mFrameEventHistory owns the instance of FakeProducerFrameEventHistory,
@@ -1425,6 +1438,7 @@
 TEST_F(GetFrameTimestampsTest, QueryPresentSupported) {
     bool displayPresentSupported = true;
     mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+    mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(displayPresentSupported);
 
     // Verify supported bits are forwarded.
     int supportsPresent = -1;
@@ -1436,6 +1450,7 @@
 TEST_F(GetFrameTimestampsTest, QueryPresentNotSupported) {
     bool displayPresentSupported = false;
     mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+    mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(displayPresentSupported);
 
     // Verify supported bits are forwarded.
     int supportsPresent = -1;
@@ -2013,6 +2028,7 @@
 TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
     enableFrameTimestamps();
     mSurface->mFakeSurfaceComposer->setSupportsPresent(false);
+    mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(false);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 18fb7c1..1d4fc1f 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -50,6 +50,7 @@
         "Keyboard.cpp",
         "KeyCharacterMap.cpp",
         "KeyLayoutMap.cpp",
+        "PrintTools.cpp",
         "PropertyMap.cpp",
         "TouchVideoFrame.cpp",
         "VelocityControl.cpp",
@@ -102,6 +103,9 @@
 
             sanitize: {
                 misc_undefined: ["integer"],
+                diag: {
+                    misc_undefined: ["integer"],
+                },
             },
         },
         host: {
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/libs/input/PrintTools.cpp
similarity index 60%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to libs/input/PrintTools.cpp
index d75777b..5d6ae4e 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/libs/input/PrintTools.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright (C) 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.
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package android.gui;
+#define LOG_TAG "PrintTools"
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
+#include <input/PrintTools.h>
 
-/** @hide */
-parcelable DisplayModelId {
-    int id;
+namespace android {
+
+const char* toString(bool value) {
+    return value ? "true" : "false";
 }
+
+} // namespace android
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index ed728dc..e3fad3d 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -33,7 +33,7 @@
 
 cc_library_headers {
     name: "libnativedisplay_headers",
-    export_include_dirs: ["include",],
+    export_include_dirs: ["include"],
 }
 
 cc_library_shared {
@@ -55,6 +55,7 @@
     version_script: "libnativedisplay.map.txt",
 
     srcs: [
+        ":libgui_frame_event_aidl",
         "AChoreographer.cpp",
         "ADisplay.cpp",
         "surfacetexture/surface_texture.cpp",
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 576941f..f3009dd 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -207,7 +207,11 @@
       if (result == 0) {
         outPlanes->planeCount = 3;
         outPlanes->planes[0].data = yuvData.y;
-        outPlanes->planes[0].pixelStride = 1;
+        if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010) {
+            outPlanes->planes[0].pixelStride = 2;
+        } else {
+            outPlanes->planes[0].pixelStride = 1;
+        }
         outPlanes->planes[0].rowStride = yuvData.ystride;
         outPlanes->planes[1].data = yuvData.cb;
         outPlanes->planes[1].pixelStride = yuvData.chroma_step;
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 1a1c3b4..4ea2af2 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -57,6 +57,7 @@
 #include <gui/TraceUtils.h>
 #include <sync/sync.h>
 #include <ui/BlurRegion.h>
+#include <ui/DataspaceUtils.h>
 #include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/Trace.h>
@@ -1128,9 +1129,15 @@
                                                           ? layerDimmingRatio
                                                           : 1.f}));
 
-            // Turn on dithering when dimming beyond this threshold.
+            // Turn on dithering when dimming beyond this (arbitrary) threshold...
             static constexpr float kDimmingThreshold = 0.2f;
-            if (layerDimmingRatio <= kDimmingThreshold) {
+            // ...or we're rendering an HDR layer down to an 8-bit target
+            // Most HDR standards require at least 10-bits of color depth for source content, so we
+            // can just extract the transfer function rather than dig into precise gralloc layout.
+            // Furthermore, we can assume that the only 8-bit target we support is RGBA8888.
+            const bool requiresDownsample = isHdrDataspace(layer.sourceDataspace) &&
+                    buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888;
+            if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) {
                 paint.setDither(true);
             }
             paint.setAlphaf(layer.alpha);
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 4af38c5..0a85fe0 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -129,7 +129,6 @@
         "DebugUtils.cpp",
         "DeviceProductInfo.cpp",
         "DisplayIdentification.cpp",
-        "DisplayMode.cpp",
         "DynamicDisplayInfo.cpp",
         "Fence.cpp",
         "FenceTime.cpp",
@@ -141,7 +140,6 @@
         "GraphicBuffer.cpp",
         "GraphicBufferAllocator.cpp",
         "GraphicBufferMapper.cpp",
-        "HdrCapabilities.cpp",
         "PixelFormat.cpp",
         "PublicFormat.cpp",
         "StaticAsserts.cpp",
diff --git a/libs/ui/DisplayMode.cpp b/libs/ui/DisplayMode.cpp
deleted file mode 100644
index cf05dbf..0000000
--- a/libs/ui/DisplayMode.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.
- */
-
-#include <ui/DisplayMode.h>
-
-#include <cstdint>
-
-#include <ui/FlattenableHelpers.h>
-
-#define RETURN_IF_ERROR(op) \
-    if (const status_t status = (op); status != OK) return status;
-
-namespace android::ui {
-
-size_t DisplayMode::getFlattenedSize() const {
-    return FlattenableHelpers::getFlattenedSize(id) +
-            FlattenableHelpers::getFlattenedSize(resolution) +
-            FlattenableHelpers::getFlattenedSize(xDpi) +
-            FlattenableHelpers::getFlattenedSize(yDpi) +
-            FlattenableHelpers::getFlattenedSize(refreshRate) +
-            FlattenableHelpers::getFlattenedSize(appVsyncOffset) +
-            FlattenableHelpers::getFlattenedSize(sfVsyncOffset) +
-            FlattenableHelpers::getFlattenedSize(presentationDeadline) +
-            FlattenableHelpers::getFlattenedSize(group);
-}
-
-status_t DisplayMode::flatten(void* buffer, size_t size) const {
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, id));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, resolution));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, xDpi));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, yDpi));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, refreshRate));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, appVsyncOffset));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, sfVsyncOffset));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, presentationDeadline));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, group));
-    return OK;
-}
-
-status_t DisplayMode::unflatten(const void* buffer, size_t size) {
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &id));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &resolution));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &xDpi));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &yDpi));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &refreshRate));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &appVsyncOffset));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &sfVsyncOffset));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &presentationDeadline));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &group));
-    return OK;
-}
-
-} // namespace android::ui
diff --git a/libs/ui/DynamicDisplayInfo.cpp b/libs/ui/DynamicDisplayInfo.cpp
index 78ba996..f5feea9 100644
--- a/libs/ui/DynamicDisplayInfo.cpp
+++ b/libs/ui/DynamicDisplayInfo.cpp
@@ -18,11 +18,6 @@
 
 #include <cstdint>
 
-#include <ui/FlattenableHelpers.h>
-
-#define RETURN_IF_ERROR(op) \
-    if (const status_t status = (op); status != OK) return status;
-
 namespace android::ui {
 
 std::optional<ui::DisplayMode> DynamicDisplayInfo::getActiveDisplayMode() const {
@@ -34,42 +29,4 @@
     return {};
 }
 
-size_t DynamicDisplayInfo::getFlattenedSize() const {
-    return FlattenableHelpers::getFlattenedSize(supportedDisplayModes) +
-            FlattenableHelpers::getFlattenedSize(activeDisplayModeId) +
-            FlattenableHelpers::getFlattenedSize(supportedColorModes) +
-            FlattenableHelpers::getFlattenedSize(activeColorMode) +
-            FlattenableHelpers::getFlattenedSize(hdrCapabilities) +
-            FlattenableHelpers::getFlattenedSize(autoLowLatencyModeSupported) +
-            FlattenableHelpers::getFlattenedSize(gameContentTypeSupported) +
-            FlattenableHelpers::getFlattenedSize(preferredBootDisplayMode);
-}
-
-status_t DynamicDisplayInfo::flatten(void* buffer, size_t size) const {
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedDisplayModes));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeDisplayModeId));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedColorModes));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeColorMode));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, hdrCapabilities));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, autoLowLatencyModeSupported));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, gameContentTypeSupported));
-    RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, preferredBootDisplayMode));
-    return OK;
-}
-
-status_t DynamicDisplayInfo::unflatten(const void* buffer, size_t size) {
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedDisplayModes));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeDisplayModeId));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedColorModes));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeColorMode));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &hdrCapabilities));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &autoLowLatencyModeSupported));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &gameContentTypeSupported));
-    RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &preferredBootDisplayMode));
-    return OK;
-}
-
 } // namespace android::ui
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 1a42642..1fce31d 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -22,6 +22,7 @@
 #include <aidlcommonsupport/NativeHandle.h>
 #include <android/binder_enums.h>
 #include <android/binder_manager.h>
+#include <gralloctypes/Gralloc4.h>
 #include <hidl/ServiceManagement.h>
 #include <hwbinder/IPCThreadState.h>
 #include <ui/Gralloc4.h>
@@ -358,20 +359,19 @@
             if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
                 continue;
             }
-            if (0 != planeLayoutComponent.offsetInBits % 8) {
-                unlock(bufferHandle);
-                return BAD_VALUE;
-            }
 
-            uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes +
-                    (planeLayoutComponent.offsetInBits / 8);
+            uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes;
+
+            // Note that `offsetInBits` may not be a multiple of 8 for packed formats (e.g. P010)
+            // but we still want to point to the start of the first byte.
+            tmpData += (planeLayoutComponent.offsetInBits / 8);
+
             uint64_t sampleIncrementInBytes;
 
             auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
             switch (type) {
                 case PlaneLayoutComponentType::Y:
-                    if ((ycbcr.y != nullptr) || (planeLayoutComponent.sizeInBits != 8) ||
-                        (planeLayout.sampleIncrementInBits != 8)) {
+                    if ((ycbcr.y != nullptr) || (planeLayout.sampleIncrementInBits % 8 != 0)) {
                         unlock(bufferHandle);
                         return BAD_VALUE;
                     }
@@ -387,7 +387,8 @@
                     }
 
                     sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
-                    if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2)) {
+                    if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) &&
+                        (sampleIncrementInBytes != 4)) {
                         unlock(bufferHandle);
                         return BAD_VALUE;
                     }
@@ -524,6 +525,37 @@
     return decodeFunction(vec, outMetadata);
 }
 
+template <class T>
+status_t Gralloc4Mapper::set(buffer_handle_t bufferHandle, const MetadataType& metadataType,
+                             const T& metadata, EncodeFunction<T> encodeFunction) const {
+    hidl_vec<uint8_t> encodedMetadata;
+    if (const status_t status = encodeFunction(metadata, &encodedMetadata); status != OK) {
+        ALOGE("Encoding metadata(%s) failed with %d", metadataType.name.c_str(), status);
+        return status;
+    }
+    hidl_vec<uint8_t> vec;
+    auto ret =
+            mMapper->set(const_cast<native_handle_t*>(bufferHandle), metadataType, encodedMetadata);
+
+    const Error error = ret.withDefault(kTransactionError);
+    switch (error) {
+        case Error::BAD_DESCRIPTOR:
+        case Error::BAD_BUFFER:
+        case Error::BAD_VALUE:
+        case Error::NO_RESOURCES:
+            ALOGE("set(%s, %" PRIu64 ", ...) failed with %d", metadataType.name.c_str(),
+                  metadataType.value, error);
+            break;
+        // It is not an error to attempt to set metadata that a particular gralloc implementation
+        // happens to not support.
+        case Error::UNSUPPORTED:
+        case Error::NONE:
+            break;
+    }
+
+    return static_cast<status_t>(error);
+}
+
 status_t Gralloc4Mapper::getBufferId(buffer_handle_t bufferHandle, uint64_t* outBufferId) const {
     return get(bufferHandle, gralloc4::MetadataType_BufferId, gralloc4::decodeBufferId,
                outBufferId);
@@ -673,6 +705,12 @@
     return NO_ERROR;
 }
 
+status_t Gralloc4Mapper::setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace) const {
+    return set(bufferHandle, gralloc4::MetadataType_Dataspace,
+               static_cast<aidl::android::hardware::graphics::common::Dataspace>(dataspace),
+               gralloc4::encodeDataspace);
+}
+
 status_t Gralloc4Mapper::getBlendMode(buffer_handle_t bufferHandle,
                                       ui::BlendMode* outBlendMode) const {
     return get(bufferHandle, gralloc4::MetadataType_BlendMode, gralloc4::decodeBlendMode,
@@ -685,24 +723,47 @@
                outSmpte2086);
 }
 
+status_t Gralloc4Mapper::setSmpte2086(buffer_handle_t bufferHandle,
+                                      std::optional<ui::Smpte2086> smpte2086) const {
+    return set(bufferHandle, gralloc4::MetadataType_Smpte2086, smpte2086,
+               gralloc4::encodeSmpte2086);
+}
+
 status_t Gralloc4Mapper::getCta861_3(buffer_handle_t bufferHandle,
                                      std::optional<ui::Cta861_3>* outCta861_3) const {
     return get(bufferHandle, gralloc4::MetadataType_Cta861_3, gralloc4::decodeCta861_3,
                outCta861_3);
 }
 
+status_t Gralloc4Mapper::setCta861_3(buffer_handle_t bufferHandle,
+                                     std::optional<ui::Cta861_3> cta861_3) const {
+    return set(bufferHandle, gralloc4::MetadataType_Cta861_3, cta861_3, gralloc4::encodeCta861_3);
+}
+
 status_t Gralloc4Mapper::getSmpte2094_40(
         buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_40) const {
     return get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, gralloc4::decodeSmpte2094_40,
                outSmpte2094_40);
 }
 
+status_t Gralloc4Mapper::setSmpte2094_40(buffer_handle_t bufferHandle,
+                                         std::optional<std::vector<uint8_t>> smpte2094_40) const {
+    return set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, smpte2094_40,
+               gralloc4::encodeSmpte2094_40);
+}
+
 status_t Gralloc4Mapper::getSmpte2094_10(
         buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_10) const {
     return get(bufferHandle, gralloc4::MetadataType_Smpte2094_10, gralloc4::decodeSmpte2094_10,
                outSmpte2094_10);
 }
 
+status_t Gralloc4Mapper::setSmpte2094_10(buffer_handle_t bufferHandle,
+                                         std::optional<std::vector<uint8_t>> smpte2094_10) const {
+    return set(bufferHandle, gralloc4::MetadataType_Smpte2094_10, smpte2094_10,
+               gralloc4::encodeSmpte2094_10);
+}
+
 template <class T>
 status_t Gralloc4Mapper::getDefault(uint32_t width, uint32_t height, PixelFormat format,
                                     uint32_t layerCount, uint64_t usage,
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 82d6cd5..a98e697 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -281,6 +281,10 @@
     return mMapper->getDataspace(bufferHandle, outDataspace);
 }
 
+status_t GraphicBufferMapper::setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace) {
+    return mMapper->setDataspace(bufferHandle, dataspace);
+}
+
 status_t GraphicBufferMapper::getBlendMode(buffer_handle_t bufferHandle,
                                            ui::BlendMode* outBlendMode) {
     return mMapper->getBlendMode(bufferHandle, outBlendMode);
@@ -291,21 +295,41 @@
     return mMapper->getSmpte2086(bufferHandle, outSmpte2086);
 }
 
+status_t GraphicBufferMapper::setSmpte2086(buffer_handle_t bufferHandle,
+                                           std::optional<ui::Smpte2086> smpte2086) {
+    return mMapper->setSmpte2086(bufferHandle, smpte2086);
+}
+
 status_t GraphicBufferMapper::getCta861_3(buffer_handle_t bufferHandle,
                                           std::optional<ui::Cta861_3>* outCta861_3) {
     return mMapper->getCta861_3(bufferHandle, outCta861_3);
 }
 
+status_t GraphicBufferMapper::setCta861_3(buffer_handle_t bufferHandle,
+                                          std::optional<ui::Cta861_3> cta861_3) {
+    return mMapper->setCta861_3(bufferHandle, cta861_3);
+}
+
 status_t GraphicBufferMapper::getSmpte2094_40(
         buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_40) {
     return mMapper->getSmpte2094_40(bufferHandle, outSmpte2094_40);
 }
 
+status_t GraphicBufferMapper::setSmpte2094_40(buffer_handle_t bufferHandle,
+                                              std::optional<std::vector<uint8_t>> smpte2094_40) {
+    return mMapper->setSmpte2094_40(bufferHandle, smpte2094_40);
+}
+
 status_t GraphicBufferMapper::getSmpte2094_10(
         buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_10) {
     return mMapper->getSmpte2094_10(bufferHandle, outSmpte2094_10);
 }
 
+status_t GraphicBufferMapper::setSmpte2094_10(buffer_handle_t bufferHandle,
+                                              std::optional<std::vector<uint8_t>> smpte2094_10) {
+    return mMapper->setSmpte2094_10(bufferHandle, smpte2094_10);
+}
+
 status_t GraphicBufferMapper::getDefaultPixelFormatFourCC(uint32_t width, uint32_t height,
                                                           PixelFormat format, uint32_t layerCount,
                                                           uint64_t usage,
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
deleted file mode 100644
index aec2fac..0000000
--- a/libs/ui/HdrCapabilities.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#include <ui/HdrCapabilities.h>
-
-namespace android {
-
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
-#endif
-
-size_t HdrCapabilities::getFlattenedSize() const {
-    return  sizeof(mMaxLuminance) +
-            sizeof(mMaxAverageLuminance) +
-            sizeof(mMinLuminance) +
-            sizeof(int32_t) +
-            mSupportedHdrTypes.size() * sizeof(ui::Hdr);
-}
-
-status_t HdrCapabilities::flatten(void* buffer, size_t size) const {
-
-    if (size < getFlattenedSize()) {
-        return NO_MEMORY;
-    }
-
-    int32_t* const buf = static_cast<int32_t*>(buffer);
-    reinterpret_cast<float&>(buf[0]) = mMaxLuminance;
-    reinterpret_cast<float&>(buf[1]) = mMaxAverageLuminance;
-    reinterpret_cast<float&>(buf[2]) = mMinLuminance;
-    buf[3] = static_cast<int32_t>(mSupportedHdrTypes.size());
-    for (size_t i = 0, c = mSupportedHdrTypes.size(); i < c; ++i) {
-        buf[4 + i] = static_cast<int32_t>(mSupportedHdrTypes[i]);
-    }
-    return NO_ERROR;
-}
-
-status_t HdrCapabilities::unflatten(void const* buffer, size_t size) {
-
-    size_t minSize = sizeof(mMaxLuminance) +
-                     sizeof(mMaxAverageLuminance) +
-                     sizeof(mMinLuminance) +
-                     sizeof(int32_t);
-
-    if (size < minSize) {
-        return NO_MEMORY;
-    }
-
-    int32_t const * const buf = static_cast<int32_t const *>(buffer);
-    const size_t itemCount = size_t(buf[3]);
-
-    // check the buffer is large enough
-    if (size < minSize + itemCount * sizeof(int32_t)) {
-        return BAD_VALUE;
-    }
-
-    mMaxLuminance        = reinterpret_cast<float const&>(buf[0]);
-    mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]);
-    mMinLuminance        = reinterpret_cast<float const&>(buf[2]);
-    if (itemCount) {
-        mSupportedHdrTypes.resize(itemCount);
-        for (size_t i = 0; i < itemCount; ++i) {
-            mSupportedHdrTypes[i] = static_cast<ui::Hdr>(buf[4 + i]);
-        }
-    }
-    return NO_ERROR;
-}
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-} // namespace android
diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h
index 56f68e7..a2791a6 100644
--- a/libs/ui/include/ui/DisplayMode.h
+++ b/libs/ui/include/ui/DisplayMode.h
@@ -29,7 +29,7 @@
 using DisplayModeId = int32_t;
 
 // Mode supported by physical display.
-struct DisplayMode : LightFlattenable<DisplayMode> {
+struct DisplayMode {
     DisplayModeId id;
     ui::Size resolution;
     float xDpi = 0;
@@ -40,11 +40,6 @@
     nsecs_t sfVsyncOffset = 0;
     nsecs_t presentationDeadline = 0;
     int32_t group = -1;
-
-    bool isFixedSize() const { return false; }
-    size_t getFlattenedSize() const;
-    status_t flatten(void* buffer, size_t size) const;
-    status_t unflatten(const void* buffer, size_t size);
 };
 
 } // namespace android::ui
diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h
index ce75a65..8c9fe4c 100644
--- a/libs/ui/include/ui/DynamicDisplayInfo.h
+++ b/libs/ui/include/ui/DynamicDisplayInfo.h
@@ -24,12 +24,11 @@
 
 #include <ui/GraphicTypes.h>
 #include <ui/HdrCapabilities.h>
-#include <utils/Flattenable.h>
 
 namespace android::ui {
 
 // Information about a physical display which may change on hotplug reconnect.
-struct DynamicDisplayInfo : LightFlattenable<DynamicDisplayInfo> {
+struct DynamicDisplayInfo {
     std::vector<ui::DisplayMode> supportedDisplayModes;
 
     // This struct is going to be serialized over binder, so
@@ -53,11 +52,6 @@
     ui::DisplayModeId preferredBootDisplayMode;
 
     std::optional<ui::DisplayMode> getActiveDisplayMode() const;
-
-    bool isFixedSize() const { return false; }
-    size_t getFlattenedSize() const;
-    status_t flatten(void* buffer, size_t size) const;
-    status_t unflatten(const void* buffer, size_t size);
 };
 
 } // namespace android::ui
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
index 753b0a6..6101d4b 100644
--- a/libs/ui/include/ui/Gralloc.h
+++ b/libs/ui/include/ui/Gralloc.h
@@ -161,6 +161,10 @@
                                   ui::Dataspace* /*outDataspace*/) const {
         return INVALID_OPERATION;
     }
+    virtual status_t setDataspace(buffer_handle_t /*bufferHandle*/,
+                                  ui::Dataspace /*dataspace*/) const {
+        return INVALID_OPERATION;
+    }
     virtual status_t getBlendMode(buffer_handle_t /*bufferHandle*/,
                                   ui::BlendMode* /*outBlendMode*/) const {
         return INVALID_OPERATION;
@@ -169,21 +173,36 @@
                                   std::optional<ui::Smpte2086>* /*outSmpte2086*/) const {
         return INVALID_OPERATION;
     }
+    virtual status_t setSmpte2086(buffer_handle_t /*bufferHandle*/,
+                                  std::optional<ui::Smpte2086> /*smpte2086*/) const {
+        return INVALID_OPERATION;
+    }
     virtual status_t getCta861_3(buffer_handle_t /*bufferHandle*/,
                                  std::optional<ui::Cta861_3>* /*outCta861_3*/) const {
         return INVALID_OPERATION;
     }
+    virtual status_t setCta861_3(buffer_handle_t /*bufferHandle*/,
+                                 std::optional<ui::Cta861_3> /*cta861_3*/) const {
+        return INVALID_OPERATION;
+    }
     virtual status_t getSmpte2094_40(
             buffer_handle_t /*bufferHandle*/,
             std::optional<std::vector<uint8_t>>* /*outSmpte2094_40*/) const {
         return INVALID_OPERATION;
     }
+    virtual status_t setSmpte2094_40(buffer_handle_t /*bufferHandle*/,
+                                     std::optional<std::vector<uint8_t>> /*smpte2094_40*/) const {
+        return INVALID_OPERATION;
+    }
     virtual status_t getSmpte2094_10(
             buffer_handle_t /*bufferHandle*/,
             std::optional<std::vector<uint8_t>>* /*outSmpte2094_10*/) const {
         return INVALID_OPERATION;
     }
-
+    virtual status_t setSmpte2094_10(buffer_handle_t /*bufferHandle*/,
+                                     std::optional<std::vector<uint8_t>> /*smpte2094_10*/) const {
+        return INVALID_OPERATION;
+    }
     virtual status_t getDefaultPixelFormatFourCC(uint32_t /*width*/, uint32_t /*height*/,
                                                  PixelFormat /*format*/, uint32_t /*layerCount*/,
                                                  uint64_t /*usage*/,
diff --git a/libs/ui/include/ui/Gralloc4.h b/libs/ui/include/ui/Gralloc4.h
index fe38709..cf023c9 100644
--- a/libs/ui/include/ui/Gralloc4.h
+++ b/libs/ui/include/ui/Gralloc4.h
@@ -102,16 +102,24 @@
     status_t getPlaneLayouts(buffer_handle_t bufferHandle,
                              std::vector<ui::PlaneLayout>* outPlaneLayouts) const override;
     status_t getDataspace(buffer_handle_t bufferHandle, ui::Dataspace* outDataspace) const override;
+    status_t setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace) const override;
     status_t getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode* outBlendMode) const override;
     status_t getSmpte2086(buffer_handle_t bufferHandle,
                           std::optional<ui::Smpte2086>* outSmpte2086) const override;
+    status_t setSmpte2086(buffer_handle_t bufferHandle,
+                          std::optional<ui::Smpte2086> smpte2086) const override;
     status_t getCta861_3(buffer_handle_t bufferHandle,
                          std::optional<ui::Cta861_3>* outCta861_3) const override;
+    status_t setCta861_3(buffer_handle_t bufferHandle,
+                         std::optional<ui::Cta861_3> cta861_3) const override;
     status_t getSmpte2094_40(buffer_handle_t bufferHandle,
                              std::optional<std::vector<uint8_t>>* outSmpte2094_40) const override;
+    status_t setSmpte2094_40(buffer_handle_t bufferHandle,
+                             std::optional<std::vector<uint8_t>> smpte2094_40) const override;
     status_t getSmpte2094_10(buffer_handle_t bufferHandle,
                              std::optional<std::vector<uint8_t>>* outSmpte2094_10) const override;
-
+    status_t setSmpte2094_10(buffer_handle_t bufferHandle,
+                             std::optional<std::vector<uint8_t>> smpte2094_10) const override;
     status_t getDefaultPixelFormatFourCC(uint32_t width, uint32_t height, PixelFormat format,
                                          uint32_t layerCount, uint64_t usage,
                                          uint32_t* outPixelFormatFourCC) const override;
@@ -157,6 +165,8 @@
 
     template <class T>
     using DecodeFunction = status_t (*)(const hardware::hidl_vec<uint8_t>& input, T* output);
+    template <class T>
+    using EncodeFunction = status_t (*)(const T& input, hardware::hidl_vec<uint8_t>* output);
 
     template <class T>
     status_t get(
@@ -165,6 +175,12 @@
             DecodeFunction<T> decodeFunction, T* outMetadata) const;
 
     template <class T>
+    status_t set(
+            buffer_handle_t bufferHandle,
+            const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType,
+            const T& metadata, EncodeFunction<T> encodeFunction) const;
+
+    template <class T>
     status_t getDefault(
             uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
             uint64_t usage,
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 257c155..507fa35 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -121,13 +121,20 @@
     status_t getPlaneLayouts(buffer_handle_t bufferHandle,
                              std::vector<ui::PlaneLayout>* outPlaneLayouts);
     status_t getDataspace(buffer_handle_t bufferHandle, ui::Dataspace* outDataspace);
+    status_t setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace);
     status_t getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode* outBlendMode);
     status_t getSmpte2086(buffer_handle_t bufferHandle, std::optional<ui::Smpte2086>* outSmpte2086);
+    status_t setSmpte2086(buffer_handle_t bufferHandle, std::optional<ui::Smpte2086> smpte2086);
     status_t getCta861_3(buffer_handle_t bufferHandle, std::optional<ui::Cta861_3>* outCta861_3);
+    status_t setCta861_3(buffer_handle_t bufferHandle, std::optional<ui::Cta861_3> cta861_3);
     status_t getSmpte2094_40(buffer_handle_t bufferHandle,
                              std::optional<std::vector<uint8_t>>* outSmpte2094_40);
+    status_t setSmpte2094_40(buffer_handle_t bufferHandle,
+                             std::optional<std::vector<uint8_t>> smpte2094_40);
     status_t getSmpte2094_10(buffer_handle_t bufferHandle,
                              std::optional<std::vector<uint8_t>>* outSmpte2094_10);
+    status_t setSmpte2094_10(buffer_handle_t bufferHandle,
+                             std::optional<std::vector<uint8_t>> smpte2094_10);
 
     /**
      * Gets the default metadata for a gralloc buffer allocated with the given parameters.
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index 4bdacb0..8661c36 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -62,5 +62,23 @@
 using Compression = aidl::android::hardware::graphics::common::Compression;
 using Interlaced = aidl::android::hardware::graphics::common::Interlaced;
 
+inline aidl::android::hardware::graphics::common::XyColor translate(const android_xy_color& color) {
+    return aidl::android::hardware::graphics::common::XyColor{.x = color.x, .y = color.y};
+}
+
+inline Smpte2086 translate(const android_smpte2086_metadata& metadata) {
+    return Smpte2086{.primaryRed = translate(metadata.displayPrimaryRed),
+                     .primaryGreen = translate(metadata.displayPrimaryGreen),
+                     .primaryBlue = translate(metadata.displayPrimaryBlue),
+                     .whitePoint = translate(metadata.whitePoint),
+                     .maxLuminance = metadata.maxLuminance,
+                     .minLuminance = metadata.minLuminance};
+}
+
+inline Cta861_3 translate(const android_cta861_3_metadata& metadata) {
+    return Cta861_3{.maxContentLightLevel = metadata.maxContentLightLevel,
+                    .maxFrameAverageLightLevel = metadata.maxFrameAverageLightLevel};
+}
+
 }  // namespace ui
 }  // namespace android
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 813adde..ae54223 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -22,12 +22,10 @@
 #include <vector>
 
 #include <ui/GraphicTypes.h>
-#include <utils/Flattenable.h>
 
 namespace android {
 
-class HdrCapabilities : public LightFlattenable<HdrCapabilities>
-{
+class HdrCapabilities {
 public:
     HdrCapabilities(const std::vector<ui::Hdr>& types,
             float maxLuminance, float maxAverageLuminance, float minLuminance)
@@ -49,12 +47,6 @@
     float getDesiredMaxAverageLuminance() const { return mMaxAverageLuminance; }
     float getDesiredMinLuminance() const { return mMinLuminance; }
 
-    // Flattenable protocol
-    bool isFixedSize() const { return false; }
-    size_t getFlattenedSize() const;
-    status_t flatten(void* buffer, size_t size) const;
-    status_t unflatten(void const* buffer, size_t size);
-
 private:
     std::vector<ui::Hdr> mSupportedHdrTypes;
     float mMaxLuminance;
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 3a4b6c5..2a3924b 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -202,9 +202,11 @@
         coords += "}";
     }
     return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32
-                        ", source=%s, action=%s, pointerCount=%" PRIu32 " pointers=%s)",
+                        ", source=%s, action=%s, pointerCount=%" PRIu32
+                        " pointers=%s, flags=0x%08x)",
                         id, eventTime, deviceId, inputEventSourceToString(source).c_str(),
-                        MotionEvent::actionToString(action).c_str(), pointerCount, coords.c_str());
+                        MotionEvent::actionToString(action).c_str(), pointerCount, coords.c_str(),
+                        flags);
 }
 
 void NotifyMotionArgs::notify(InputListenerInterface& listener) const {
diff --git a/services/inputflinger/PreferStylusOverTouchBlocker.cpp b/services/inputflinger/PreferStylusOverTouchBlocker.cpp
index ad639b4..beec2e1 100644
--- a/services/inputflinger/PreferStylusOverTouchBlocker.cpp
+++ b/services/inputflinger/PreferStylusOverTouchBlocker.cpp
@@ -15,78 +15,163 @@
  */
 
 #include "PreferStylusOverTouchBlocker.h"
-
-#include <android-base/stringprintf.h>
-
-using android::base::StringPrintf;
-
-static const char* toString(bool value) {
-    return value ? "true" : "false";
-}
+#include <input/PrintTools.h>
 
 namespace android {
 
-ftl::StaticVector<NotifyMotionArgs, 2> PreferStylusOverTouchBlocker::processMotion(
-        const NotifyMotionArgs& args) {
-    const bool isStylusEvent = isFromSource(args.source, AINPUT_SOURCE_STYLUS);
-    if (isStylusEvent) {
-        for (size_t i = 0; i < args.pointerCount; i++) {
-            // Make sure we are canceling stylus pointers
-            const int32_t toolType = args.pointerProperties[i].toolType;
-            LOG_ALWAYS_FATAL_IF(toolType != AMOTION_EVENT_TOOL_TYPE_STYLUS &&
-                                        toolType != AMOTION_EVENT_TOOL_TYPE_ERASER,
-                                "The pointer %zu has toolType=%i, but the source is STYLUS. If "
-                                "simultaneous touch and stylus is supported, "
-                                "'PreferStylusOverTouchBlocker' should be disabled.",
-                                i, toolType);
+static std::pair<bool, bool> checkToolType(const NotifyMotionArgs& args) {
+    bool hasStylus = false;
+    bool hasTouch = false;
+    for (size_t i = 0; i < args.pointerCount; i++) {
+        // Make sure we are canceling stylus pointers
+        const int32_t toolType = args.pointerProperties[i].toolType;
+        if (toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS ||
+            toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
+            hasStylus = true;
+        }
+        if (toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) {
+            hasTouch = true;
         }
     }
-    const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN;
+    return std::make_pair(hasTouch, hasStylus);
+}
+
+/**
+ * Intersect two sets in-place, storing the result in 'set1'.
+ * Find elements in set1 that are not present in set2 and delete them,
+ * relying on the fact that the two sets are ordered.
+ */
+template <typename T>
+static void intersectInPlace(std::set<T>& set1, const std::set<T>& set2) {
+    typename std::set<T>::iterator it1 = set1.begin();
+    typename std::set<T>::const_iterator it2 = set2.begin();
+    while (it1 != set1.end() && it2 != set2.end()) {
+        const T& element1 = *it1;
+        const T& element2 = *it2;
+        if (element1 < element2) {
+            // This element is not present in set2. Remove it from set1.
+            it1 = set1.erase(it1);
+            continue;
+        }
+        if (element2 < element1) {
+            it2++;
+        }
+        if (element1 == element2) {
+            it1++;
+            it2++;
+        }
+    }
+    // Remove the rest of the elements in set1 because set2 is already exhausted.
+    set1.erase(it1, set1.end());
+}
+
+/**
+ * Same as above, but prune a map
+ */
+template <typename K, class V>
+static void intersectInPlace(std::map<K, V>& map, const std::set<K>& set2) {
+    typename std::map<K, V>::iterator it1 = map.begin();
+    typename std::set<K>::const_iterator it2 = set2.begin();
+    while (it1 != map.end() && it2 != set2.end()) {
+        const auto& [key, _] = *it1;
+        const K& element2 = *it2;
+        if (key < element2) {
+            // This element is not present in set2. Remove it from map.
+            it1 = map.erase(it1);
+            continue;
+        }
+        if (element2 < key) {
+            it2++;
+        }
+        if (key == element2) {
+            it1++;
+            it2++;
+        }
+    }
+    // Remove the rest of the elements in map because set2 is already exhausted.
+    map.erase(it1, map.end());
+}
+
+// -------------------------------- PreferStylusOverTouchBlocker -----------------------------------
+
+std::vector<NotifyMotionArgs> PreferStylusOverTouchBlocker::processMotion(
+        const NotifyMotionArgs& args) {
+    const auto [hasTouch, hasStylus] = checkToolType(args);
     const bool isUpOrCancel =
             args.action == AMOTION_EVENT_ACTION_UP || args.action == AMOTION_EVENT_ACTION_CANCEL;
+
+    if (hasTouch && hasStylus) {
+        mDevicesWithMixedToolType.insert(args.deviceId);
+    }
+    // Handle the case where mixed touch and stylus pointers are reported. Add this device to the
+    // ignore list, since it clearly supports simultaneous touch and stylus.
+    if (mDevicesWithMixedToolType.find(args.deviceId) != mDevicesWithMixedToolType.end()) {
+        // This event comes from device with mixed stylus and touch event. Ignore this device.
+        if (mCanceledDevices.find(args.deviceId) != mCanceledDevices.end()) {
+            // If we started to cancel events from this device, continue to do so to keep
+            // the stream consistent. It should happen at most once per "mixed" device.
+            if (isUpOrCancel) {
+                mCanceledDevices.erase(args.deviceId);
+                mLastTouchEvents.erase(args.deviceId);
+            }
+            return {};
+        }
+        return {args};
+    }
+
+    const bool isStylusEvent = hasStylus;
+    const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN;
+
     if (isStylusEvent) {
         if (isDown) {
             // Reject all touch while stylus is down
-            mIsStylusDown = true;
-            if (mIsTouchDown && !mCurrentTouchIsCanceled) {
-                // Cancel touch!
-                mCurrentTouchIsCanceled = true;
-                mLastTouchEvent.action = AMOTION_EVENT_ACTION_CANCEL;
-                mLastTouchEvent.flags |= AMOTION_EVENT_FLAG_CANCELED;
-                mLastTouchEvent.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
-                return {mLastTouchEvent, args};
+            mActiveStyli.insert(args.deviceId);
+
+            // Cancel all current touch!
+            std::vector<NotifyMotionArgs> result;
+            for (auto& [deviceId, lastTouchEvent] : mLastTouchEvents) {
+                if (mCanceledDevices.find(deviceId) != mCanceledDevices.end()) {
+                    // Already canceled, go to next one.
+                    continue;
+                }
+                // Not yet canceled. Cancel it.
+                lastTouchEvent.action = AMOTION_EVENT_ACTION_CANCEL;
+                lastTouchEvent.flags |= AMOTION_EVENT_FLAG_CANCELED;
+                lastTouchEvent.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+                result.push_back(lastTouchEvent);
+                mCanceledDevices.insert(deviceId);
             }
+            result.push_back(args);
+            return result;
         }
         if (isUpOrCancel) {
-            mIsStylusDown = false;
+            mActiveStyli.erase(args.deviceId);
         }
         // Never drop stylus events
         return {args};
     }
 
-    const bool isTouchEvent =
-            isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN) && !isStylusEvent;
+    const bool isTouchEvent = hasTouch;
     if (isTouchEvent) {
-        if (mIsStylusDown) {
-            mCurrentTouchIsCanceled = true;
+        // Suppress the current gesture if any stylus is still down
+        if (!mActiveStyli.empty()) {
+            mCanceledDevices.insert(args.deviceId);
         }
+
+        const bool shouldDrop = mCanceledDevices.find(args.deviceId) != mCanceledDevices.end();
+        if (isUpOrCancel) {
+            mCanceledDevices.erase(args.deviceId);
+            mLastTouchEvents.erase(args.deviceId);
+        }
+
         // If we already canceled the current gesture, then continue to drop events from it, even if
         // the stylus has been lifted.
-        if (mCurrentTouchIsCanceled) {
-            if (isUpOrCancel) {
-                mCurrentTouchIsCanceled = false;
-            }
+        if (shouldDrop) {
             return {};
         }
 
-        // Update state
-        mLastTouchEvent = args;
-        if (isDown) {
-            mIsTouchDown = true;
-        }
-        if (isUpOrCancel) {
-            mIsTouchDown = false;
-            mCurrentTouchIsCanceled = false;
+        if (!isUpOrCancel) {
+            mLastTouchEvents[args.deviceId] = args;
         }
         return {args};
     }
@@ -95,12 +180,36 @@
     return {args};
 }
 
-std::string PreferStylusOverTouchBlocker::dump() {
+void PreferStylusOverTouchBlocker::notifyInputDevicesChanged(
+        const std::vector<InputDeviceInfo>& inputDevices) {
+    std::set<int32_t> presentDevices;
+    for (const InputDeviceInfo& device : inputDevices) {
+        presentDevices.insert(device.getId());
+    }
+    // Only keep the devices that are still present.
+    intersectInPlace(mDevicesWithMixedToolType, presentDevices);
+    intersectInPlace(mLastTouchEvents, presentDevices);
+    intersectInPlace(mCanceledDevices, presentDevices);
+    intersectInPlace(mActiveStyli, presentDevices);
+}
+
+void PreferStylusOverTouchBlocker::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
+    mDevicesWithMixedToolType.erase(args.deviceId);
+    mLastTouchEvents.erase(args.deviceId);
+    mCanceledDevices.erase(args.deviceId);
+    mActiveStyli.erase(args.deviceId);
+}
+
+static std::string dumpArgs(const NotifyMotionArgs& args) {
+    return args.dump();
+}
+
+std::string PreferStylusOverTouchBlocker::dump() const {
     std::string out;
-    out += StringPrintf("mIsTouchDown: %s\n", toString(mIsTouchDown));
-    out += StringPrintf("mIsStylusDown: %s\n", toString(mIsStylusDown));
-    out += StringPrintf("mLastTouchEvent: %s\n", mLastTouchEvent.dump().c_str());
-    out += StringPrintf("mCurrentTouchIsCanceled: %s\n", toString(mCurrentTouchIsCanceled));
+    out += "mActiveStyli: " + dumpSet(mActiveStyli) + "\n";
+    out += "mLastTouchEvents: " + dumpMap(mLastTouchEvents, constToString, dumpArgs) + "\n";
+    out += "mDevicesWithMixedToolType: " + dumpSet(mDevicesWithMixedToolType) + "\n";
+    out += "mCanceledDevices: " + dumpSet(mCanceledDevices) + "\n";
     return out;
 }
 
diff --git a/services/inputflinger/PreferStylusOverTouchBlocker.h b/services/inputflinger/PreferStylusOverTouchBlocker.h
index 3f56161..716dc4d 100644
--- a/services/inputflinger/PreferStylusOverTouchBlocker.h
+++ b/services/inputflinger/PreferStylusOverTouchBlocker.h
@@ -16,66 +16,50 @@
 
 #pragma once
 
-#include <ftl/static_vector.h>
 #include <optional>
+#include <set>
 #include "InputListener.h"
 
 namespace android {
 
 /**
- * When stylus is down, we ignore all touch.
+ * When stylus is down, all touch is ignored.
  * TODO(b/210159205): delete this when simultaneous stylus and touch is supported
  */
 class PreferStylusOverTouchBlocker {
 public:
     /**
-     * Process the provided event and emit up to 2 events in response.
+     * Process the provided event and emit 0 or more events that should be used instead of it.
      * In the majority of cases, the returned result will just be the provided args (array with
      * only 1 element), unmodified.
      *
      * If the gesture should be blocked, the returned result may be:
      *
      * a) An empty array, if the current event should just be ignored completely
-     * b) An array of 2 elements, containing an event with ACTION_CANCEL and the current event.
+     * b) An array of N elements, containing N-1 events with ACTION_CANCEL and the current event.
      *
-     * bool is set to 'true'.
-     * NotifyMotionArgs potentially contains an event that should be used to cancel the existing
-     * gesture.
-     *
-     * If the event should not be blocked, bool contains 'false'.
+     * The returned result is intended to be reinjected into the original event stream in
+     * replacement of the incoming event.
      */
-    ftl::StaticVector<NotifyMotionArgs, 2> processMotion(const NotifyMotionArgs& args);
-    std::string dump();
+    std::vector<NotifyMotionArgs> processMotion(const NotifyMotionArgs& args);
+    std::string dump() const;
+
+    void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices);
+
+    void notifyDeviceReset(const NotifyDeviceResetArgs& args);
 
 private:
-    bool mIsTouchDown = false;
-    bool mIsStylusDown = false;
-    // Provide some default values for the stored MotionEvent to allow printint the event before
-    // any real event is received.
-    NotifyMotionArgs mLastTouchEvent{0 /*id*/,
-                                     0 /*eventTime*/,
-                                     0 /*readTime*/,
-                                     0 /*deviceId*/,
-                                     AINPUT_SOURCE_TOUCHSCREEN,
-                                     0 /*displayId*/,
-                                     0 /*policyFlags*/,
-                                     0 /*action*/,
-                                     0 /*actionButton*/,
-                                     0 /*flags*/,
-                                     0 /*metaState*/,
-                                     0 /*buttonState*/,
-                                     MotionClassification::NONE,
-                                     AMOTION_EVENT_EDGE_FLAG_NONE,
-                                     0 /*pointerCount*/,
-                                     nullptr /*properties*/,
-                                     nullptr /*coords*/,
-                                     0. /*xPrecision*/,
-                                     0. /*yPrecision*/,
-                                     AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                     AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                     0 /*downTime*/,
-                                     {}};
-    bool mCurrentTouchIsCanceled = false;
+    // Stores the device id's of styli that are currently down.
+    std::set<int32_t /*deviceId*/> mActiveStyli;
+    // For each device, store the last touch event as long as the touch is down. Upon liftoff,
+    // the entry is erased.
+    std::map<int32_t /*deviceId*/, NotifyMotionArgs> mLastTouchEvents;
+    // Device ids of devices for which the current touch gesture is canceled.
+    std::set<int32_t /*deviceId*/> mCanceledDevices;
+
+    // Device ids of input devices where we encountered simultaneous touch and stylus
+    // events. For these devices, we don't do any event processing (nothing is blocked or altered).
+    std::set<int32_t /*deviceId*/> mDevicesWithMixedToolType;
 };
 
 } // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
index fb3962e..b69e16a 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.cpp
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -368,6 +368,14 @@
 }
 
 void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) {
+    const std::vector<NotifyMotionArgs> processedArgs =
+            mPreferStylusOverTouchBlocker.processMotion(*args);
+    for (const NotifyMotionArgs& loopArgs : processedArgs) {
+        notifyMotionInner(&loopArgs);
+    }
+}
+
+void UnwantedInteractionBlocker::notifyMotionInner(const NotifyMotionArgs* args) {
     auto it = mPalmRejectors.find(args->deviceId);
     const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source);
     if (!sendToPalmRejector) {
@@ -401,6 +409,7 @@
         mPalmRejectors.emplace(args->deviceId, info);
     }
     mListener.notifyDeviceReset(args);
+    mPreferStylusOverTouchBlocker.notifyDeviceReset(*args);
 }
 
 void UnwantedInteractionBlocker::notifyPointerCaptureChanged(
@@ -437,10 +446,13 @@
         auto const& [deviceId, _] = item;
         return devicesToKeep.find(deviceId) == devicesToKeep.end();
     });
+    mPreferStylusOverTouchBlocker.notifyInputDevicesChanged(inputDevices);
 }
 
 void UnwantedInteractionBlocker::dump(std::string& dump) {
     dump += "UnwantedInteractionBlocker:\n";
+    dump += "  mPreferStylusOverTouchBlocker:\n";
+    dump += addPrefix(mPreferStylusOverTouchBlocker.dump(), "    ");
     dump += StringPrintf("  mEnablePalmRejection: %s\n", toString(mEnablePalmRejection));
     dump += StringPrintf("  isPalmRejectionEnabled (flag value): %s\n",
                          toString(isPalmRejectionEnabled()));
diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h
index 14068fd..8a1cd72 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.h
+++ b/services/inputflinger/UnwantedInteractionBlocker.h
@@ -23,6 +23,8 @@
 #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_util.h"
 #include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
 
+#include "PreferStylusOverTouchBlocker.h"
+
 namespace android {
 
 // --- Functions for manipulation of event streams
@@ -88,9 +90,14 @@
     InputListenerInterface& mListener;
     const bool mEnablePalmRejection;
 
+    // When stylus is down, ignore touch
+    PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker;
+
     // Detect and reject unwanted palms on screen
     // Use a separate palm rejector for every touch device.
     std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors;
+    // TODO(b/210159205): delete this when simultaneous stylus and touch is supported
+    void notifyMotionInner(const NotifyMotionArgs* args);
 };
 
 class SlotState {
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 8bd3899..d6a6bd2 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -60,10 +60,11 @@
 #define INDENT3 "      "
 
 using android::base::StringPrintf;
-using namespace android::flag_operators;
 
 namespace android {
 
+using namespace ftl::flag_operators;
+
 static const char* DEVICE_INPUT_PATH = "/dev/input";
 // v4l2 devices go directly into /dev
 static const char* DEVICE_PATH = "/dev";
@@ -302,7 +303,8 @@
 
 // --- Global Functions ---
 
-Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis, Flags<InputDeviceClass> deviceClasses) {
+ftl::Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis,
+                                             ftl::Flags<InputDeviceClass> deviceClasses) {
     // Touch devices get dibs on touch-related axes.
     if (deviceClasses.test(InputDeviceClass::TOUCH)) {
         switch (axis) {
@@ -765,10 +767,10 @@
     return device != nullptr ? device->identifier : InputDeviceIdentifier();
 }
 
-Flags<InputDeviceClass> EventHub::getDeviceClasses(int32_t deviceId) const {
+ftl::Flags<InputDeviceClass> EventHub::getDeviceClasses(int32_t deviceId) const {
     std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    return device != nullptr ? device->classes : Flags<InputDeviceClass>(0);
+    return device != nullptr ? device->classes : ftl::Flags<InputDeviceClass>(0);
 }
 
 int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
@@ -1909,7 +1911,7 @@
 }
 
 void EventHub::reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
-                                                    Flags<InputDeviceClass> classes) {
+                                                    ftl::Flags<InputDeviceClass> classes) {
     SHA256_CTX ctx;
     SHA256_Init(&ctx);
     SHA256_Update(&ctx, reinterpret_cast<const uint8_t*>(identifier.uniqueId.c_str()),
@@ -2191,7 +2193,7 @@
     }
 
     // If the device isn't recognized as something we handle, don't monitor it.
-    if (device->classes == Flags<InputDeviceClass>(0)) {
+    if (device->classes == ftl::Flags<InputDeviceClass>(0)) {
         ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(),
               device->identifier.name.c_str());
         return;
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index a050963..ba5083b 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -18,9 +18,10 @@
 
 #include "InputDevice.h"
 
-#include <ftl/Flags.h>
 #include <algorithm>
 
+#include <ftl/flags.h>
+
 #include "CursorInputMapper.h"
 #include "ExternalStylusInputMapper.h"
 #include "InputReaderContext.h"
@@ -145,7 +146,7 @@
         return;
     }
     std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
-    Flags<InputDeviceClass> classes = contextPtr->getDeviceClasses();
+    ftl::Flags<InputDeviceClass> classes = contextPtr->getDeviceClasses();
     std::vector<std::unique_ptr<InputMapper>> mappers;
 
     // Check if we should skip population
@@ -236,7 +237,7 @@
 void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,
                             uint32_t changes) {
     mSources = 0;
-    mClasses = Flags<InputDeviceClass>(0);
+    mClasses = ftl::Flags<InputDeviceClass>(0);
     mControllerNumber = 0;
 
     for_each_subdevice([this](InputDeviceContext& context) {
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 18e912d..130c556 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -19,13 +19,12 @@
 
 #include <bitset>
 #include <climits>
+#include <filesystem>
 #include <unordered_map>
 #include <vector>
 
-#include <ftl/Flags.h>
-#include <filesystem>
-
 #include <batteryservice/BatteryService.h>
+#include <ftl/flags.h>
 #include <input/Input.h>
 #include <input/InputDevice.h>
 #include <input/KeyCharacterMap.h>
@@ -189,7 +188,7 @@
     int32_t id;
     std::string name;
     std::optional<int32_t> maxBrightness;
-    Flags<InputLightClass> flags;
+    ftl::Flags<InputLightClass> flags;
     std::array<int32_t, COLOR_NUM> rgbIndex;
     std::filesystem::path path;
 };
@@ -198,7 +197,7 @@
 struct RawBatteryInfo {
     int32_t id;
     std::string name;
-    Flags<InputBatteryClass> flags;
+    ftl::Flags<InputBatteryClass> flags;
     std::filesystem::path path;
 };
 
@@ -206,7 +205,8 @@
  * Gets the class that owns an axis, in cases where multiple classes might claim
  * the same axis for different purposes.
  */
-extern Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis, Flags<InputDeviceClass> deviceClasses);
+extern ftl::Flags<InputDeviceClass> getAbsAxisUsage(int32_t axis,
+                                                    ftl::Flags<InputDeviceClass> deviceClasses);
 
 /*
  * Grand Central Station for events.
@@ -239,7 +239,7 @@
         FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
     };
 
-    virtual Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const = 0;
+    virtual ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const = 0;
 
     virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0;
 
@@ -436,7 +436,7 @@
 public:
     EventHub();
 
-    Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override final;
+    ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override final;
 
     InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override final;
 
@@ -559,7 +559,7 @@
 
         std::unique_ptr<TouchVideoDevice> videoDevice;
 
-        Flags<InputDeviceClass> classes;
+        ftl::Flags<InputDeviceClass> classes;
 
         BitArray<KEY_MAX> keyBitmask;
         BitArray<KEY_MAX> keyState;
@@ -662,7 +662,7 @@
     int32_t getNextControllerNumberLocked(const std::string& name) REQUIRES(mLock);
     void releaseControllerNumberLocked(int32_t num) REQUIRES(mLock);
     void reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
-                                              Flags<InputDeviceClass> classes) REQUIRES(mLock);
+                                              ftl::Flags<InputDeviceClass> classes) REQUIRES(mLock);
 
     const std::unordered_map<int32_t, RawBatteryInfo>& getBatteryInfoLocked(int32_t deviceId) const
             REQUIRES(mLock);
@@ -725,6 +725,6 @@
     bool mPendingINotify;
 };
 
-}; // namespace android
+} // namespace android
 
 #endif // _RUNTIME_EVENT_HUB_H
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 694daa9..728020e 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -17,12 +17,12 @@
 #ifndef _UI_INPUTREADER_INPUT_DEVICE_H
 #define _UI_INPUTREADER_INPUT_DEVICE_H
 
-#include <ftl/Flags.h>
+#include <ftl/flags.h>
 #include <input/DisplayViewport.h>
 #include <input/InputDevice.h>
 #include <input/PropertyMap.h>
-#include <stdint.h>
 
+#include <cstdint>
 #include <optional>
 #include <unordered_map>
 #include <vector>
@@ -53,7 +53,7 @@
     inline int32_t getGeneration() const { return mGeneration; }
     inline const std::string getName() const { return mIdentifier.name; }
     inline const std::string getDescriptor() { return mIdentifier.descriptor; }
-    inline Flags<InputDeviceClass> getClasses() const { return mClasses; }
+    inline ftl::Flags<InputDeviceClass> getClasses() const { return mClasses; }
     inline uint32_t getSources() const { return mSources; }
     inline bool hasEventHubDevices() const { return !mDevices.empty(); }
 
@@ -160,7 +160,7 @@
     int32_t mControllerNumber;
     InputDeviceIdentifier mIdentifier;
     std::string mAlias;
-    Flags<InputDeviceClass> mClasses;
+    ftl::Flags<InputDeviceClass> mClasses;
 
     // map from eventHubId to device context and mappers
     using MapperVector = std::vector<std::unique_ptr<InputMapper>>;
@@ -250,7 +250,7 @@
     inline int32_t getId() { return mDeviceId; }
     inline int32_t getEventHubId() { return mId; }
 
-    inline Flags<InputDeviceClass> getDeviceClasses() const {
+    inline ftl::Flags<InputDeviceClass> getDeviceClasses() const {
         return mEventHub->getDeviceClasses(mId);
     }
     inline InputDeviceIdentifier getDeviceIdentifier() const {
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index bf58705..8641287 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -39,10 +39,11 @@
 using android::gui::WindowInfoHandle;
 using android::os::InputEventInjectionResult;
 using android::os::InputEventInjectionSync;
-using namespace android::flag_operators;
 
 namespace android::inputdispatcher {
 
+using namespace ftl::flag_operators;
+
 // An arbitrary time value.
 static const nsecs_t ARBITRARY_TIME = 1234;
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 9f33d23..8ba501c 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <cinttypes>
+#include <memory>
+
 #include <CursorInputMapper.h>
 #include <InputDevice.h>
 #include <InputMapper.h>
@@ -34,18 +37,15 @@
 #include <android-base/thread_annotations.h>
 #include <gtest/gtest.h>
 #include <gui/constants.h>
-#include <inttypes.h>
-#include <math.h>
 
-#include <memory>
-#include <regex>
 #include "input/DisplayViewport.h"
 #include "input/Input.h"
 
 namespace android {
 
+using namespace ftl::flag_operators;
+
 using std::chrono_literals::operator""ms;
-using namespace android::flag_operators;
 
 // Timeout for waiting for an expected event
 static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
@@ -429,7 +429,7 @@
 
     struct Device {
         InputDeviceIdentifier identifier;
-        Flags<InputDeviceClass> classes;
+        ftl::Flags<InputDeviceClass> classes;
         PropertyMap configuration;
         KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
         KeyedVector<int, bool> relativeAxes;
@@ -457,7 +457,7 @@
             return OK;
         }
 
-        explicit Device(Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {}
+        explicit Device(ftl::Flags<InputDeviceClass> classes) : classes(classes), enabled(true) {}
     };
 
     std::mutex mLock;
@@ -484,7 +484,8 @@
 
     FakeEventHub() { }
 
-    void addDevice(int32_t deviceId, const std::string& name, Flags<InputDeviceClass> classes) {
+    void addDevice(int32_t deviceId, const std::string& name,
+                   ftl::Flags<InputDeviceClass> classes) {
         Device* device = new Device(classes);
         device->identifier.name = name;
         mDevices.add(deviceId, device);
@@ -695,9 +696,9 @@
         return index >= 0 ? mDevices.valueAt(index) : nullptr;
     }
 
-    Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
+    ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
         Device* device = getDevice(deviceId);
-        return device ? device->classes : Flags<InputDeviceClass>(0);
+        return device ? device->classes : ftl::Flags<InputDeviceClass>(0);
     }
 
     InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override {
@@ -1572,8 +1573,8 @@
         mFakePolicy.clear();
     }
 
-    void addDevice(int32_t eventHubId, const std::string& name, Flags<InputDeviceClass> classes,
-                   const PropertyMap* configuration) {
+    void addDevice(int32_t eventHubId, const std::string& name,
+                   ftl::Flags<InputDeviceClass> classes, const PropertyMap* configuration) {
         mFakeEventHub->addDevice(eventHubId, name, classes);
 
         if (configuration) {
@@ -1598,7 +1599,8 @@
 
     FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t eventHubId,
                                                   const std::string& name,
-                                                  Flags<InputDeviceClass> classes, uint32_t sources,
+                                                  ftl::Flags<InputDeviceClass> classes,
+                                                  uint32_t sources,
                                                   const PropertyMap* configuration) {
         std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, name);
         FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(eventHubId, sources);
@@ -1610,7 +1612,7 @@
 
 TEST_F(InputReaderTest, PolicyGetInputDevices) {
     ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard", InputDeviceClass::KEYBOARD, nullptr));
-    ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored", Flags<InputDeviceClass>(0),
+    ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored", ftl::Flags<InputDeviceClass>(0),
                                       nullptr)); // no classes so device will be ignored
 
     // Should also have received a notification describing the new input devices.
@@ -1672,7 +1674,7 @@
 
 TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass(InputDeviceClass::KEYBOARD);
+    constexpr ftl::Flags<InputDeviceClass> deviceClass(InputDeviceClass::KEYBOARD);
     constexpr int32_t eventHubId = 1;
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
     // Must add at least one mapper or the device will be ignored!
@@ -1709,7 +1711,7 @@
 
 TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr int32_t eventHubId = 1;
     FakeInputMapper& mapper =
             addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
@@ -1773,7 +1775,7 @@
 
 TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr int32_t eventHubId = 1;
     FakeInputMapper& mapper =
             addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
@@ -1806,7 +1808,7 @@
 
 TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr int32_t eventHubId = 1;
     FakeInputMapper& mapper =
             addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
@@ -1839,7 +1841,7 @@
 
 TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr int32_t eventHubId = 1;
     FakeInputMapper& mapper =
             addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
@@ -1891,7 +1893,7 @@
 
 TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr nsecs_t when = 0;
     constexpr int32_t eventHubId = 1;
     constexpr nsecs_t readTime = 2;
@@ -1915,7 +1917,7 @@
 
 TEST_F(InputReaderTest, DeviceReset_RandomId) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr int32_t eventHubId = 1;
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
     // Must add at least one mapper or the device will be ignored!
@@ -1948,7 +1950,7 @@
 
 TEST_F(InputReaderTest, DeviceReset_GenerateIdWithInputReaderSource) {
     constexpr int32_t deviceId = 1;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr int32_t eventHubId = 1;
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
     // Must add at least one mapper or the device will be ignored!
@@ -1963,7 +1965,7 @@
 
 TEST_F(InputReaderTest, Device_CanDispatchToDisplay) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr int32_t eventHubId = 1;
     const char* DEVICE_LOCATION = "USB1";
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2008,7 +2010,7 @@
 
 TEST_F(InputReaderTest, WhenEnabledChanges_AllSubdevicesAreUpdated) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
     // Must add at least one mapper or the device will be ignored!
@@ -2049,7 +2051,7 @@
 
 TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToSubdeviceMappers) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    constexpr Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
+    constexpr ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD;
     constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
     // Add two subdevices to device
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
@@ -2106,7 +2108,8 @@
 
 TEST_F(InputReaderTest, VibratorGetVibratorIds) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR;
+    ftl::Flags<InputDeviceClass> deviceClass =
+            InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR;
     constexpr int32_t eventHubId = 1;
     const char* DEVICE_LOCATION = "BLUETOOTH";
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2166,7 +2169,8 @@
 
 TEST_F(InputReaderTest, BatteryGetCapacity) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+    ftl::Flags<InputDeviceClass> deviceClass =
+            InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
     constexpr int32_t eventHubId = 1;
     const char* DEVICE_LOCATION = "BLUETOOTH";
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2182,7 +2186,8 @@
 
 TEST_F(InputReaderTest, BatteryGetStatus) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+    ftl::Flags<InputDeviceClass> deviceClass =
+            InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
     constexpr int32_t eventHubId = 1;
     const char* DEVICE_LOCATION = "BLUETOOTH";
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2198,7 +2203,7 @@
 
 TEST_F(InputReaderTest, LightGetColor) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
-    Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT;
+    ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT;
     constexpr int32_t eventHubId = 1;
     const char* DEVICE_LOCATION = "BLUETOOTH";
     std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
@@ -2625,7 +2630,7 @@
     static const int32_t DEVICE_ID;
     static const int32_t DEVICE_GENERATION;
     static const int32_t DEVICE_CONTROLLER_NUMBER;
-    static const Flags<InputDeviceClass> DEVICE_CLASSES;
+    static const ftl::Flags<InputDeviceClass> DEVICE_CLASSES;
     static const int32_t EVENTHUB_ID;
 
     std::shared_ptr<FakeEventHub> mFakeEventHub;
@@ -2646,7 +2651,7 @@
         mDevice = std::make_shared<InputDevice>(mReader->getContext(), DEVICE_ID, DEVICE_GENERATION,
                                                 identifier);
         mReader->pushNextDevice(mDevice);
-        mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, Flags<InputDeviceClass>(0));
+        mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, ftl::Flags<InputDeviceClass>(0));
         mReader->loopOnce();
     }
 
@@ -2661,14 +2666,14 @@
 const int32_t InputDeviceTest::DEVICE_ID = END_RESERVED_ID + 1000;
 const int32_t InputDeviceTest::DEVICE_GENERATION = 2;
 const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0;
-const Flags<InputDeviceClass> InputDeviceTest::DEVICE_CLASSES =
+const ftl::Flags<InputDeviceClass> InputDeviceTest::DEVICE_CLASSES =
         InputDeviceClass::KEYBOARD | InputDeviceClass::TOUCH | InputDeviceClass::JOYSTICK;
 const int32_t InputDeviceTest::EVENTHUB_ID = 1;
 
 TEST_F(InputDeviceTest, ImmutableProperties) {
     ASSERT_EQ(DEVICE_ID, mDevice->getId());
     ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str());
-    ASSERT_EQ(Flags<InputDeviceClass>(0), mDevice->getClasses());
+    ASSERT_EQ(ftl::Flags<InputDeviceClass>(0), mDevice->getClasses());
 }
 
 TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsFalse) {
@@ -2912,7 +2917,7 @@
     static const int32_t DEVICE_ID;
     static const int32_t DEVICE_GENERATION;
     static const int32_t DEVICE_CONTROLLER_NUMBER;
-    static const Flags<InputDeviceClass> DEVICE_CLASSES;
+    static const ftl::Flags<InputDeviceClass> DEVICE_CLASSES;
     static const int32_t EVENTHUB_ID;
 
     std::shared_ptr<FakeEventHub> mFakeEventHub;
@@ -2921,7 +2926,7 @@
     std::unique_ptr<InstrumentedInputReader> mReader;
     std::shared_ptr<InputDevice> mDevice;
 
-    virtual void SetUp(Flags<InputDeviceClass> classes) {
+    virtual void SetUp(ftl::Flags<InputDeviceClass> classes) {
         mFakeEventHub = std::make_unique<FakeEventHub>();
         mFakePolicy = new FakeInputReaderPolicy();
         mFakeListener = std::make_unique<TestInputListener>();
@@ -2953,7 +2958,7 @@
 
     std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
                                            const std::string& location, int32_t eventHubId,
-                                           Flags<InputDeviceClass> classes) {
+                                           ftl::Flags<InputDeviceClass> classes) {
         InputDeviceIdentifier identifier;
         identifier.name = name;
         identifier.location = location;
@@ -3045,8 +3050,8 @@
 const int32_t InputMapperTest::DEVICE_ID = END_RESERVED_ID + 1000;
 const int32_t InputMapperTest::DEVICE_GENERATION = 2;
 const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0;
-const Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
-        Flags<InputDeviceClass>(0); // not needed for current tests
+const ftl::Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
+        ftl::Flags<InputDeviceClass>(0); // not needed for current tests
 const int32_t InputMapperTest::EVENTHUB_ID = 1;
 
 // --- SwitchInputMapperTest ---
@@ -3842,7 +3847,7 @@
     constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
     std::shared_ptr<InputDevice> device2 =
             newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
-                      Flags<InputDeviceClass>(0));
+                      ftl::Flags<InputDeviceClass>(0));
 
     mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
     mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
@@ -3954,7 +3959,7 @@
     constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
     std::shared_ptr<InputDevice> device2 =
             newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
-                      Flags<InputDeviceClass>(0));
+                      ftl::Flags<InputDeviceClass>(0));
     mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
     mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/);
     mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
@@ -8409,7 +8414,7 @@
     constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
     std::shared_ptr<InputDevice> device2 =
             newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
-                      Flags<InputDeviceClass>(0));
+                      ftl::Flags<InputDeviceClass>(0));
 
     mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX,
                                    0 /*flat*/, 0 /*fuzz*/);
@@ -9350,7 +9355,7 @@
     static const int32_t DEVICE_ID;
     static const int32_t DEVICE_GENERATION;
     static const int32_t DEVICE_CONTROLLER_NUMBER;
-    static const Flags<InputDeviceClass> DEVICE_CLASSES;
+    static const ftl::Flags<InputDeviceClass> DEVICE_CLASSES;
     static const int32_t EVENTHUB_ID;
 
     std::shared_ptr<FakeEventHub> mFakeEventHub;
@@ -9359,7 +9364,7 @@
     std::unique_ptr<InstrumentedInputReader> mReader;
     std::shared_ptr<InputDevice> mDevice;
 
-    virtual void SetUp(Flags<InputDeviceClass> classes) {
+    virtual void SetUp(ftl::Flags<InputDeviceClass> classes) {
         mFakeEventHub = std::make_unique<FakeEventHub>();
         mFakePolicy = new FakeInputReaderPolicy();
         mFakeListener = std::make_unique<TestInputListener>();
@@ -9385,7 +9390,7 @@
 
     std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
                                            const std::string& location, int32_t eventHubId,
-                                           Flags<InputDeviceClass> classes) {
+                                           ftl::Flags<InputDeviceClass> classes) {
         InputDeviceIdentifier identifier;
         identifier.name = name;
         identifier.location = location;
@@ -9411,8 +9416,8 @@
 const int32_t PeripheralControllerTest::DEVICE_ID = END_RESERVED_ID + 1000;
 const int32_t PeripheralControllerTest::DEVICE_GENERATION = 2;
 const int32_t PeripheralControllerTest::DEVICE_CONTROLLER_NUMBER = 0;
-const Flags<InputDeviceClass> PeripheralControllerTest::DEVICE_CLASSES =
-        Flags<InputDeviceClass>(0); // not needed for current tests
+const ftl::Flags<InputDeviceClass> PeripheralControllerTest::DEVICE_CLASSES =
+        ftl::Flags<InputDeviceClass>(0); // not needed for current tests
 const int32_t PeripheralControllerTest::EVENTHUB_ID = 1;
 
 // --- BatteryControllerTest ---
diff --git a/services/inputflinger/tests/PreferStylusOverTouch_test.cpp b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
index 70f40aa..8e2ab88 100644
--- a/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
+++ b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
@@ -20,12 +20,16 @@
 namespace android {
 
 constexpr int32_t TOUCH_DEVICE_ID = 3;
-constexpr int32_t STYLUS_DEVICE_ID = 4;
+constexpr int32_t SECOND_TOUCH_DEVICE_ID = 4;
+constexpr int32_t STYLUS_DEVICE_ID = 5;
+constexpr int32_t SECOND_STYLUS_DEVICE_ID = 6;
 
 constexpr int DOWN = AMOTION_EVENT_ACTION_DOWN;
 constexpr int MOVE = AMOTION_EVENT_ACTION_MOVE;
 constexpr int UP = AMOTION_EVENT_ACTION_UP;
 constexpr int CANCEL = AMOTION_EVENT_ACTION_CANCEL;
+static constexpr int32_t POINTER_1_DOWN =
+        AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
 constexpr int32_t TOUCHSCREEN = AINPUT_SOURCE_TOUCHSCREEN;
 constexpr int32_t STYLUS = AINPUT_SOURCE_STYLUS;
 
@@ -78,29 +82,30 @@
 
 class PreferStylusOverTouchTest : public testing::Test {
 protected:
-    void assertNotBlocked(const NotifyMotionArgs& args) {
-        ftl::StaticVector<NotifyMotionArgs, 2> processedArgs = mBlocker.processMotion(args);
-        ASSERT_EQ(1u, processedArgs.size());
-        ASSERT_EQ(args, processedArgs[0]);
+    void assertNotBlocked(const NotifyMotionArgs& args) { assertResponse(args, {args}); }
+
+    void assertDropped(const NotifyMotionArgs& args) { assertResponse(args, {}); }
+
+    void assertResponse(const NotifyMotionArgs& args,
+                        const std::vector<NotifyMotionArgs>& expected) {
+        std::vector<NotifyMotionArgs> receivedArgs = mBlocker.processMotion(args);
+        ASSERT_EQ(expected.size(), receivedArgs.size());
+        for (size_t i = 0; i < expected.size(); i++) {
+            // The 'eventTime' of CANCEL events is dynamically generated. Don't check this field.
+            if (expected[i].action == CANCEL && receivedArgs[i].action == CANCEL) {
+                receivedArgs[i].eventTime = expected[i].eventTime;
+            }
+
+            ASSERT_EQ(expected[i], receivedArgs[i])
+                    << expected[i].dump() << " vs " << receivedArgs[i].dump();
+        }
     }
 
-    void assertDropped(const NotifyMotionArgs& args) {
-        ftl::StaticVector<NotifyMotionArgs, 2> processedArgs = mBlocker.processMotion(args);
-        ASSERT_TRUE(processedArgs.empty());
+    void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& devices) {
+        mBlocker.notifyInputDevicesChanged(devices);
     }
 
-    void assertCanceled(const NotifyMotionArgs& args,
-                        std::optional<NotifyMotionArgs> canceledArgs) {
-        ftl::StaticVector<NotifyMotionArgs, 2> processedArgs = mBlocker.processMotion(args);
-        ASSERT_EQ(2u, processedArgs.size());
-        NotifyMotionArgs& cancelEvent = processedArgs[0];
-        ASSERT_EQ(CANCEL, cancelEvent.action);
-        ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, cancelEvent.flags & AMOTION_EVENT_FLAG_CANCELED);
-        ASSERT_TRUE(isFromSource(cancelEvent.source, TOUCHSCREEN));
-        ASSERT_FALSE(isFromSource(cancelEvent.source, STYLUS));
-
-        ASSERT_EQ(args, processedArgs[1]);
-    }
+    void dump() const { ALOGI("Blocker: \n%s\n", mBlocker.dump().c_str()); }
 
 private:
     PreferStylusOverTouchBlocker mBlocker;
@@ -148,7 +153,8 @@
     args = generateMotionArgs(3 /*downTime*/, 3 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
     NotifyMotionArgs cancelArgs =
             generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, CANCEL, {{1, 3}}, TOUCHSCREEN);
-    assertCanceled(args, cancelArgs);
+    cancelArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
+    assertResponse(args, {cancelArgs, args});
 
     // Both stylus and touch events continue. Stylus should be not blocked, and touch should be
     // blocked
@@ -160,6 +166,26 @@
 }
 
 /**
+ * Stylus goes down after touch gesture.
+ */
+TEST_F(PreferStylusOverTouchTest, StylusDownAfterTouch) {
+    NotifyMotionArgs args;
+
+    args = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+    assertNotBlocked(args);
+
+    args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{1, 3}}, TOUCHSCREEN);
+    assertNotBlocked(args);
+
+    args = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{1, 3}}, TOUCHSCREEN);
+    assertNotBlocked(args);
+
+    // Stylus goes down
+    args = generateMotionArgs(3 /*downTime*/, 3 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
+    assertNotBlocked(args);
+}
+
+/**
  * New touch events should be simply blocked (dropped) when stylus is down. No CANCEL event should
  * be generated.
  */
@@ -247,4 +273,230 @@
     assertNotBlocked(args);
 }
 
+/**
+ * If an event with mixed stylus and touch pointers is encountered, it should be ignored. Touches
+ * from such should pass, even if stylus from the same device goes down.
+ */
+TEST_F(PreferStylusOverTouchTest, MixedStylusAndTouchPointersAreIgnored) {
+    NotifyMotionArgs args;
+
+    // Event from a stylus device, but with finger tool type
+    args = generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2}}, STYLUS);
+    // Keep source stylus, but make the tool type touch
+    args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+    assertNotBlocked(args);
+
+    // Second pointer (stylus pointer) goes down, from the same device
+    args = generateMotionArgs(1 /*downTime*/, 2 /*eventTime*/, POINTER_1_DOWN, {{1, 2}, {10, 20}},
+                              STYLUS);
+    // Keep source stylus, but make the tool type touch
+    args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    assertNotBlocked(args);
+
+    // Second pointer (stylus pointer) goes down, from the same device
+    args = generateMotionArgs(1 /*downTime*/, 3 /*eventTime*/, MOVE, {{2, 3}, {11, 21}}, STYLUS);
+    // Keep source stylus, but make the tool type touch
+    args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+    assertNotBlocked(args);
+}
+
+/**
+ * When there are two touch devices, stylus down should cancel all current touch streams.
+ */
+TEST_F(PreferStylusOverTouchTest, TouchFromTwoDevicesAndStylus) {
+    NotifyMotionArgs touch1Down =
+            generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+    assertNotBlocked(touch1Down);
+
+    NotifyMotionArgs touch2Down =
+            generateMotionArgs(2 /*downTime*/, 2 /*eventTime*/, DOWN, {{3, 4}}, TOUCHSCREEN);
+    touch2Down.deviceId = SECOND_TOUCH_DEVICE_ID;
+    assertNotBlocked(touch2Down);
+
+    NotifyMotionArgs stylusDown =
+            generateMotionArgs(3 /*downTime*/, 3 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
+    NotifyMotionArgs cancelArgs1 = touch1Down;
+    cancelArgs1.action = CANCEL;
+    cancelArgs1.flags |= AMOTION_EVENT_FLAG_CANCELED;
+    NotifyMotionArgs cancelArgs2 = touch2Down;
+    cancelArgs2.action = CANCEL;
+    cancelArgs2.flags |= AMOTION_EVENT_FLAG_CANCELED;
+    assertResponse(stylusDown, {cancelArgs1, cancelArgs2, stylusDown});
+}
+
+/**
+ * Touch should be canceled when stylus goes down. After the stylus lifts up, the touch from that
+ * device should continue to be canceled.
+ * If one of the devices is already canceled, it should remain canceled, but new touches from a
+ * different device should go through.
+ */
+TEST_F(PreferStylusOverTouchTest, AllTouchMustLiftAfterCanceledByStylus) {
+    // First device touches down
+    NotifyMotionArgs touch1Down =
+            generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+    assertNotBlocked(touch1Down);
+
+    // Stylus goes down - touch should be canceled
+    NotifyMotionArgs stylusDown =
+            generateMotionArgs(2 /*downTime*/, 2 /*eventTime*/, DOWN, {{10, 30}}, STYLUS);
+    NotifyMotionArgs cancelArgs1 = touch1Down;
+    cancelArgs1.action = CANCEL;
+    cancelArgs1.flags |= AMOTION_EVENT_FLAG_CANCELED;
+    assertResponse(stylusDown, {cancelArgs1, stylusDown});
+
+    // Stylus goes up
+    NotifyMotionArgs stylusUp =
+            generateMotionArgs(2 /*downTime*/, 3 /*eventTime*/, UP, {{10, 30}}, STYLUS);
+    assertNotBlocked(stylusUp);
+
+    // Touch from the first device remains blocked
+    NotifyMotionArgs touch1Move =
+            generateMotionArgs(1 /*downTime*/, 4 /*eventTime*/, MOVE, {{2, 3}}, TOUCHSCREEN);
+    assertDropped(touch1Move);
+
+    // Second touch goes down. It should not be blocked because stylus has already lifted.
+    NotifyMotionArgs touch2Down =
+            generateMotionArgs(5 /*downTime*/, 5 /*eventTime*/, DOWN, {{31, 32}}, TOUCHSCREEN);
+    touch2Down.deviceId = SECOND_TOUCH_DEVICE_ID;
+    assertNotBlocked(touch2Down);
+
+    // First device is lifted up. It's already been canceled, so the UP event should be dropped.
+    NotifyMotionArgs touch1Up =
+            generateMotionArgs(1 /*downTime*/, 6 /*eventTime*/, UP, {{2, 3}}, TOUCHSCREEN);
+    assertDropped(touch1Up);
+
+    // Touch from second device touch should continue to work
+    NotifyMotionArgs touch2Move =
+            generateMotionArgs(5 /*downTime*/, 7 /*eventTime*/, MOVE, {{32, 33}}, TOUCHSCREEN);
+    touch2Move.deviceId = SECOND_TOUCH_DEVICE_ID;
+    assertNotBlocked(touch2Move);
+
+    // Second touch lifts up
+    NotifyMotionArgs touch2Up =
+            generateMotionArgs(5 /*downTime*/, 8 /*eventTime*/, UP, {{32, 33}}, TOUCHSCREEN);
+    touch2Up.deviceId = SECOND_TOUCH_DEVICE_ID;
+    assertNotBlocked(touch2Up);
+
+    // Now that all touch has been lifted, new touch from either first or second device should work
+    NotifyMotionArgs touch3Down =
+            generateMotionArgs(9 /*downTime*/, 9 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+    assertNotBlocked(touch3Down);
+
+    NotifyMotionArgs touch4Down =
+            generateMotionArgs(10 /*downTime*/, 10 /*eventTime*/, DOWN, {{100, 200}}, TOUCHSCREEN);
+    touch4Down.deviceId = SECOND_TOUCH_DEVICE_ID;
+    assertNotBlocked(touch4Down);
+}
+
+/**
+ * When we don't know that a specific device does both stylus and touch, and we only see touch
+ * pointers from it, we should treat it as a touch device. That means, the device events should be
+ * canceled when stylus from another device goes down. When we detect simultaneous touch and stylus
+ * from this device though, we should just pass this device through without canceling anything.
+ *
+ * In this test:
+ * 1. Start by touching down with device 1
+ * 2. Device 2 has stylus going down
+ * 3. Device 1 should be canceled.
+ * 4. When we add stylus pointers to the device 1, they should continue to be canceled.
+ * 5. Device 1 lifts up.
+ * 6. Subsequent events from device 1 should not be canceled even if stylus is down.
+ * 7. If a reset happens, and such device is no longer there, then we should
+ * Therefore, the device 1 is "ignored" and does not participate into "prefer stylus over touch"
+ * behaviour.
+ */
+TEST_F(PreferStylusOverTouchTest, MixedStylusAndTouchDeviceIsCanceledAtFirst) {
+    // Touch from device 1 goes down
+    NotifyMotionArgs touchDown =
+            generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+    touchDown.source = STYLUS;
+    assertNotBlocked(touchDown);
+
+    // Stylus from device 2 goes down. Touch should be canceled.
+    NotifyMotionArgs args =
+            generateMotionArgs(2 /*downTime*/, 2 /*eventTime*/, DOWN, {{10, 20}}, STYLUS);
+    NotifyMotionArgs cancelTouchArgs = touchDown;
+    cancelTouchArgs.action = CANCEL;
+    cancelTouchArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
+    assertResponse(args, {cancelTouchArgs, args});
+
+    // Introduce a stylus pointer into the device 1 stream. It should be ignored.
+    args = generateMotionArgs(1 /*downTime*/, 3 /*eventTime*/, POINTER_1_DOWN, {{1, 2}, {3, 4}},
+                              TOUCHSCREEN);
+    args.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    args.source = STYLUS;
+    assertDropped(args);
+
+    // Lift up touch from the mixed touch/stylus device
+    args = generateMotionArgs(1 /*downTime*/, 4 /*eventTime*/, CANCEL, {{1, 2}, {3, 4}},
+                              TOUCHSCREEN);
+    args.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    args.source = STYLUS;
+    assertDropped(args);
+
+    // Stylus from device 2 is still down. Since the device 1 is now identified as a mixed
+    // touch/stylus device, its events should go through, even if they are touch.
+    args = generateMotionArgs(5 /*downTime*/, 5 /*eventTime*/, DOWN, {{21, 22}}, TOUCHSCREEN);
+    touchDown.source = STYLUS;
+    assertResponse(args, {args});
+
+    // Reconfigure such that only the stylus device remains
+    InputDeviceInfo stylusDevice;
+    stylusDevice.initialize(STYLUS_DEVICE_ID, 1 /*generation*/, 1 /*controllerNumber*/,
+                            {} /*identifier*/, "stylus device", false /*external*/,
+                            false /*hasMic*/);
+    notifyInputDevicesChanged({stylusDevice});
+    // The touchscreen device was removed, so we no longer remember anything about it. We should
+    // again start blocking touch events from it.
+    args = generateMotionArgs(6 /*downTime*/, 6 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+    args.source = STYLUS;
+    assertDropped(args);
+}
+
+/**
+ * If two styli are active at the same time, touch should be blocked until both of them are lifted.
+ * If one of them lifts, touch should continue to be blocked.
+ */
+TEST_F(PreferStylusOverTouchTest, TouchIsBlockedWhenTwoStyliAreUsed) {
+    NotifyMotionArgs args;
+
+    // First stylus is down
+    assertNotBlocked(generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{10, 30}}, STYLUS));
+
+    // Second stylus is down
+    args = generateMotionArgs(1 /*downTime*/, 1 /*eventTime*/, DOWN, {{20, 40}}, STYLUS);
+    args.deviceId = SECOND_STYLUS_DEVICE_ID;
+    assertNotBlocked(args);
+
+    // Touch goes down. It should be ignored.
+    args = generateMotionArgs(2 /*downTime*/, 2 /*eventTime*/, DOWN, {{1, 2}}, TOUCHSCREEN);
+    assertDropped(args);
+
+    // Lift the first stylus
+    args = generateMotionArgs(0 /*downTime*/, 3 /*eventTime*/, UP, {{10, 30}}, STYLUS);
+    assertNotBlocked(args);
+
+    // Touch should continue to be blocked
+    args = generateMotionArgs(2 /*downTime*/, 4 /*eventTime*/, UP, {{1, 2}}, TOUCHSCREEN);
+    assertDropped(args);
+
+    // New touch should be blocked because second stylus is still down
+    args = generateMotionArgs(5 /*downTime*/, 5 /*eventTime*/, DOWN, {{5, 6}}, TOUCHSCREEN);
+    assertDropped(args);
+
+    // Second stylus goes up
+    args = generateMotionArgs(1 /*downTime*/, 6 /*eventTime*/, UP, {{20, 40}}, STYLUS);
+    args.deviceId = SECOND_STYLUS_DEVICE_ID;
+    assertNotBlocked(args);
+
+    // Current touch gesture should continue to be blocked
+    // Touch should continue to be blocked
+    args = generateMotionArgs(5 /*downTime*/, 7 /*eventTime*/, UP, {{5, 6}}, TOUCHSCREEN);
+    assertDropped(args);
+
+    // Now that all styli were lifted, new touch should go through
+    args = generateMotionArgs(8 /*downTime*/, 8 /*eventTime*/, DOWN, {{7, 8}}, TOUCHSCREEN);
+    assertNotBlocked(args);
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index b2f8eb3..e378096 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -519,6 +519,34 @@
             &(args = generateMotionArgs(0 /*downTime*/, 4 /*eventTime*/, MOVE, {{7, 8, 9}})));
 }
 
+/**
+ * Send a touch event, and then a stylus event. Make sure that both work.
+ */
+TEST_F(UnwantedInteractionBlockerTest, StylusAfterTouchWorks) {
+    NotifyMotionArgs args;
+    mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+    args = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+    mBlocker->notifyMotion(&args);
+    args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{4, 5, 6}});
+    mBlocker->notifyMotion(&args);
+    args = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{4, 5, 6}});
+    mBlocker->notifyMotion(&args);
+
+    // Now touch down stylus
+    args = generateMotionArgs(3 /*downTime*/, 3 /*eventTime*/, DOWN, {{10, 20, 30}});
+    args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    args.source |= AINPUT_SOURCE_STYLUS;
+    mBlocker->notifyMotion(&args);
+    args = generateMotionArgs(3 /*downTime*/, 4 /*eventTime*/, MOVE, {{40, 50, 60}});
+    args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    args.source |= AINPUT_SOURCE_STYLUS;
+    mBlocker->notifyMotion(&args);
+    args = generateMotionArgs(3 /*downTime*/, 5 /*eventTime*/, UP, {{40, 50, 60}});
+    args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    args.source |= AINPUT_SOURCE_STYLUS;
+    mBlocker->notifyMotion(&args);
+}
+
 using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;
 
 /**
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 7194db3..b18d204 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -257,11 +257,13 @@
 
             bool isUidActive(uid_t uid);
 
-            void onUidGone(uid_t uid, bool disabled);
-            void onUidActive(uid_t uid);
-            void onUidIdle(uid_t uid, bool disabled);
+            void onUidGone(uid_t uid, bool disabled) override;
+            void onUidActive(uid_t uid) override;
+            void onUidIdle(uid_t uid, bool disabled) override;
             void onUidStateChanged(uid_t uid __unused, int32_t procState __unused,
-                                   int64_t procStateSeq __unused, int32_t capability __unused) {}
+                                   int64_t procStateSeq __unused,
+                                   int32_t capability __unused) override {}
+            void onUidProcAdjChanged(uid_t uid __unused) override {}
 
             void addOverrideUid(uid_t uid, bool active);
             void removeOverrideUid(uid_t uid);
diff --git a/services/sensorservice/SensorServiceUtils.cpp b/services/sensorservice/SensorServiceUtils.cpp
index 7dd2331..6bad962 100644
--- a/services/sensorservice/SensorServiceUtils.cpp
+++ b/services/sensorservice/SensorServiceUtils.cpp
@@ -39,6 +39,7 @@
             return 5;
 
         case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+        case SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED:
         case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
         case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES:
         case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES:
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index bcae8d9..c5d7a60 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -1098,6 +1098,13 @@
         }
     }
 
+    if (s.what & layer_state_t::eDimmingEnabledChanged) {
+        if (mDrawingState.dimmingEnabled != s.dimmingEnabled) {
+            ALOGV("%s: false [eDimmingEnabledChanged changed]", __func__);
+            return false;
+        }
+    }
+
     ALOGV("%s: true", __func__);
     return true;
 }
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index aefc014..516c3ef 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -23,6 +23,7 @@
         "android.hardware.graphics.composer3-V1-ndk",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
+        "android.hardware.power-V2-cpp",
         "libbase",
         "libcutils",
         "libgui",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 283fe86..974f7c6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -207,6 +207,9 @@
     // framerate of the layer as measured by LayerHistory
     float fps;
 
+    // The dimming flag
+    bool dimmingEnabled{true};
+
     virtual ~LayerFECompositionState();
 
     // Debugging
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index cb00e71..29d3366 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -16,20 +16,20 @@
 
 #pragma once
 
+#include <string>
+
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <android-base/strings.h>
+#include <ftl/flags.h>
+#include <math/HashCombine.h>
+
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/LayerFECompositionState.h>
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
-#include <ftl/Flags.h>
-
-#include <string>
 
 #include "DisplayHardware/Hal.h"
-#include "math/HashCombine.h"
-
-#include <aidl/android/hardware/graphics/common/BufferUsage.h>
-#include <aidl/android/hardware/graphics/composer3/Composition.h>
 
 namespace std {
 template <typename T>
@@ -84,13 +84,13 @@
 public:
     virtual ~StateInterface() = default;
 
-    virtual Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) = 0;
+    virtual ftl::Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) = 0;
 
     virtual size_t getHash() const = 0;
 
     virtual LayerStateField getField() const = 0;
 
-    virtual Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const = 0;
+    virtual ftl::Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const = 0;
 
     virtual bool equals(const StateInterface* other) const = 0;
 
@@ -152,12 +152,12 @@
     ~OutputLayerState() override = default;
 
     // Returns this member's field flag if it was changed
-    Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) override {
+    ftl::Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) override {
         T newValue = mReader(layer);
         return update(newValue);
     }
 
-    Flags<LayerStateField> update(const T& newValue) {
+    ftl::Flags<LayerStateField> update(const T& newValue) {
         if (!mEquals(mValue, newValue)) {
             mValue = newValue;
             mHash = {};
@@ -176,14 +176,14 @@
         return *mHash;
     }
 
-    Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const override {
+    ftl::Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const override {
         if (other->getField() != FIELD) {
             return {};
         }
 
         // The early return ensures that this downcast is sound
         const OutputLayerState* otherState = static_cast<const OutputLayerState*>(other);
-        return *this != *otherState ? FIELD : Flags<LayerStateField>{};
+        return *this != *otherState ? FIELD : ftl::Flags<LayerStateField>{};
     }
 
     bool equals(const StateInterface* other) const override {
@@ -215,7 +215,7 @@
     LayerState(compositionengine::OutputLayer* layer);
 
     // Returns which fields were updated
-    Flags<LayerStateField> update(compositionengine::OutputLayer*);
+    ftl::Flags<LayerStateField> update(compositionengine::OutputLayer*);
 
     // Computes a hash for this LayerState.
     // The hash is only computed from NonUniqueFields, and excludes GraphicBuffers since they are
@@ -224,7 +224,7 @@
 
     // Returns the bit-set of differing fields between this LayerState and another LayerState.
     // This bit-set is based on NonUniqueFields only, and excludes GraphicBuffers.
-    Flags<LayerStateField> getDifferingFields(const LayerState& other) const;
+    ftl::Flags<LayerStateField> getDifferingFields(const LayerState& other) const;
 
     compositionengine::OutputLayer* getOutputLayer() const { return mOutputLayer; }
     int32_t getId() const { return mId.get(); }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
index ef1560e..6be6735 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <ftl/flags.h>
+
 #include <compositionengine/impl/planner/LayerState.h>
 
 namespace android::compositionengine::impl::planner {
@@ -35,7 +37,7 @@
         // This implies that only one layer is allowed to differ in an approximate match.
         size_t differingIndex;
         // Set of fields that differ for the differing layer in the approximate match.
-        Flags<LayerStateField> differingFields;
+        ftl::Flags<LayerStateField> differingFields;
     };
 
     // Returns an approximate match when comparing this layer stack with the provided list of
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index ff7d430..6631a27 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -121,6 +121,7 @@
     dumpVal(out, "isColorspaceAgnostic", isColorspaceAgnostic);
     dumpVal(out, "dataspace", toString(dataspace), dataspace);
     dumpVal(out, "hdr metadata types", hdrMetadata.validTypes);
+    dumpVal(out, "dimming enabled", dimmingEnabled);
     dumpVal(out, "colorTransform", colorTransform);
 
     out.append("\n");
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 723593d..3289d55 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -324,9 +324,10 @@
 
     // For hdr content, treat the white point as the display brightness - HDR content should not be
     // boosted or dimmed.
+    // If the layer explicitly requests to disable dimming, then don't dim either.
     if (isHdrDataspace(state.dataspace) ||
         getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits ||
-        getOutput().getState().displayBrightnessNits == 0.f) {
+        getOutput().getState().displayBrightnessNits == 0.f || !layerFEState->dimmingEnabled) {
         state.dimmingRatio = 1.f;
         state.whitePointNits = getOutput().getState().displayBrightnessNits;
     } else {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index c79ca0d..f439caf 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -41,7 +41,7 @@
     update(layer);
 }
 
-Flags<LayerStateField> LayerState::update(compositionengine::OutputLayer* layer) {
+ftl::Flags<LayerStateField> LayerState::update(compositionengine::OutputLayer* layer) {
     ALOGE_IF(mOutputLayer != layer && layer->getLayerFE().getSequence() != mId.get(),
              "[%s] Expected mOutputLayer ID to never change: %d, %d", __func__,
              layer->getLayerFE().getSequence(), mId.get());
@@ -50,7 +50,7 @@
     // same, i.e., the LayerFE is the same. An example use-case is screen rotation.
     mOutputLayer = layer;
 
-    Flags<LayerStateField> differences;
+    ftl::Flags<LayerStateField> differences;
 
     // Update the unique fields as well, since we have to set them at least
     // once from the OutputLayer
@@ -76,8 +76,8 @@
     return hash;
 }
 
-Flags<LayerStateField> LayerState::getDifferingFields(const LayerState& other) const {
-    Flags<LayerStateField> differences;
+ftl::Flags<LayerStateField> LayerState::getDifferingFields(const LayerState& other) const {
+    ftl::Flags<LayerStateField> differences;
     auto myFields = getNonUniqueFields();
     auto otherFields = other.getNonUniqueFields();
     for (size_t i = 0; i < myFields.size(); ++i) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index 74d2701..c8413eb 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -97,7 +97,7 @@
         if (const auto layerEntry = mPreviousLayers.find(id); layerEntry != mPreviousLayers.end()) {
             // Track changes from previous info
             LayerState& state = layerEntry->second;
-            Flags<LayerStateField> differences = state.update(layer);
+            ftl::Flags<LayerStateField> differences = state.update(layer);
             if (differences.get() == 0) {
                 state.incrementFramesSinceBufferUpdate();
             } else {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
index 2d53583..2fc029f 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
@@ -57,7 +57,7 @@
             return std::nullopt;
         }
 
-        Flags<LayerStateField> differingFields = mLayers[i].getDifferingFields(*other[i]);
+        ftl::Flags<LayerStateField> differingFields = mLayers[i].getDifferingFields(*other[i]);
 
         // If we don't find an approximate match on this layer, then the LayerStacks differ
         // by too much, so return nothing
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 8eb1946..ceee48c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -668,6 +668,13 @@
     EXPECT_EQ(mOutputState.sdrWhitePointNits / mOutputState.displayBrightnessNits,
               mOutputLayer.getState().dimmingRatio);
 
+    mLayerFEState.dimmingEnabled = false;
+    mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+    EXPECT_EQ(mOutputState.displayBrightnessNits, mOutputLayer.getState().whitePointNits);
+    EXPECT_EQ(1.f, mOutputLayer.getState().dimmingRatio);
+
+    // change dimmingEnabled back to true.
+    mLayerFEState.dimmingEnabled = true;
     mLayerFEState.dataspace = ui::Dataspace::BT2020_ITU_PQ;
     mLayerFEState.isColorspaceAgnostic = false;
     mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index bd4ff13..5c6e8da 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -97,12 +97,12 @@
     void verifyUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs) {
         EXPECT_EQ(lhs.getHash(), rhs.getHash());
 
-        EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), lhs.getDifferingFields(rhs));
-        EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), rhs.getDifferingFields(lhs));
+        EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::None), lhs.getDifferingFields(rhs));
+        EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::None), rhs.getDifferingFields(lhs));
     }
 
     void verifyNonUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs,
-                                        Flags<LayerStateField> fields) {
+                                        ftl::Flags<LayerStateField> fields) {
         EXPECT_NE(lhs.getHash(), rhs.getHash());
 
         EXPECT_EQ(fields, lhs.getDifferingFields(rhs));
@@ -159,9 +159,9 @@
     sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionState, sSequenceIdTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
     EXPECT_EQ(sSequenceIdTwo, mLayerState->getId());
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Id), updates);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Id), updates);
 }
 
 TEST_F(LayerStateTest, compareId) {
@@ -204,9 +204,9 @@
     sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionState, sSequenceId, sDebugNameTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
     EXPECT_EQ(sDebugNameTwo, mLayerState->getName());
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Name), updates);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Name), updates);
 }
 
 TEST_F(LayerStateTest, compareName) {
@@ -253,9 +253,9 @@
     outputLayerCompositionStateTwo.displayFrame = sRectTwo;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
                        layerFECompositionState);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
     EXPECT_EQ(sRectTwo, mLayerState->getDisplayFrame());
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::DisplayFrame), updates);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::DisplayFrame), updates);
 }
 
 TEST_F(LayerStateTest, compareDisplayFrame) {
@@ -315,9 +315,9 @@
     layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
     EXPECT_EQ(Composition::SOLID_COLOR, mLayerState->getCompositionType());
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::CompositionType), updates);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::CompositionType), updates);
 }
 
 TEST_F(LayerStateTest, compareCompositionType) {
@@ -357,8 +357,8 @@
     layerFECompositionStateTwo.buffer = new GraphicBuffer();
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Buffer), updates);
 }
 
 TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) {
@@ -380,8 +380,8 @@
         layerFECompositionStateTwo.frameNumber = i;
         setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                            layerFECompositionStateTwo);
-        Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-        EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer), updates);
+        ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+        EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Buffer), updates);
     }
 }
 
@@ -404,8 +404,8 @@
     for (uint64_t i = 0; i < 10; i++) {
         setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                            layerFECompositionStateTwo);
-        Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-        EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer), updates);
+        ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+        EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Buffer), updates);
     }
 }
 
@@ -446,8 +446,8 @@
     outputLayerCompositionStateTwo.sourceCrop = sFloatRectTwo;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
                        layerFECompositionState);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SourceCrop), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::SourceCrop), updates);
 }
 
 TEST_F(LayerStateTest, compareSourceCrop) {
@@ -485,8 +485,8 @@
     outputLayerCompositionStateTwo.bufferTransform = Hwc2::Transform::FLIP_V;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
                        layerFECompositionState);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BufferTransform), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::BufferTransform), updates);
 }
 
 TEST_F(LayerStateTest, compareBufferTransform) {
@@ -525,8 +525,8 @@
     layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlendMode), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::BlendMode), updates);
 }
 
 TEST_F(LayerStateTest, compareBlendMode) {
@@ -564,8 +564,8 @@
     layerFECompositionStateTwo.alpha = sAlphaTwo;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Alpha), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Alpha), updates);
 }
 
 TEST_F(LayerStateTest, compareAlpha) {
@@ -603,8 +603,8 @@
     layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::LayerMetadata), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::LayerMetadata), updates);
 }
 
 TEST_F(LayerStateTest, compareLayerMetadata) {
@@ -652,8 +652,8 @@
     outputLayerCompositionStateTwo.visibleRegion = sRegionTwo;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
                        layerFECompositionState);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::VisibleRegion), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::VisibleRegion), updates);
 }
 
 TEST_F(LayerStateTest, compareVisibleRegion) {
@@ -691,8 +691,8 @@
     outputLayerCompositionStateTwo.dataspace = ui::Dataspace::DISPLAY_P3;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
                        layerFECompositionState);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Dataspace), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Dataspace), updates);
 }
 
 TEST_F(LayerStateTest, compareDataspace) {
@@ -738,9 +738,9 @@
                               "buffer2");
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer) |
-                      Flags<LayerStateField>(LayerStateField::PixelFormat),
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::Buffer) |
+                      ftl::Flags<LayerStateField>(LayerStateField::PixelFormat),
               updates);
 }
 
@@ -768,7 +768,7 @@
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
     verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState,
-                                   Flags<LayerStateField>(LayerStateField::PixelFormat));
+                                   ftl::Flags<LayerStateField>(LayerStateField::PixelFormat));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -790,8 +790,8 @@
     layerFECompositionStateTwo.colorTransform = sMat4One;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ColorTransform), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::ColorTransform), updates);
 }
 
 TEST_F(LayerStateTest, compareColorTransform) {
@@ -831,8 +831,8 @@
     layerFECompositionStateTwo.sidebandStream = NativeHandle::create(sFakeSidebandStreamTwo, false);
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SidebandStream), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::SidebandStream), updates);
 }
 
 TEST_F(LayerStateTest, compareSidebandStream) {
@@ -870,8 +870,8 @@
     layerFECompositionStateTwo.color = sHalf4Two;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SolidColor), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::SolidColor), updates);
 }
 
 TEST_F(LayerStateTest, compareSolidColor) {
@@ -909,8 +909,8 @@
     layerFECompositionStateTwo.backgroundBlurRadius = sBgBlurRadiusTwo;
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BackgroundBlurRadius), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::BackgroundBlurRadius), updates);
 }
 
 TEST_F(LayerStateTest, compareBackgroundBlur) {
@@ -949,8 +949,8 @@
     layerFECompositionStateTwo.blurRegions.push_back(sBlurRegionTwo);
     setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
-    Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlurRegions), updates);
+    ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::BlurRegions), updates);
 }
 
 TEST_F(LayerStateTest, compareBlurRegions) {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index f5a4b3d..9116fd3 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -471,9 +471,8 @@
         return;
     }
 
-    const auto [lowFps, highFps] = mRefreshRateConfigs->getSupportedRefreshRateRange();
-    mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*mFlinger, lowFps.getIntValue(),
-                                                               highFps.getIntValue(), showSpinnner);
+    const auto fpsRange = mRefreshRateConfigs->getSupportedRefreshRateRange();
+    mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, showSpinnner);
     mRefreshRateOverlay->setLayerStack(getLayerStack());
     mRefreshRateOverlay->setViewport(getSize());
     mRefreshRateOverlay->changeRefreshRate(getActiveMode()->getFps());
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 2c4a300..d5d87b4 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <unordered_map>
 
+#include <android-base/thread_annotations.h>
 #include <android/native_window.h>
 #include <binder/IBinder.h>
 #include <gui/LayerState.h>
@@ -28,6 +29,7 @@
 #include <renderengine/RenderEngine.h>
 #include <system/window.h>
 #include <ui/DisplayId.h>
+#include <ui/DisplayIdentification.h>
 #include <ui/DisplayState.h>
 #include <ui/GraphicTypes.h>
 #include <ui/HdrCapabilities.h>
@@ -39,15 +41,11 @@
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
-#include "MainThreadGuard.h"
-
-#include <ui/DisplayIdentification.h>
 #include "DisplayHardware/DisplayMode.h"
 #include "DisplayHardware/Hal.h"
 #include "DisplayHardware/PowerAdvisor.h"
-
 #include "Scheduler/RefreshRateConfigs.h"
-
+#include "ThreadContext.h"
 #include "TracedOrdinal.h"
 
 namespace android {
@@ -99,9 +97,9 @@
     void setLayerStack(ui::LayerStack);
     void setDisplaySize(int width, int height);
     void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
-    void stageBrightness(float brightness) REQUIRES(SF_MAIN_THREAD);
-    void persistBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
-    bool isBrightnessStale() const REQUIRES(SF_MAIN_THREAD);
+    void stageBrightness(float brightness) REQUIRES(kMainThreadContext);
+    void persistBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
+    bool isBrightnessStale() const REQUIRES(kMainThreadContext);
     void setFlags(uint32_t flags);
 
     ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
@@ -109,7 +107,7 @@
 
     static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
 
-    std::optional<float> getStagedBrightness() const REQUIRES(SF_MAIN_THREAD);
+    std::optional<float> getStagedBrightness() const REQUIRES(kMainThreadContext);
     ui::Transform::RotationFlags getTransformHint() const;
     const ui::Transform& getTransform() const;
     const Rect& getLayerStackSpaceRect() const;
@@ -209,15 +207,15 @@
     bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock);
     std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock);
     void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock);
-    ActiveModeInfo getUpcomingActiveMode() const REQUIRES(SF_MAIN_THREAD) {
+    ActiveModeInfo getUpcomingActiveMode() const REQUIRES(kMainThreadContext) {
         return mUpcomingActiveMode;
     }
 
-    void setActiveMode(DisplayModeId) REQUIRES(SF_MAIN_THREAD);
+    void setActiveMode(DisplayModeId) REQUIRES(kMainThreadContext);
     status_t initiateModeChange(const ActiveModeInfo&,
                                 const hal::VsyncPeriodChangeConstraints& constraints,
                                 hal::VsyncPeriodChangeTimeline* outTimeline)
-            REQUIRES(SF_MAIN_THREAD);
+            REQUIRES(kMainThreadContext);
 
     // Return the immutable list of supported display modes. The HWC may report different modes
     // after a hotplug reconnect event, in which case the DisplayDevice object will be recreated.
@@ -304,7 +302,7 @@
     ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
     TracedOrdinal<bool> mDesiredActiveModeChanged
             GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
-    ActiveModeInfo mUpcomingActiveMode GUARDED_BY(SF_MAIN_THREAD);
+    ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
 };
 
 struct DisplayDeviceState {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 44c086d..05f488b 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -32,7 +32,6 @@
 #include <utils/Trace.h>
 
 #include <android/hardware/power/1.3/IPower.h>
-#include <android/hardware/power/IPower.h>
 #include <android/hardware/power/IPowerHintSession.h>
 #include <android/hardware/power/WorkDuration.h>
 
@@ -62,8 +61,6 @@
 
 using scheduler::OneShotTimer;
 
-class AidlPowerHalWrapper;
-
 PowerAdvisor::~PowerAdvisor() = default;
 
 namespace {
@@ -294,259 +291,232 @@
     const sp<V1_3::IPower> mPowerHal = nullptr;
 };
 
-class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
-public:
-    AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
-        auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
-        if (!ret.isOk()) {
-            mHasExpensiveRendering = false;
-        }
-
-        ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT,
-                                          &mHasDisplayUpdateImminent);
-        if (!ret.isOk()) {
-            mHasDisplayUpdateImminent = false;
-        }
-
-        mSupportsPowerHint = checkPowerHintSessionSupported();
+AidlPowerHalWrapper::AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
+    auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
+    if (!ret.isOk()) {
+        mHasExpensiveRendering = false;
     }
 
-    ~AidlPowerHalWrapper() override {
-        if (mPowerHintSession != nullptr) {
-            mPowerHintSession->close();
-            mPowerHintSession = nullptr;
-        }
-    };
-
-    static std::unique_ptr<HalWrapper> connect() {
-        // This only waits if the service is actually declared
-        sp<IPower> powerHal = waitForVintfService<IPower>();
-        if (powerHal == nullptr) {
-            return nullptr;
-        }
-        ALOGI("Loaded AIDL Power HAL service");
-
-        return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
+    ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT, &mHasDisplayUpdateImminent);
+    if (!ret.isOk()) {
+        mHasDisplayUpdateImminent = false;
     }
 
-    bool setExpensiveRendering(bool enabled) override {
-        ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
-        if (!mHasExpensiveRendering) {
-            ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
-            return true;
-        }
+    mSupportsPowerHint = checkPowerHintSessionSupported();
+}
 
-        auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
-        if (ret.isOk()) {
-            traceExpensiveRendering(enabled);
-        }
-        return ret.isOk();
+AidlPowerHalWrapper::~AidlPowerHalWrapper() {
+    if (mPowerHintSession != nullptr) {
+        mPowerHintSession->close();
+        mPowerHintSession = nullptr;
     }
-
-    bool notifyDisplayUpdateImminent() override {
-        ALOGV("AIDL notifyDisplayUpdateImminent");
-        if (!mHasDisplayUpdateImminent) {
-            ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
-            return true;
-        }
-
-        auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
-        return ret.isOk();
-    }
-
-    // only version 2+ of the aidl supports power hint sessions, hidl has no support
-    bool supportsPowerHintSession() override { return mSupportsPowerHint; }
-
-    bool checkPowerHintSessionSupported() {
-        int64_t unused;
-        // Try to get preferred rate to determine if hint sessions are supported
-        // We check for isOk not EX_UNSUPPORTED_OPERATION to lump other errors
-        return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
-    }
-
-    bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; }
-
-    void closePowerHintSession() {
-        if (mPowerHintSession != nullptr) {
-            mPowerHintSession->close();
-            mPowerHintSession = nullptr;
-        }
-    }
-
-    void restartPowerHintSession() {
-        closePowerHintSession();
-        startPowerHintSession();
-    }
-
-    void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override {
-        if (threadIds != mPowerHintThreadIds) {
-            mPowerHintThreadIds = threadIds;
-            if (isPowerHintSessionRunning()) {
-                restartPowerHintSession();
-            }
-        }
-    }
-
-    bool startPowerHintSession() override {
-        if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
-            ALOGV("Cannot start power hint session, skipping");
-            return false;
-        }
-        auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
-                                                mPowerHintThreadIds, mTargetDuration,
-                                                &mPowerHintSession);
-        if (!ret.isOk()) {
-            ALOGW("Failed to start power hint session with error: %s",
-                  ret.exceptionToString(ret.exceptionCode()).c_str());
-        } else {
-            mLastTargetDurationSent = mTargetDuration;
-        }
-        return isPowerHintSessionRunning();
-    }
-
-    bool shouldSetTargetDuration(int64_t targetDurationNanos) {
-        // report if the change in target from our last submission to now exceeds the threshold
-        return abs(1.0 -
-                   static_cast<double>(mLastTargetDurationSent) /
-                           static_cast<double>(targetDurationNanos)) >=
-                kAllowedTargetDeviationPercent;
-    }
-
-    void setTargetWorkDuration(int64_t targetDurationNanos) override {
-        ATRACE_CALL();
-        mTargetDuration = targetDurationNanos;
-        if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
-        if (!sNormalizeTarget && shouldSetTargetDuration(targetDurationNanos) &&
-            isPowerHintSessionRunning()) {
-            if (mLastActualDurationSent.has_value()) {
-                // update the error term here since we are actually sending an update to powerhal
-                if (sTraceHintSessionData)
-                    ATRACE_INT64("Target error term",
-                                 targetDurationNanos - *mLastActualDurationSent);
-            }
-            ALOGV("Sending target time: %lld ns", static_cast<long long>(targetDurationNanos));
-            mLastTargetDurationSent = targetDurationNanos;
-            auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
-            if (!ret.isOk()) {
-                ALOGW("Failed to set power hint target work duration with error: %s",
-                      ret.exceptionMessage().c_str());
-                mShouldReconnectHal = true;
-            }
-        }
-    }
-
-    bool shouldReportActualDurationsNow() {
-        // report if we have never reported before or are approaching a stale session
-        if (!mLastActualDurationSent.has_value() ||
-            (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
-            return true;
-        }
-
-        if (!mActualDuration.has_value()) {
-            return false;
-        }
-
-        // duration of most recent timing
-        const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
-        // duration of the last timing actually reported to the powerhal
-        const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
-
-        // report if the change in duration from then to now exceeds the threshold
-        return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
-                kAllowedActualDeviationPercent;
-    }
-
-    void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override {
-        ATRACE_CALL();
-
-        if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
-            ALOGV("Failed to send actual work duration, skipping");
-            return;
-        }
-
-        WorkDuration duration;
-        duration.durationNanos = actualDurationNanos;
-        mActualDuration = actualDurationNanos;
-
-        // normalize the sent values to a pre-set target
-        if (sNormalizeTarget) {
-            duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
-        }
-        duration.timeStampNanos = timeStampNanos;
-        mPowerHintQueue.push_back(duration);
-
-        long long targetNsec = mTargetDuration;
-        long long durationNsec = actualDurationNanos;
-
-        if (sTraceHintSessionData) {
-            ATRACE_INT64("Measured duration", durationNsec);
-            ATRACE_INT64("Target error term", targetNsec - durationNsec);
-        }
-
-        ALOGV("Sending actual work duration of: %lld on target: %lld with error: %lld",
-              durationNsec, targetNsec, targetNsec - durationNsec);
-
-        // This rate limiter queues similar duration reports to the powerhal into
-        // batches to avoid excessive binder calls. The criteria to send a given batch
-        // are outlined in shouldReportActualDurationsNow()
-        if (shouldReportActualDurationsNow()) {
-            ALOGV("Sending hint update batch");
-            mLastActualReportTimestamp = systemTime();
-            auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
-            if (!ret.isOk()) {
-                ALOGW("Failed to report actual work durations with error: %s",
-                      ret.exceptionMessage().c_str());
-                mShouldReconnectHal = true;
-            }
-            mPowerHintQueue.clear();
-            // we save the non-normalized value here to detect % changes
-            mLastActualDurationSent = actualDurationNanos;
-        }
-    }
-
-    bool shouldReconnectHAL() override { return mShouldReconnectHal; }
-
-    std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; }
-
-    std::optional<int64_t> getTargetWorkDuration() override { return mTargetDuration; }
-
-private:
-    const sp<IPower> mPowerHal = nullptr;
-    bool mHasExpensiveRendering = false;
-    bool mHasDisplayUpdateImminent = false;
-    // Used to indicate an error state and need for reconstruction
-    bool mShouldReconnectHal = false;
-    // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
-    sp<IPowerHintSession> mPowerHintSession = nullptr;
-    // Queue of actual durations saved to report
-    std::vector<WorkDuration> mPowerHintQueue;
-    // The latest un-normalized values we have received for target and actual
-    int64_t mTargetDuration = kDefaultTarget.count();
-    std::optional<int64_t> mActualDuration;
-    // The list of thread ids, stored so we can restart the session from this class if needed
-    std::vector<int32_t> mPowerHintThreadIds;
-    bool mSupportsPowerHint;
-    // Keep track of the last messages sent for rate limiter change detection
-    std::optional<int64_t> mLastActualDurationSent;
-    // timestamp of the last report we sent, used to avoid stale sessions
-    int64_t mLastActualReportTimestamp = 0;
-    int64_t mLastTargetDurationSent = kDefaultTarget.count();
-    // Whether to normalize all the actual values as error terms relative to a constant target
-    // This saves a binder call by not setting the target, and should not affect the pid values
-    static const bool sNormalizeTarget;
-    // Whether we should emit ATRACE_INT data for hint sessions
-    static const bool sTraceHintSessionData;
-    // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
-    static constexpr double kAllowedActualDeviationPercent = 0.1;
-    // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
-    static constexpr double kAllowedTargetDeviationPercent = 0.05;
-    // Target used for init and normalization, the actual value does not really matter
-    static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
-    // Amount of time after the last message was sent before the session goes stale
-    // actually 100ms but we use 80 here to ideally avoid going stale
-    static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
 };
 
+std::unique_ptr<PowerAdvisor::HalWrapper> AidlPowerHalWrapper::connect() {
+    // This only waits if the service is actually declared
+    sp<IPower> powerHal = waitForVintfService<IPower>();
+    if (powerHal == nullptr) {
+        return nullptr;
+    }
+    ALOGI("Loaded AIDL Power HAL service");
+
+    return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
+}
+
+bool AidlPowerHalWrapper::setExpensiveRendering(bool enabled) {
+    ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
+    if (!mHasExpensiveRendering) {
+        ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
+        return true;
+    }
+
+    auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
+    if (ret.isOk()) {
+        traceExpensiveRendering(enabled);
+    }
+    return ret.isOk();
+}
+
+bool AidlPowerHalWrapper::notifyDisplayUpdateImminent() {
+    ALOGV("AIDL notifyDisplayUpdateImminent");
+    if (!mHasDisplayUpdateImminent) {
+        ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
+        return true;
+    }
+
+    auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
+    return ret.isOk();
+}
+
+// only version 2+ of the aidl supports power hint sessions, hidl has no support
+bool AidlPowerHalWrapper::supportsPowerHintSession() {
+    return mSupportsPowerHint;
+}
+
+bool AidlPowerHalWrapper::checkPowerHintSessionSupported() {
+    int64_t unused;
+    // Try to get preferred rate to determine if hint sessions are supported
+    // We check for isOk not EX_UNSUPPORTED_OPERATION to lump together errors
+    return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
+}
+
+bool AidlPowerHalWrapper::isPowerHintSessionRunning() {
+    return mPowerHintSession != nullptr;
+}
+
+void AidlPowerHalWrapper::closePowerHintSession() {
+    if (mPowerHintSession != nullptr) {
+        mPowerHintSession->close();
+        mPowerHintSession = nullptr;
+    }
+}
+
+void AidlPowerHalWrapper::restartPowerHintSession() {
+    closePowerHintSession();
+    startPowerHintSession();
+}
+
+void AidlPowerHalWrapper::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) {
+    if (threadIds != mPowerHintThreadIds) {
+        mPowerHintThreadIds = threadIds;
+        if (isPowerHintSessionRunning()) {
+            restartPowerHintSession();
+        }
+    }
+}
+
+bool AidlPowerHalWrapper::startPowerHintSession() {
+    if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
+        ALOGV("Cannot start power hint session, skipping");
+        return false;
+    }
+    auto ret =
+            mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
+                                         mPowerHintThreadIds, mTargetDuration, &mPowerHintSession);
+    if (!ret.isOk()) {
+        ALOGW("Failed to start power hint session with error: %s",
+              ret.exceptionToString(ret.exceptionCode()).c_str());
+    } else {
+        mLastTargetDurationSent = mTargetDuration;
+    }
+    return isPowerHintSessionRunning();
+}
+
+bool AidlPowerHalWrapper::shouldSetTargetDuration(int64_t targetDurationNanos) {
+    if (targetDurationNanos <= 0) {
+        return false;
+    }
+    // report if the change in target from our last submission to now exceeds the threshold
+    return abs(1.0 -
+               static_cast<double>(mLastTargetDurationSent) /
+                       static_cast<double>(targetDurationNanos)) >= kAllowedTargetDeviationPercent;
+}
+
+void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDurationNanos) {
+    ATRACE_CALL();
+    mTargetDuration = targetDurationNanos;
+    if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
+    if (!sNormalizeTarget && isPowerHintSessionRunning() &&
+        shouldSetTargetDuration(targetDurationNanos)) {
+        if (mLastActualDurationSent.has_value()) {
+            // update the error term here since we are actually sending an update to powerhal
+            if (sTraceHintSessionData)
+                ATRACE_INT64("Target error term", targetDurationNanos - *mLastActualDurationSent);
+        }
+        ALOGV("Sending target time: %" PRId64 "ns", targetDurationNanos);
+        mLastTargetDurationSent = targetDurationNanos;
+        auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
+        if (!ret.isOk()) {
+            ALOGW("Failed to set power hint target work duration with error: %s",
+                  ret.exceptionMessage().c_str());
+            mShouldReconnectHal = true;
+        }
+    }
+}
+
+bool AidlPowerHalWrapper::shouldReportActualDurationsNow() {
+    // report if we have never reported before or are approaching a stale session
+    if (!mLastActualDurationSent.has_value() ||
+        (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
+        return true;
+    }
+
+    if (!mActualDuration.has_value()) {
+        return false;
+    }
+
+    // duration of most recent timing
+    const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
+    // duration of the last timing actually reported to the powerhal
+    const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
+
+    // report if the change in duration from then to now exceeds the threshold
+    return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
+            kAllowedActualDeviationPercent;
+}
+
+void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDurationNanos,
+                                                 nsecs_t timeStampNanos) {
+    ATRACE_CALL();
+
+    if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
+        ALOGV("Failed to send actual work duration, skipping");
+        return;
+    }
+
+    WorkDuration duration;
+    duration.durationNanos = actualDurationNanos;
+    mActualDuration = actualDurationNanos;
+
+    // normalize the sent values to a pre-set target
+    if (sNormalizeTarget) {
+        duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
+    }
+    duration.timeStampNanos = timeStampNanos;
+    mPowerHintQueue.push_back(duration);
+
+    nsecs_t targetNsec = mTargetDuration;
+    nsecs_t durationNsec = actualDurationNanos;
+
+    if (sTraceHintSessionData) {
+        ATRACE_INT64("Measured duration", durationNsec);
+        ATRACE_INT64("Target error term", targetNsec - durationNsec);
+    }
+
+    ALOGV("Sending actual work duration of: %" PRId64 " on target: %" PRId64
+          " with error: %" PRId64,
+          durationNsec, targetNsec, targetNsec - durationNsec);
+
+    // This rate limiter queues similar duration reports to the powerhal into
+    // batches to avoid excessive binder calls. The criteria to send a given batch
+    // are outlined in shouldReportActualDurationsNow()
+    if (shouldReportActualDurationsNow()) {
+        ALOGV("Sending hint update batch");
+        mLastActualReportTimestamp = systemTime();
+        auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
+        if (!ret.isOk()) {
+            ALOGW("Failed to report actual work durations with error: %s",
+                  ret.exceptionMessage().c_str());
+            mShouldReconnectHal = true;
+        }
+        mPowerHintQueue.clear();
+        // we save the non-normalized value here to detect % changes
+        mLastActualDurationSent = actualDurationNanos;
+    }
+}
+
+bool AidlPowerHalWrapper::shouldReconnectHAL() {
+    return mShouldReconnectHal;
+}
+
+std::vector<int32_t> AidlPowerHalWrapper::getPowerHintSessionThreadIds() {
+    return mPowerHintThreadIds;
+}
+
+std::optional<int64_t> AidlPowerHalWrapper::getTargetWorkDuration() {
+    return mTargetDuration;
+}
+
 const bool AidlPowerHalWrapper::sTraceHintSessionData =
         base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
 
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 0db56aa..3f47ffd 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -22,6 +22,7 @@
 
 #include <utils/Mutex.h>
 
+#include <android/hardware/power/IPower.h>
 #include <ui/DisplayIdentification.h>
 #include "../Scheduler/OneShotTimer.h"
 
@@ -118,6 +119,69 @@
     scheduler::OneShotTimer mScreenUpdateTimer;
 };
 
+class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
+public:
+    explicit AidlPowerHalWrapper(sp<hardware::power::IPower> powerHal);
+    ~AidlPowerHalWrapper() override;
+
+    static std::unique_ptr<HalWrapper> connect();
+
+    bool setExpensiveRendering(bool enabled) override;
+    bool notifyDisplayUpdateImminent() override;
+    bool supportsPowerHintSession() override;
+    bool isPowerHintSessionRunning() override;
+    void restartPowerHintSession() override;
+    void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
+    bool startPowerHintSession() override;
+    void setTargetWorkDuration(int64_t targetDurationNanos) override;
+    void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override;
+    bool shouldReconnectHAL() override;
+    std::vector<int32_t> getPowerHintSessionThreadIds() override;
+    std::optional<int64_t> getTargetWorkDuration() override;
+
+private:
+    bool checkPowerHintSessionSupported();
+    void closePowerHintSession();
+    bool shouldReportActualDurationsNow();
+    bool shouldSetTargetDuration(int64_t targetDurationNanos);
+
+    const sp<hardware::power::IPower> mPowerHal = nullptr;
+    bool mHasExpensiveRendering = false;
+    bool mHasDisplayUpdateImminent = false;
+    // Used to indicate an error state and need for reconstruction
+    bool mShouldReconnectHal = false;
+    // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
+    sp<hardware::power::IPowerHintSession> mPowerHintSession = nullptr;
+    // Queue of actual durations saved to report
+    std::vector<hardware::power::WorkDuration> mPowerHintQueue;
+    // The latest un-normalized values we have received for target and actual
+    int64_t mTargetDuration = kDefaultTarget.count();
+    std::optional<int64_t> mActualDuration;
+    // The list of thread ids, stored so we can restart the session from this class if needed
+    std::vector<int32_t> mPowerHintThreadIds;
+    bool mSupportsPowerHint;
+    // Keep track of the last messages sent for rate limiter change detection
+    std::optional<int64_t> mLastActualDurationSent;
+    // timestamp of the last report we sent, used to avoid stale sessions
+    int64_t mLastActualReportTimestamp = 0;
+    int64_t mLastTargetDurationSent = kDefaultTarget.count();
+    // Whether to normalize all the actual values as error terms relative to a constant target
+    // This saves a binder call by not setting the target, and should not affect the pid values
+    static const bool sNormalizeTarget;
+    // Whether we should emit ATRACE_INT data for hint sessions
+    static const bool sTraceHintSessionData;
+
+    // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
+    static constexpr double kAllowedActualDeviationPercent = 0.1;
+    // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
+    static constexpr double kAllowedTargetDeviationPercent = 0.05;
+    // Target used for init and normalization, the actual value does not really matter
+    static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
+    // Amount of time after the last message was sent before the session goes stale
+    // actually 100ms but we use 80 here to ideally avoid going stale
+    static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
+};
+
 } // namespace impl
 } // namespace Hwc2
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index b4fb51f..3803a78 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -19,20 +19,20 @@
 #pragma clang diagnostic ignored "-Wconversion"
 
 // #define LOG_NDEBUG 0
-#include "VirtualDisplaySurface.h"
 
 #include <cinttypes>
 
-#include "HWComposer.h"
-#include "SurfaceFlinger.h"
-
-#include <ftl/Flags.h>
 #include <ftl/enum.h>
+#include <ftl/flags.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
 #include <gui/IProducerListener.h>
 #include <system/window.h>
 
+#include "HWComposer.h"
+#include "SurfaceFlinger.h"
+#include "VirtualDisplaySurface.h"
+
 #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \
         mDisplayName.c_str(), ##__VA_ARGS__)
 #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \
@@ -657,7 +657,7 @@
 
 std::string VirtualDisplaySurface::toString(CompositionType type) {
     using namespace std::literals;
-    return type == CompositionType::Unknown ? "Unknown"s : Flags(type).string();
+    return type == CompositionType::Unknown ? "Unknown"s : ftl::Flags(type).string();
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index fa5a1c8..bd73723 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -37,6 +37,7 @@
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
 #include <ftl/enum.h>
+#include <ftl/fake_guard.h>
 #include <gui/BufferItem.h>
 #include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
@@ -81,11 +82,13 @@
 constexpr int kDumpTableRowLength = 159;
 } // namespace
 
+using namespace ftl::flag_operators;
+
 using base::StringAppendF;
-using namespace android::flag_operators;
-using PresentState = frametimeline::SurfaceFrame::PresentState;
 using gui::WindowInfo;
 
+using PresentState = frametimeline::SurfaceFrame::PresentState;
+
 std::atomic<int32_t> Layer::sSequence{1};
 
 Layer::Layer(const LayerCreationArgs& args)
@@ -139,6 +142,7 @@
     mDrawingState.destinationFrame.makeInvalid();
     mDrawingState.isTrustedOverlay = false;
     mDrawingState.dropInputMode = gui::DropInputMode::NONE;
+    mDrawingState.dimmingEnabled = true;
 
     if (args.flags & ISurfaceComposerClient::eNoColorFill) {
         // Set an invalid color so there is no color fill.
@@ -477,6 +481,7 @@
     compositionState->colorTransformIsIdentity = !hasColorTransform();
     compositionState->surfaceDamage = surfaceDamageRegion;
     compositionState->hasProtectedContent = isProtected();
+    compositionState->dimmingEnabled = isDimmingEnabled();
 
     const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
 
@@ -1038,6 +1043,16 @@
     return true;
 }
 
+bool Layer::setDimmingEnabled(const bool dimmingEnabled) {
+    if (mDrawingState.dimmingEnabled == dimmingEnabled) return false;
+
+    mDrawingState.sequence++;
+    mDrawingState.dimmingEnabled = dimmingEnabled;
+    mDrawingState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 bool Layer::setFrameRateSelectionPriority(int32_t priority) {
     if (mDrawingState.frameRateSelectionPriority == priority) return false;
     mDrawingState.frameRateSelectionPriority = priority;
@@ -1373,10 +1388,10 @@
 // ----------------------------------------------------------------------------
 
 // TODO(marissaw): add new layer state info to layer debugging
-LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const {
+gui::LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const {
     using namespace std::string_literals;
 
-    LayerDebugInfo info;
+    gui::LayerDebugInfo info;
     const State& ds = getDrawingState();
     info.mName = getName();
     sp<Layer> parent = mDrawingParent.promote();
@@ -2045,10 +2060,10 @@
     writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
 
     if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
+        ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread.
+
         // Only populate for the primary display.
-        UnnecessaryLock assumeLocked(mFlinger->mStateLock); // called from the main thread.
-        const auto display = mFlinger->getDefaultDisplayDeviceLocked();
-        if (display) {
+        if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) {
             const auto compositionType = getCompositionType(*display);
             layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
             LayerProtoHelper::writeToProto(getVisibleRegion(display.get()),
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 846460d..455920b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -69,13 +69,16 @@
 class DisplayDevice;
 class GraphicBuffer;
 class SurfaceFlinger;
-class LayerDebugInfo;
 
 namespace compositionengine {
 class OutputLayer;
 struct LayerFECompositionState;
 }
 
+namespace gui {
+class LayerDebugInfo;
+}
+
 namespace impl {
 class SurfaceInterceptor;
 }
@@ -281,6 +284,8 @@
         gui::DropInputMode dropInputMode;
 
         bool autoRefresh = false;
+
+        bool dimmingEnabled = true;
     };
 
     /*
@@ -411,6 +416,7 @@
     virtual mat4 getColorTransform() const;
     virtual bool hasColorTransform() const;
     virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
+    virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; };
 
     // Used only to set BufferStateLayer state
     virtual bool setTransform(uint32_t /*transform*/) { return false; };
@@ -437,6 +443,7 @@
     }
     virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
     virtual bool setColorSpaceAgnostic(const bool agnostic);
+    virtual bool setDimmingEnabled(const bool dimmingEnabled);
     virtual bool setFrameRateSelectionPriority(int32_t priority);
     virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
     virtual void setAutoRefresh(bool /* autoRefresh */) {}
@@ -737,7 +744,7 @@
     inline const State& getDrawingState() const { return mDrawingState; }
     inline State& getDrawingState() { return mDrawingState; }
 
-    LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const;
+    gui::LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const;
 
     void miniDump(std::string& result, const DisplayDevice&) const;
     void dumpFrameStats(std::string& result) const;
diff --git a/services/surfaceflinger/MainThreadGuard.h b/services/surfaceflinger/MainThreadGuard.h
deleted file mode 100644
index c1aa118..0000000
--- a/services/surfaceflinger/MainThreadGuard.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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/Mutex.h>
-
-namespace android {
-namespace {
-
-// Helps to ensure that some functions runs on SF's main thread by using the
-// clang thread safety annotations.
-class CAPABILITY("mutex") MainThreadGuard {
-} SF_MAIN_THREAD;
-
-struct SCOPED_CAPABILITY MainThreadScopedGuard {
-public:
-    explicit MainThreadScopedGuard(MainThreadGuard& mutex) ACQUIRE(mutex) {}
-    ~MainThreadScopedGuard() RELEASE() {}
-};
-} // namespace
-} // namespace android
diff --git a/services/surfaceflinger/MutexUtils.h b/services/surfaceflinger/MutexUtils.h
new file mode 100644
index 0000000..f8be6f3
--- /dev/null
+++ b/services/surfaceflinger/MutexUtils.h
@@ -0,0 +1,53 @@
+/*
+ * 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
+
+#include <log/log.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+struct SCOPED_CAPABILITY ConditionalLock {
+    ConditionalLock(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) {
+        if (lock) mutex.lock();
+    }
+
+    ~ConditionalLock() RELEASE() {
+        if (lock) mutex.unlock();
+    }
+
+    Mutex& mutex;
+    const bool lock;
+};
+
+struct SCOPED_CAPABILITY TimedLock {
+    TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex)
+          : mutex(mutex), status(mutex.timedLock(timeout)) {
+        ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status);
+    }
+
+    ~TimedLock() RELEASE() {
+        if (locked()) mutex.unlock();
+    }
+
+    bool locked() const { return status == NO_ERROR; }
+
+    Mutex& mutex;
+    const status_t status;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 81c1566..80aa072 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wextra"
-
 #include <algorithm>
 
 #include "RefreshRateOverlay.h"
 #include "Client.h"
 #include "Layer.h"
 
-#include <SkBlendMode.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include <SkCanvas.h>
 #include <SkPaint.h>
+#pragma clang diagnostic pop
+#include <SkBlendMode.h>
 #include <SkRect.h>
 #include <SkSurface.h>
-#include <gui/IProducerListener.h>
 #include <gui/SurfaceComposerClient.h>
 #include <gui/SurfaceControl.h>
 
@@ -37,29 +35,40 @@
 #define LOG_TAG "RefreshRateOverlay"
 
 namespace android {
+namespace {
 
-void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor& color,
+constexpr int kDigitWidth = 64;
+constexpr int kDigitHeight = 100;
+constexpr int kDigitSpace = 16;
+
+// Layout is digit, space, digit, space, digit, space, spinner.
+constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace;
+constexpr int kBufferHeight = kDigitHeight;
+
+} // namespace
+
+void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color,
                                                          SkCanvas& canvas) {
     const SkRect rect = [&]() {
         switch (segment) {
             case Segment::Upper:
-                return SkRect::MakeLTRB(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
+                return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace);
             case Segment::UpperLeft:
-                return SkRect::MakeLTRB(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
+                return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2);
             case Segment::UpperRight:
-                return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
-                                        DIGIT_HEIGHT / 2);
+                return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth,
+                                        kDigitHeight / 2);
             case Segment::Middle:
-                return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2,
-                                        left + DIGIT_WIDTH, DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
+                return SkRect::MakeLTRB(left, kDigitHeight / 2 - kDigitSpace / 2,
+                                        left + kDigitWidth, kDigitHeight / 2 + kDigitSpace / 2);
             case Segment::LowerLeft:
-                return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
+                return SkRect::MakeLTRB(left, kDigitHeight / 2, left + kDigitSpace, kDigitHeight);
             case Segment::LowerRight:
-                return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2,
-                                        left + DIGIT_WIDTH, DIGIT_HEIGHT);
+                return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2,
+                                        left + kDigitWidth, kDigitHeight);
             case Segment::Bottom:
-                return SkRect::MakeLTRB(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH,
-                                        DIGIT_HEIGHT);
+                return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth,
+                                        kDigitHeight);
         }
     }();
 
@@ -69,7 +78,7 @@
     canvas.drawRect(rect, paint);
 }
 
-void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor& color,
+void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor color,
                                                        SkCanvas& canvas) {
     if (digit < 0 || digit > 9) return;
 
@@ -94,37 +103,45 @@
         drawSegment(Segment::Bottom, left, color, canvas);
 }
 
-std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::draw(
-        int number, SkColor& color, ui::Transform::RotationFlags rotation, bool showSpinner) {
+auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color,
+                                                  ui::Transform::RotationFlags rotation,
+                                                  bool showSpinner) -> Buffers {
     if (number < 0 || number > 1000) return {};
 
     const auto hundreds = number / 100;
     const auto tens = (number / 10) % 10;
     const auto ones = number % 10;
 
-    std::vector<sp<GraphicBuffer>> buffers;
-    const auto loopCount = showSpinner ? 6 : 1;
-    for (int i = 0; i < loopCount; i++) {
+    const size_t loopCount = showSpinner ? 6 : 1;
+
+    Buffers buffers;
+    buffers.reserve(loopCount);
+
+    for (size_t i = 0; i < loopCount; i++) {
         // Pre-rotate the buffer before it reaches SurfaceFlinger.
         SkMatrix canvasTransform = SkMatrix();
-        auto [bufferWidth, bufferHeight] = [&] {
+        const auto [bufferWidth, bufferHeight] = [&]() -> std::pair<int, int> {
             switch (rotation) {
                 case ui::Transform::ROT_90:
-                    canvasTransform.setTranslate(BUFFER_HEIGHT, 0);
-                    canvasTransform.preRotate(90);
-                    return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
+                    canvasTransform.setTranslate(kBufferHeight, 0);
+                    canvasTransform.preRotate(90.f);
+                    return {kBufferHeight, kBufferWidth};
                 case ui::Transform::ROT_270:
-                    canvasTransform.setRotate(270, BUFFER_WIDTH / 2.0, BUFFER_WIDTH / 2.0);
-                    return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
+                    canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f);
+                    return {kBufferHeight, kBufferWidth};
                 default:
-                    return std::make_tuple(BUFFER_WIDTH, BUFFER_HEIGHT);
+                    return {kBufferWidth, kBufferHeight};
             }
         }();
+
         sp<GraphicBuffer> buffer =
-                new GraphicBuffer(bufferWidth, bufferHeight, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+                new GraphicBuffer(static_cast<uint32_t>(bufferWidth),
+                                  static_cast<uint32_t>(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888,
+                                  1,
                                   GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
                                           GRALLOC_USAGE_HW_TEXTURE,
                                   "RefreshRateOverlayBuffer");
+
         const status_t bufferStatus = buffer->initCheck();
         LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
                             bufferStatus);
@@ -137,15 +154,15 @@
         if (hundreds != 0) {
             drawDigit(hundreds, left, color, *canvas);
         }
-        left += DIGIT_WIDTH + DIGIT_SPACE;
+        left += kDigitWidth + kDigitSpace;
 
         if (tens != 0) {
             drawDigit(tens, left, color, *canvas);
         }
-        left += DIGIT_WIDTH + DIGIT_SPACE;
+        left += kDigitWidth + kDigitSpace;
 
         drawDigit(ones, left, color, *canvas);
-        left += DIGIT_WIDTH + DIGIT_SPACE;
+        left += kDigitWidth + kDigitSpace;
 
         if (showSpinner) {
             switch (i) {
@@ -172,51 +189,48 @@
 
         void* pixels = nullptr;
         buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
+
         const SkImageInfo& imageInfo = surface->imageInfo();
-        size_t dstRowBytes = buffer->getStride() * imageInfo.bytesPerPixel();
+        const size_t dstRowBytes =
+                buffer->getStride() * static_cast<size_t>(imageInfo.bytesPerPixel());
+
         canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
         buffer->unlock();
-        buffers.emplace_back(buffer);
+        buffers.push_back(std::move(buffer));
     }
     return buffers;
 }
 
-RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, uint32_t lowFps, uint32_t highFps,
-                                       bool showSpinner)
-      : mFlinger(flinger),
-        mClient(new Client(&mFlinger)),
+RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner)
+      : mFpsRange(fpsRange),
         mShowSpinner(showSpinner),
-        mLowFps(lowFps),
-        mHighFps(highFps) {
-    createLayer();
-}
-
-bool RefreshRateOverlay::createLayer() {
-    mSurfaceControl =
-            SurfaceComposerClient::getDefault()
-                    ->createSurface(String8("RefreshRateOverlay"), SevenSegmentDrawer::getWidth(),
-                                    SevenSegmentDrawer::getHeight(), PIXEL_FORMAT_RGBA_8888,
-                                    ISurfaceComposerClient::eFXSurfaceBufferState);
-
+        mSurfaceControl(SurfaceComposerClient::getDefault()
+                                ->createSurface(String8("RefreshRateOverlay"), kBufferWidth,
+                                                kBufferHeight, PIXEL_FORMAT_RGBA_8888,
+                                                ISurfaceComposerClient::eFXSurfaceBufferState)) {
     if (!mSurfaceControl) {
-        ALOGE("failed to create buffer state layer");
-        return false;
+        ALOGE("%s: Failed to create buffer state layer", __func__);
+        return;
     }
 
+    constexpr float kFrameRate = 0.f;
+    constexpr int8_t kCompatibility = static_cast<int8_t>(Layer::FrameRateCompatibility::NoVote);
+    constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
+
     SurfaceComposerClient::Transaction()
-            .setFrameRate(mSurfaceControl, 0.0f,
-                          static_cast<int8_t>(Layer::FrameRateCompatibility::NoVote),
-                          static_cast<int8_t>(scheduler::Seamlessness::OnlySeamless))
+            .setFrameRate(mSurfaceControl, kFrameRate, kCompatibility, kSeamlessness)
             .setLayer(mSurfaceControl, INT32_MAX - 2)
             .setTrustedOverlay(mSurfaceControl, true)
             .apply();
-
-    return true;
 }
 
-const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
-    ui::Transform::RotationFlags transformHint =
+auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& {
+    static const Buffers kNoBuffers;
+    if (!mSurfaceControl) return kNoBuffers;
+
+    const auto transformHint =
             static_cast<ui::Transform::RotationFlags>(mSurfaceControl->getTransformHint());
+
     // Tell SurfaceFlinger about the pre-rotation on the buffer.
     const auto transform = [&] {
         switch (transformHint) {
@@ -233,40 +247,49 @@
     t.setTransform(mSurfaceControl, transform);
     t.apply();
 
-    if (mBufferCache.find(transformHint) == mBufferCache.end() ||
-        mBufferCache.at(transformHint).find(fps) == mBufferCache.at(transformHint).end()) {
-        // Ensure the range is > 0, so we don't divide by 0.
-        const auto rangeLength = std::max(1u, mHighFps - mLowFps);
-        // Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside
-        // of this range if the display has changed its set of supported refresh rates.
-        fps = std::max(fps, mLowFps);
-        fps = std::min(fps, mHighFps);
-        const auto fpsScale = static_cast<float>(fps - mLowFps) / rangeLength;
-        SkColor4f colorBase = SkColor4f::FromColor(HIGH_FPS_COLOR) * fpsScale;
-        SkColor4f lowFpsColor = SkColor4f::FromColor(LOW_FPS_COLOR) * (1 - fpsScale);
-        colorBase.fR = colorBase.fR + lowFpsColor.fR;
-        colorBase.fG = colorBase.fG + lowFpsColor.fG;
-        colorBase.fB = colorBase.fB + lowFpsColor.fB;
-        colorBase.fA = ALPHA;
-        SkColor color = colorBase.toSkColor();
-        auto buffers = SevenSegmentDrawer::draw(fps, color, transformHint, mShowSpinner);
-        mBufferCache[transformHint].emplace(fps, buffers);
+    BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint});
+    if (it == mBufferCache.end()) {
+        const int minFps = mFpsRange.min.getIntValue();
+        const int maxFps = mFpsRange.max.getIntValue();
+
+        // Clamp to the range. The current fps may be outside of this range if the display has
+        // changed its set of supported refresh rates.
+        const int intFps = std::clamp(fps.getIntValue(), minFps, maxFps);
+
+        // Ensure non-zero range to avoid division by zero.
+        const float fpsScale = static_cast<float>(intFps - minFps) / std::max(1, maxFps - minFps);
+
+        constexpr SkColor kMinFpsColor = SK_ColorRED;
+        constexpr SkColor kMaxFpsColor = SK_ColorGREEN;
+        constexpr float kAlpha = 0.8f;
+
+        SkColor4f colorBase = SkColor4f::FromColor(kMaxFpsColor) * fpsScale;
+        const SkColor4f minFpsColor = SkColor4f::FromColor(kMinFpsColor) * (1 - fpsScale);
+
+        colorBase.fR = colorBase.fR + minFpsColor.fR;
+        colorBase.fG = colorBase.fG + minFpsColor.fG;
+        colorBase.fB = colorBase.fB + minFpsColor.fB;
+        colorBase.fA = kAlpha;
+
+        const SkColor color = colorBase.toSkColor();
+
+        auto buffers = SevenSegmentDrawer::draw(intFps, color, transformHint, mShowSpinner);
+        it = mBufferCache.try_emplace({intFps, transformHint}, std::move(buffers)).first;
     }
 
-    return mBufferCache[transformHint][fps];
+    return it->second;
 }
 
 void RefreshRateOverlay::setViewport(ui::Size viewport) {
     constexpr int32_t kMaxWidth = 1000;
-    const auto width = std::min(kMaxWidth, std::min(viewport.width, viewport.height));
+    const auto width = std::min({kMaxWidth, viewport.width, viewport.height});
     const auto height = 2 * width;
     Rect frame((3 * width) >> 4, height >> 5);
     frame.offsetBy(width >> 5, height >> 4);
 
     SurfaceComposerClient::Transaction t;
-    t.setMatrix(mSurfaceControl,
-                frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth()), 0, 0,
-                frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight()));
+    t.setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
+                frame.getHeight() / static_cast<float>(kBufferHeight));
     t.setPosition(mSurfaceControl, frame.left, frame.top);
     t.apply();
 }
@@ -278,25 +301,22 @@
 }
 
 void RefreshRateOverlay::changeRefreshRate(Fps fps) {
-    mCurrentFps = fps.getIntValue();
-    auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
+    mCurrentFps = fps;
+    const auto buffer = getOrCreateBuffers(fps)[mFrame];
     SurfaceComposerClient::Transaction t;
     t.setBuffer(mSurfaceControl, buffer);
     t.apply();
 }
 
 void RefreshRateOverlay::animate() {
-    if (!mCurrentFps.has_value()) return;
+    if (!mShowSpinner || !mCurrentFps) return;
 
     const auto& buffers = getOrCreateBuffers(*mCurrentFps);
     mFrame = (mFrame + 1) % buffers.size();
-    auto buffer = buffers[mFrame];
+    const auto buffer = buffers[mFrame];
     SurfaceComposerClient::Transaction t;
     t.setBuffer(mSurfaceControl, buffer);
     t.apply();
 }
 
 } // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 381df37..a465a36 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -16,32 +16,27 @@
 
 #pragma once
 
-#include <SkCanvas.h>
 #include <SkColor.h>
-#include <unordered_map>
+#include <vector>
 
-#include <math/vec4.h>
-#include <renderengine/RenderEngine.h>
+#include <ftl/small_map.h>
 #include <ui/LayerStack.h>
-#include <ui/Rect.h>
 #include <ui/Size.h>
+#include <ui/Transform.h>
 #include <utils/StrongPointer.h>
 
 #include <scheduler/Fps.h>
 
+class SkCanvas;
+
 namespace android {
 
-class Client;
 class GraphicBuffer;
-class IBinder;
-class IGraphicBufferProducer;
-class Layer;
-class SurfaceFlinger;
 class SurfaceControl;
 
 class RefreshRateOverlay {
 public:
-    RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner);
+    RefreshRateOverlay(FpsRange, bool showSpinner);
 
     void setLayerStack(ui::LayerStack);
     void setViewport(ui::Size);
@@ -49,52 +44,38 @@
     void animate();
 
 private:
+    using Buffers = std::vector<sp<GraphicBuffer>>;
+
     class SevenSegmentDrawer {
     public:
-        static std::vector<sp<GraphicBuffer>> draw(int number, SkColor& color,
-                                                   ui::Transform::RotationFlags, bool showSpinner);
-        static uint32_t getHeight() { return BUFFER_HEIGHT; }
-        static uint32_t getWidth() { return BUFFER_WIDTH; }
+        static Buffers draw(int number, SkColor, ui::Transform::RotationFlags, bool showSpinner);
 
     private:
         enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Bottom };
 
-        static void drawSegment(Segment segment, int left, SkColor& color, SkCanvas& canvas);
-        static void drawDigit(int digit, int left, SkColor& color, SkCanvas& canvas);
-
-        static constexpr uint32_t DIGIT_HEIGHT = 100;
-        static constexpr uint32_t DIGIT_WIDTH = 64;
-        static constexpr uint32_t DIGIT_SPACE = 16;
-        static constexpr uint32_t BUFFER_HEIGHT = DIGIT_HEIGHT;
-        static constexpr uint32_t BUFFER_WIDTH =
-                4 * DIGIT_WIDTH + 3 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit|Space|Spinner
+        static void drawSegment(Segment, int left, SkColor, SkCanvas&);
+        static void drawDigit(int digit, int left, SkColor, SkCanvas&);
     };
 
-    bool createLayer();
+    const Buffers& getOrCreateBuffers(Fps);
 
-    const std::vector<sp<GraphicBuffer>>& getOrCreateBuffers(uint32_t fps);
+    struct Key {
+        int fps;
+        ui::Transform::RotationFlags flags;
 
-    SurfaceFlinger& mFlinger;
-    const sp<Client> mClient;
-    sp<IBinder> mIBinder;
-    sp<IGraphicBufferProducer> mGbp;
+        bool operator==(Key other) const { return fps == other.fps && flags == other.flags; }
+    };
 
-    std::unordered_map<ui::Transform::RotationFlags,
-                       std::unordered_map<int, std::vector<sp<GraphicBuffer>>>>
-            mBufferCache;
-    std::optional<int> mCurrentFps;
-    int mFrame = 0;
-    static constexpr float ALPHA = 0.8f;
-    const SkColor LOW_FPS_COLOR = SK_ColorRED;
-    const SkColor HIGH_FPS_COLOR = SK_ColorGREEN;
+    using BufferCache = ftl::SmallMap<Key, Buffers, 9>;
+    BufferCache mBufferCache;
 
+    std::optional<Fps> mCurrentFps;
+    size_t mFrame = 0;
+
+    const FpsRange mFpsRange; // For color interpolation.
     const bool mShowSpinner;
 
-    // Interpolate the colors between these values.
-    const uint32_t mLowFps;
-    const uint32_t mHighFps;
-
-    sp<SurfaceControl> mSurfaceControl;
+    const sp<SurfaceControl> mSurfaceControl;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Features.h b/services/surfaceflinger/Scheduler/include/scheduler/Features.h
index 0e96678..b3a6a60 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Features.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Features.h
@@ -16,10 +16,10 @@
 
 #pragma once
 
-#include <ftl/Flags.h>
-
 #include <cstdint>
 
+#include <ftl/flags.h>
+
 namespace android::scheduler {
 
 enum class Feature : std::uint8_t {
@@ -29,6 +29,6 @@
     kTracePredictedVsync = 0b1000,
 };
 
-using FeatureFlags = Flags<Feature>;
+using FeatureFlags = ftl::Flags<Feature>;
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f326bfd..d5b7193 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -24,7 +24,10 @@
 
 #include "SurfaceFlinger.h"
 
+#include <android-base/parseint.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android/configuration.h>
 #include <android/gui/IDisplayEventConnection.h>
 #include <android/gui/StaticDisplayInfo.h>
@@ -50,6 +53,7 @@
 #include <configstore/Utils.h>
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
+#include <ftl/fake_guard.h>
 #include <ftl/future.h>
 #include <ftl/small_map.h>
 #include <gui/BufferQueue.h>
@@ -124,6 +128,7 @@
 #include "LayerRenderArea.h"
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
+#include "MutexUtils.h"
 #include "NativeWindowSurface.h"
 #include "RefreshRateOverlay.h"
 #include "RegionSamplingThread.h"
@@ -139,49 +144,26 @@
 #include "TimeStats/TimeStats.h"
 #include "TunnelModeEnabledReporter.h"
 #include "WindowInfosListenerInvoker.h"
-#include "android-base/parseint.h"
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
 
 #include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
 #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
 
-#define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
-
-// Note: The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
-#define ON_MAIN_THREAD(expr)                                       \
-    [&]() -> decltype(auto) {                                      \
-        LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
-        UnnecessaryLock lock(mStateLock);                          \
-        return (expr);                                             \
-    }()
-
-#define MAIN_THREAD_GUARD(expr)                                    \
-    [&]() -> decltype(auto) {                                      \
-        LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
-        MainThreadScopedGuard lock(SF_MAIN_THREAD);                \
-        return (expr);                                             \
-    }()
-
 #undef NO_THREAD_SAFETY_ANALYSIS
 #define NO_THREAD_SAFETY_ANALYSIS \
-    _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
-
-using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
-using aidl::android::hardware::graphics::composer3::Capability;
-using aidl::android::hardware::graphics::composer3::DisplayCapability;
-using KernelIdleTimerController =
-        ::android::scheduler::RefreshRateConfigs::KernelIdleTimerController;
+    _Pragma("GCC error \"Prefer <ftl/fake_guard.h> or MutexUtils.h helpers.\"")
 
 namespace android {
 
 using namespace std::string_literals;
 
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-using namespace android::sysprop;
+using namespace hardware::configstore;
+using namespace hardware::configstore::V1_0;
+using namespace sysprop;
 
-using android::hardware::power::Boost;
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
+using aidl::android::hardware::graphics::composer3::Capability;
+using aidl::android::hardware::graphics::composer3::DisplayCapability;
+
 using base::StringAppendF;
 using gui::DisplayInfo;
 using gui::IDisplayEventConnection;
@@ -192,6 +174,8 @@
 using ui::DisplayPrimaries;
 using ui::RenderIntent;
 
+using KernelIdleTimerController = scheduler::RefreshRateConfigs::KernelIdleTimerController;
+
 namespace hal = android::hardware::graphics::composer::hal;
 
 namespace {
@@ -223,38 +207,6 @@
 
 #pragma clang diagnostic pop
 
-template <typename Mutex>
-struct SCOPED_CAPABILITY ConditionalLockGuard {
-    ConditionalLockGuard(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) {
-        if (lock) mutex.lock();
-    }
-
-    ~ConditionalLockGuard() RELEASE() {
-        if (lock) mutex.unlock();
-    }
-
-    Mutex& mutex;
-    const bool lock;
-};
-
-using ConditionalLock = ConditionalLockGuard<Mutex>;
-
-struct SCOPED_CAPABILITY TimedLock {
-    TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex)
-          : mutex(mutex), status(mutex.timedLock(timeout)) {
-        ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status);
-    }
-
-    ~TimedLock() RELEASE() {
-        if (locked()) mutex.unlock();
-    }
-
-    bool locked() const { return status == NO_ERROR; }
-
-    Mutex& mutex;
-    const status_t status;
-};
-
 // TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
 constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
 
@@ -730,13 +682,15 @@
             if (renderEngineTid.has_value()) {
                 tidList.emplace_back(*renderEngineTid);
             }
-            mPowerAdvisor.startPowerHintSession(tidList);
+            if (!mPowerAdvisor.startPowerHintSession(tidList)) {
+                ALOGW("Cannot start power hint session");
+            }
         }
 
         mBootStage = BootStage::FINISHED;
 
         if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
-            ON_MAIN_THREAD(enableRefreshRateOverlay(true));
+            FTL_FAKE_GUARD(mStateLock, enableRefreshRateOverlay(true));
         }
     }));
 }
@@ -937,8 +891,9 @@
         FrameEvent::DEQUEUE_READY,
         FrameEvent::RELEASE,
     };
-    ConditionalLock _l(mStateLock,
-            std::this_thread::get_id() != mMainThreadId);
+
+    ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+
     if (!getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
         outSupported->push_back(FrameEvent::DISPLAY_PRESENT);
     }
@@ -1041,13 +996,8 @@
 
         outMode.resolution = ui::Size(width, height);
 
-        if (mEmulatedDisplayDensity) {
-            outMode.xDpi = mEmulatedDisplayDensity;
-            outMode.yDpi = mEmulatedDisplayDensity;
-        } else {
-            outMode.xDpi = xDpi;
-            outMode.yDpi = yDpi;
-        }
+        outMode.xDpi = xDpi;
+        outMode.yDpi = yDpi;
 
         const nsecs_t period = mode->getVsyncPeriod();
         outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue();
@@ -1143,7 +1093,7 @@
     }
 
     auto future = mScheduler->schedule([=]() -> status_t {
-        const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
+        const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
         if (!display) {
             ALOGE("Attempt to set allowed display modes for invalid display token %p",
                   displayToken.get());
@@ -1184,7 +1134,9 @@
         return;
     }
 
-    const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode());
+    const auto upcomingModeInfo =
+            FTL_FAKE_GUARD(kMainThreadContext, display->getUpcomingActiveMode());
+
     if (!upcomingModeInfo.mode) {
         // There is no pending mode change. This can happen if the active
         // display changed and the mode change happened on a different display.
@@ -1203,9 +1155,8 @@
         return;
     }
 
-    // We just created this display so we can call even if we are not on
-    // the main thread
-    MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+    // We just created this display so we can call even if we are not on the main thread.
+    ftl::FakeGuard guard(kMainThreadContext);
     display->setActiveMode(upcomingModeInfo.mode->getId());
 
     const Fps refreshRate = upcomingModeInfo.mode->getFps();
@@ -1290,8 +1241,10 @@
         constraints.seamlessRequired = false;
         hal::VsyncPeriodChangeTimeline outTimeline;
 
-        const auto status = MAIN_THREAD_GUARD(
-                display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline));
+        const auto status = FTL_FAKE_GUARD(kMainThreadContext,
+                                           display->initiateModeChange(*desiredActiveMode,
+                                                                       constraints, &outTimeline));
+
         if (status != NO_ERROR) {
             // initiateModeChange may fail if a hotplug event is just about
             // to be sent. We just log the error in this case.
@@ -1324,8 +1277,9 @@
 }
 
 void SurfaceFlinger::disableExpensiveRendering() {
-    auto future = mScheduler->schedule([=]() MAIN_THREAD {
-        ATRACE_CALL();
+    const char* const whence = __func__;
+    auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
+        ATRACE_NAME(whence);
         if (mPowerAdvisor.isUsingExpensiveRendering()) {
             for (const auto& [_, display] : mDisplays) {
                 constexpr bool kDisable = false;
@@ -1373,7 +1327,7 @@
         return BAD_VALUE;
     }
 
-    auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+    auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
         const auto display = getDisplayDeviceLocked(displayToken);
         if (!display) {
             ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
@@ -1408,17 +1362,17 @@
 }
 
 status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const {
-    auto future = mScheduler->schedule([=]() MAIN_THREAD mutable -> status_t {
-        *outSupport = getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG);
-        return NO_ERROR;
-    });
-    return future.get();
+    auto future = mScheduler->schedule(
+            [this] { return getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG); });
+
+    *outSupport = future.get();
+    return NO_ERROR;
 }
 
 status_t SurfaceFlinger::setBootDisplayMode(const sp<IBinder>& displayToken,
                                             ui::DisplayModeId modeId) {
     const char* const whence = __func__;
-    auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+    auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
         const auto display = getDisplayDeviceLocked(displayToken);
         if (!display) {
             ALOGE("%s: Invalid display token %p", whence, displayToken.get());
@@ -1445,7 +1399,7 @@
 
 status_t SurfaceFlinger::clearBootDisplayMode(const sp<IBinder>& displayToken) {
     const char* const whence = __func__;
-    auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+    auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
         if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
             return getHwComposer().clearBootDisplayMode(*displayId);
         } else {
@@ -1458,7 +1412,7 @@
 
 void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
     const char* const whence = __func__;
-    static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
+    static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
         if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
             getHwComposer().setAutoLowLatencyMode(*displayId, on);
         } else {
@@ -1469,7 +1423,7 @@
 
 void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) {
     const char* const whence = __func__;
-    static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
+    static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
         if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
             const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE;
             getHwComposer().setContentType(*displayId, type);
@@ -1534,7 +1488,7 @@
                                                           bool enable, uint8_t componentMask,
                                                           uint64_t maxFrames) {
     const char* const whence = __func__;
-    auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+    auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
         if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
             return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
                                                                     componentMask, maxFrames);
@@ -1608,10 +1562,10 @@
             : BAD_VALUE;
 }
 
-status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) {
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) {
     outLayers->clear();
     auto future = mScheduler->schedule([=] {
-        const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+        const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
         mDrawingState.traverseInZOrder([&](Layer* layer) {
             outLayers->push_back(layer->getLayerDebugInfo(display.get()));
         });
@@ -1723,7 +1677,7 @@
     }
 
     const char* const whence = __func__;
-    return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD {
+    return ftl::chain(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
                if (const auto display = getDisplayDeviceLocked(displayToken)) {
                    const bool supportsDisplayBrightnessCommand =
                            getHwComposer().getComposer()->isSupported(
@@ -1737,7 +1691,9 @@
                                compositionDisplay->editState().displayBrightnessNits;
                        compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits,
                                                                 brightness.displayBrightnessNits);
-                       MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness));
+                       FTL_FAKE_GUARD(kMainThreadContext,
+                                      display->stageBrightness(brightness.displayBrightness));
+
                        if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits !=
                            currentDimmingRatio) {
                            scheduleComposite(FrameHint::kNone);
@@ -1807,6 +1763,7 @@
 }
 
 status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) {
+    using hardware::power::Boost;
     Boost powerBoost = static_cast<Boost>(boostId);
 
     if (powerBoost == Boost::INTERACTION) {
@@ -1967,7 +1924,7 @@
     ATRACE_CALL();
 
     // On main thread to avoid race conditions with display power state.
-    static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
+    static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
         mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE;
 
         if (const auto display = getDefaultDisplayDeviceLocked();
@@ -2015,8 +1972,8 @@
                                                           : stats.vsyncTime + stats.vsyncPeriod;
 }
 
-bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) {
-    MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
+        FTL_FAKE_GUARD(kMainThreadContext) {
     // we set this once at the beginning of commit to ensure consistency throughout the whole frame
     mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession();
     if (mPowerHintSessionData.sessionEnabled) {
@@ -2182,20 +2139,21 @@
         mLayerTracing.notify(mVisibleRegionsDirty, frameTime);
     }
 
-    MAIN_THREAD_GUARD(persistDisplayBrightness(mustComposite));
+    persistDisplayBrightness(mustComposite);
 
     return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
 }
 
-void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) {
+void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId)
+        FTL_FAKE_GUARD(kMainThreadContext) {
     ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
-    MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+
     if (mPowerHintSessionData.sessionEnabled) {
         mPowerHintSessionData.compositeStart = systemTime();
     }
 
     compositionengine::CompositionRefreshArgs refreshArgs;
-    const auto& displays = ON_MAIN_THREAD(mDisplays);
+    const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
     refreshArgs.outputs.reserve(displays.size());
     for (const auto& [_, display] : displays) {
         refreshArgs.outputs.push_back(display->getCompositionDisplay());
@@ -2433,7 +2391,7 @@
     ATRACE_CALL();
     ALOGV("postComposition");
 
-    const auto* display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()).get();
+    const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
 
     getBE().mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
@@ -2633,44 +2591,37 @@
 }
 
 FloatRect SurfaceFlinger::getMaxDisplayBounds() {
-    // Find the largest width and height among all the displays.
-    int32_t maxDisplayWidth = 0;
-    int32_t maxDisplayHeight = 0;
+    const ui::Size maxSize = [this] {
+        ftl::FakeGuard guard(mStateLock);
 
-    // If there are no displays, set a valid display bounds so we can still compute a valid layer
-    // bounds.
-    if (ON_MAIN_THREAD(mDisplays.size()) == 0) {
-        maxDisplayWidth = maxDisplayHeight = 5000;
-    }
+        // The LayerTraceGenerator tool runs without displays.
+        if (mDisplays.empty()) return ui::Size{5000, 5000};
 
-    for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
-        const auto& displayDevice = pair.second;
-        int32_t width = displayDevice->getWidth();
-        int32_t height = displayDevice->getHeight();
-        if (width > maxDisplayWidth) {
-            maxDisplayWidth = width;
-        }
-        if (height > maxDisplayHeight) {
-            maxDisplayHeight = height;
-        }
-    }
+        return std::accumulate(mDisplays.begin(), mDisplays.end(), ui::kEmptySize,
+                               [](ui::Size size, const auto& pair) -> ui::Size {
+                                   const auto& display = pair.second;
+                                   return {std::max(size.getWidth(), display->getWidth()),
+                                           std::max(size.getHeight(), display->getHeight())};
+                               });
+    }();
 
     // Ignore display bounds for now since they will be computed later. Use a large Rect bound
     // to ensure it's bigger than an actual display will be.
-    FloatRect maxBounds = FloatRect(-maxDisplayWidth * 10, -maxDisplayHeight * 10,
-                                    maxDisplayWidth * 10, maxDisplayHeight * 10);
-    return maxBounds;
+    const float xMax = maxSize.getWidth() * 10.f;
+    const float yMax = maxSize.getHeight() * 10.f;
+
+    return {-xMax, -yMax, xMax, yMax};
 }
 
 void SurfaceFlinger::computeLayerBounds() {
-    FloatRect maxBounds = getMaxDisplayBounds();
+    const FloatRect maxBounds = getMaxDisplayBounds();
     for (const auto& layer : mDrawingState.layersSortedByZ) {
         layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */);
     }
 }
 
 void SurfaceFlinger::postFrame() {
-    const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+    const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
     if (display && getHwComposer().isConnected(display->getPhysicalId())) {
         uint32_t flipCount = display->getPageFlipCount();
         if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
@@ -2924,7 +2875,8 @@
                                                     RenderIntent::COLORIMETRIC,
                                                     Dataspace::UNKNOWN});
     if (!state.isVirtual()) {
-        MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId()));
+        FTL_FAKE_GUARD(kMainThreadContext,
+                       display->setActiveMode(state.physical->activeMode->getId()));
         display->setDeviceProductInfo(state.physical->deviceProductInfo);
     }
 
@@ -3294,7 +3246,7 @@
         return;
     }
 
-    for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+    for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
         if (const auto brightness = display->getStagedBrightness(); brightness) {
             if (!needsComposite) {
                 const status_t error =
@@ -3317,7 +3269,7 @@
                                       std::vector<DisplayInfo>& outDisplayInfos) {
     ftl::SmallMap<ui::LayerStack, DisplayDevice::InputInfo, 4> displayInputInfos;
 
-    for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+    for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
         const auto layerStack = display->getLayerStack();
         const auto info = display->getInputInfo();
 
@@ -3362,7 +3314,7 @@
 
 void SurfaceFlinger::updateCursorAsync() {
     compositionengine::CompositionRefreshArgs refreshArgs;
-    for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+    for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
         if (HalDisplayId::tryCast(display->getId())) {
             refreshArgs.outputs.push_back(display->getCompositionDisplay());
         }
@@ -3547,7 +3499,7 @@
 }
 
 void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
-    for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) {
+    for (const auto& [token, displayDevice] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
         auto display = displayDevice->getCompositionDisplay();
         if (display->includesLayer(layer->getOutputFilter())) {
             display->editState().dirtyRegion.orSelf(dirty);
@@ -4535,6 +4487,9 @@
     if (what & layer_state_t::eAutoRefreshChanged) {
         layer->setAutoRefresh(s.autoRefresh);
     }
+    if (what & layer_state_t::eDimmingEnabledChanged) {
+        if (layer->setDimmingEnabled(s.dimmingEnabled)) flags |= eTraversalNeeded;
+    }
     if (what & layer_state_t::eTrustedOverlayChanged) {
         if (layer->setTrustedOverlay(s.isTrustedOverlay)) {
             flags |= eTraversalNeeded;
@@ -4833,7 +4788,8 @@
 
 void SurfaceFlinger::initializeDisplays() {
     // Async since we may be called from the main thread.
-    static_cast<void>(mScheduler->schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
+    static_cast<void>(
+            mScheduler->schedule([this]() FTL_FAKE_GUARD(mStateLock) { onInitializeDisplays(); }));
 }
 
 void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
@@ -4933,7 +4889,7 @@
 }
 
 void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
-    auto future = mScheduler->schedule([=]() MAIN_THREAD {
+    auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
         const auto display = getDisplayDeviceLocked(displayToken);
         if (!display) {
             ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4980,7 +4936,7 @@
 
         bool dumpLayers = true;
         {
-            TimedLock lock(mStateLock, s2ns(1), __FUNCTION__);
+            TimedLock lock(mStateLock, s2ns(1), __func__);
             if (!lock.locked()) {
                 StringAppendF(&result, "Dumping without lock after timeout: %s (%d)\n",
                               strerror(-lock.status), lock.status);
@@ -5068,8 +5024,6 @@
     mFrameTimeline->parseArgs(args, result);
 }
 
-// This should only be called from the main thread.  Otherwise it would need
-// the lock and should use mCurrentState rather than mDrawingState.
 void SurfaceFlinger::logFrameStats() {
     mDrawingState.traverse([&](Layer* layer) {
         layer->logFrameStats();
@@ -5227,7 +5181,7 @@
 }
 
 void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const {
-    for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+    for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
         DisplayProto* displayProto = layersTraceProto.add_displays();
         displayProto->set_id(display->getId().value);
         displayProto->set_name(display->getDisplayName());
@@ -5506,25 +5460,14 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic error "-Wswitch-enum"
     switch (static_cast<ISurfaceComposerTag>(code)) {
-        case ENABLE_VSYNC_INJECTIONS:
-        case INJECT_VSYNC:
-            if (!hasMockHwc()) return PERMISSION_DENIED;
-            [[fallthrough]];
         // These methods should at minimum make sure that the client requested
         // access to SF.
         case BOOT_FINISHED:
-        case CLEAR_ANIMATION_FRAME_STATS:
-        case GET_ANIMATION_FRAME_STATS:
-        case OVERRIDE_HDR_TYPES:
         case GET_HDR_CAPABILITIES:
         case SET_DESIRED_DISPLAY_MODE_SPECS:
         case GET_DESIRED_DISPLAY_MODE_SPECS:
-        case SET_ACTIVE_COLOR_MODE:
-        case SET_BOOT_DISPLAY_MODE:
         case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
         case GET_GAME_CONTENT_TYPE_SUPPORT:
-        case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
-        case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
         case GET_DISPLAYED_CONTENT_SAMPLE:
         case ADD_TUNNEL_MODE_ENABLED_LISTENER:
         case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
@@ -5541,16 +5484,6 @@
             }
             return OK;
         }
-        case GET_LAYER_DEBUG_INFO: {
-            IPCThreadState* ipc = IPCThreadState::self();
-            const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
-            if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
-                ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
-                return PERMISSION_DENIED;
-            }
-            return OK;
-        }
         // Used by apps to hook Choreographer to SurfaceFlinger.
         case CREATE_DISPLAY_EVENT_CONNECTION:
         // The following calls are currently used by clients that do not
@@ -5560,17 +5493,11 @@
         case GET_ACTIVE_COLOR_MODE:
         case GET_ACTIVE_DISPLAY_MODE:
         case GET_DISPLAY_COLOR_MODES:
-        case GET_DISPLAY_NATIVE_PRIMARIES:
-        case GET_DYNAMIC_DISPLAY_INFO:
         case GET_DISPLAY_MODES:
-        case GET_SUPPORTED_FRAME_TIMESTAMPS:
         // Calling setTransactionState is safe, because you need to have been
         // granted a reference to Client* and Handle* to do anything with it.
         case SET_TRANSACTION_STATE:
         case CREATE_CONNECTION:
-        case GET_COLOR_MANAGEMENT:
-        case GET_COMPOSITION_PREFERENCE:
-        case GET_PROTECTED_CONTENT_SUPPORT:
         // setFrameRate() is deliberately available for apps to call without any
         // special permissions.
         case SET_FRAME_RATE:
@@ -5611,13 +5538,6 @@
             }
             return PERMISSION_DENIED;
         }
-        case ON_PULL_ATOM: {
-            const int uid = IPCThreadState::self()->getCallingUid();
-            if (uid == AID_SYSTEM) {
-                return OK;
-            }
-            return PERMISSION_DENIED;
-        }
         case ADD_WINDOW_INFOS_LISTENER:
         case REMOVE_WINDOW_INFOS_LISTENER: {
             const int uid = IPCThreadState::self()->getCallingUid();
@@ -5632,9 +5552,14 @@
         case GET_PHYSICAL_DISPLAY_IDS:
         case GET_PHYSICAL_DISPLAY_TOKEN:
         case SET_POWER_MODE:
+        case GET_SUPPORTED_FRAME_TIMESTAMPS:
         case GET_DISPLAY_STATE:
         case GET_DISPLAY_STATS:
         case GET_STATIC_DISPLAY_INFO:
+        case GET_DYNAMIC_DISPLAY_INFO:
+        case GET_DISPLAY_NATIVE_PRIMARIES:
+        case SET_ACTIVE_COLOR_MODE:
+        case SET_BOOT_DISPLAY_MODE:
         case CLEAR_BOOT_DISPLAY_MODE:
         case GET_BOOT_DISPLAY_MODE_SUPPORT:
         case SET_AUTO_LOW_LATENCY_MODE:
@@ -5642,6 +5567,18 @@
         case CAPTURE_LAYERS:
         case CAPTURE_DISPLAY:
         case CAPTURE_DISPLAY_BY_ID:
+        case CLEAR_ANIMATION_FRAME_STATS:
+        case GET_ANIMATION_FRAME_STATS:
+        case OVERRIDE_HDR_TYPES:
+        case ON_PULL_ATOM:
+        case ENABLE_VSYNC_INJECTIONS:
+        case INJECT_VSYNC:
+        case GET_LAYER_DEBUG_INFO:
+        case GET_COLOR_MANAGEMENT:
+        case GET_COMPOSITION_PREFERENCE:
+        case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
+        case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
+        case GET_PROTECTED_CONTENT_SUPPORT:
         case IS_WIDE_COLOR_DISPLAY:
         case GET_DISPLAY_BRIGHTNESS_SUPPORT:
         case SET_DISPLAY_BRIGHTNESS:
@@ -5858,7 +5795,7 @@
                         int64_t startingTime =
                                 (fixedStartingTime) ? fixedStartingTime : systemTime();
                         mScheduler
-                                ->schedule([&]() MAIN_THREAD {
+                                ->schedule([&]() FTL_FAKE_GUARD(mStateLock) {
                                     mLayerTracing.notify("start", startingTime);
                                 })
                                 .wait();
@@ -5971,10 +5908,12 @@
                     switch (n = data.readInt32()) {
                         case 0:
                         case 1:
-                            ON_MAIN_THREAD(enableRefreshRateOverlay(static_cast<bool>(n)));
+                            FTL_FAKE_GUARD(mStateLock,
+                                           enableRefreshRateOverlay(static_cast<bool>(n)));
                             break;
                         default: {
-                            reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled()));
+                            reply->writeBool(
+                                    FTL_FAKE_GUARD(mStateLock, isRefreshRateOverlayEnabled()));
                         }
                     }
                 });
@@ -6012,7 +5951,7 @@
                     return mScheduler
                             ->schedule([this] {
                                 const auto display =
-                                        ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+                                        FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
 
                                 // This is a little racy, but not in a way that hurts anything. As
                                 // we grab the defaultMode from the display manager policy, we could
@@ -6034,7 +5973,7 @@
                     return mScheduler
                             ->schedule([this] {
                                 const auto display =
-                                        ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+                                        FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
                                 constexpr bool kOverridePolicy = true;
                                 return setDesiredDisplayModeSpecsInternal(display, {},
                                                                           kOverridePolicy);
@@ -6150,7 +6089,7 @@
     // Update the overlay on the main thread to avoid race conditions with
     // mRefreshRateConfigs->getActiveMode()
     static_cast<void>(mScheduler->schedule([=] {
-        const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+        const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
         if (!display) {
             ALOGW("%s: default display is null", __func__);
             return;
@@ -6948,7 +6887,7 @@
     }
 
     auto future = mScheduler->schedule([=]() -> status_t {
-        const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
+        const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
         if (!display) {
             ALOGE("Attempt to set desired display modes for invalid display token %p",
                   displayToken.get());
@@ -7193,7 +7132,7 @@
     if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) {
         refreshRate = *frameRateOverride;
     } else if (!getHwComposer().isHeadless()) {
-        if (const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked())) {
+        if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) {
             refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
         }
     }
@@ -7413,6 +7352,18 @@
     return binder::Status::ok();
 }
 
+binder::Status SurfaceComposerAIDL::getSupportedFrameTimestamps(
+        std::vector<FrameEvent>* outSupported) {
+    status_t status;
+    if (!outSupported) {
+        status = UNEXPECTED_NULL;
+    } else {
+        outSupported->clear();
+        status = mFlinger->getSupportedFrameTimestamps(outSupported);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
 binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display,
                                                     gui::DisplayStatInfo* outStatInfo) {
     DisplayStatInfo statInfo;
@@ -7478,6 +7429,99 @@
     return binder::Status::fromStatusT(status);
 }
 
+binder::Status SurfaceComposerAIDL::getDynamicDisplayInfo(const sp<IBinder>& display,
+                                                          gui::DynamicDisplayInfo* outInfo) {
+    ui::DynamicDisplayInfo info;
+    status_t status = mFlinger->getDynamicDisplayInfo(display, &info);
+    if (status == NO_ERROR) {
+        // convert ui::DynamicDisplayInfo to gui::DynamicDisplayInfo
+        outInfo->supportedDisplayModes.clear();
+        outInfo->supportedDisplayModes.reserve(info.supportedDisplayModes.size());
+        for (const auto& mode : info.supportedDisplayModes) {
+            gui::DisplayMode outMode;
+            outMode.id = mode.id;
+            outMode.resolution.width = mode.resolution.width;
+            outMode.resolution.height = mode.resolution.height;
+            outMode.xDpi = mode.xDpi;
+            outMode.yDpi = mode.yDpi;
+            outMode.refreshRate = mode.refreshRate;
+            outMode.appVsyncOffset = mode.appVsyncOffset;
+            outMode.sfVsyncOffset = mode.sfVsyncOffset;
+            outMode.presentationDeadline = mode.presentationDeadline;
+            outMode.group = mode.group;
+            outInfo->supportedDisplayModes.push_back(outMode);
+        }
+
+        outInfo->activeDisplayModeId = info.activeDisplayModeId;
+
+        outInfo->supportedColorModes.clear();
+        outInfo->supportedColorModes.reserve(info.supportedColorModes.size());
+        for (const auto& cmode : info.supportedColorModes) {
+            outInfo->supportedColorModes.push_back(static_cast<int32_t>(cmode));
+        }
+
+        outInfo->activeColorMode = static_cast<int32_t>(info.activeColorMode);
+
+        gui::HdrCapabilities& hdrCapabilities = outInfo->hdrCapabilities;
+        hdrCapabilities.supportedHdrTypes.clear();
+        hdrCapabilities.supportedHdrTypes.reserve(
+                info.hdrCapabilities.getSupportedHdrTypes().size());
+        for (const auto& hdr : info.hdrCapabilities.getSupportedHdrTypes()) {
+            hdrCapabilities.supportedHdrTypes.push_back(static_cast<int32_t>(hdr));
+        }
+        hdrCapabilities.maxLuminance = info.hdrCapabilities.getDesiredMaxLuminance();
+        hdrCapabilities.maxAverageLuminance = info.hdrCapabilities.getDesiredMaxAverageLuminance();
+        hdrCapabilities.minLuminance = info.hdrCapabilities.getDesiredMinLuminance();
+
+        outInfo->autoLowLatencyModeSupported = info.autoLowLatencyModeSupported;
+        outInfo->gameContentTypeSupported = info.gameContentTypeSupported;
+        outInfo->preferredBootDisplayMode = info.preferredBootDisplayMode;
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayNativePrimaries(const sp<IBinder>& display,
+                                                              gui::DisplayPrimaries* outPrimaries) {
+    ui::DisplayPrimaries primaries;
+    status_t status = mFlinger->getDisplayNativePrimaries(display, primaries);
+    if (status == NO_ERROR) {
+        outPrimaries->red.X = primaries.red.X;
+        outPrimaries->red.Y = primaries.red.Y;
+        outPrimaries->red.Z = primaries.red.Z;
+
+        outPrimaries->green.X = primaries.green.X;
+        outPrimaries->green.Y = primaries.green.Y;
+        outPrimaries->green.Z = primaries.green.Z;
+
+        outPrimaries->blue.X = primaries.blue.X;
+        outPrimaries->blue.Y = primaries.blue.Y;
+        outPrimaries->blue.Z = primaries.blue.Z;
+
+        outPrimaries->white.X = primaries.white.X;
+        outPrimaries->white.Y = primaries.white.Y;
+        outPrimaries->white.Z = primaries.white.Z;
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setActiveColorMode(const sp<IBinder>& display, int colorMode) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->setActiveColorMode(display, static_cast<ui::ColorMode>(colorMode));
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setBootDisplayMode(const sp<IBinder>& display,
+                                                       int displayModeId) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->setBootDisplayMode(display,
+                                              static_cast<ui::DisplayModeId>(displayModeId));
+    }
+    return binder::Status::fromStatusT(status);
+}
+
 binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) {
     status_t status = checkAccessPermission();
     if (status == OK) {
@@ -7538,6 +7582,168 @@
     return binder::Status::fromStatusT(status);
 }
 
+binder::Status SurfaceComposerAIDL::clearAnimationFrameStats() {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->clearAnimationFrameStats();
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getAnimationFrameStats(gui::FrameStats* outStats) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binder::Status::fromStatusT(status);
+    }
+
+    FrameStats stats;
+    status = mFlinger->getAnimationFrameStats(&stats);
+    if (status == NO_ERROR) {
+        outStats->refreshPeriodNano = stats.refreshPeriodNano;
+        outStats->desiredPresentTimesNano.reserve(stats.desiredPresentTimesNano.size());
+        for (const auto& t : stats.desiredPresentTimesNano) {
+            outStats->desiredPresentTimesNano.push_back(t);
+        }
+        outStats->actualPresentTimesNano.reserve(stats.actualPresentTimesNano.size());
+        for (const auto& t : stats.actualPresentTimesNano) {
+            outStats->actualPresentTimesNano.push_back(t);
+        }
+        outStats->frameReadyTimesNano.reserve(stats.frameReadyTimesNano.size());
+        for (const auto& t : stats.frameReadyTimesNano) {
+            outStats->frameReadyTimesNano.push_back(t);
+        }
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::overrideHdrTypes(const sp<IBinder>& display,
+                                                     const std::vector<int32_t>& hdrTypes) {
+    // overrideHdrTypes is used by CTS tests, which acquire the necessary
+    // permission dynamically. Don't use the permission cache for this check.
+    status_t status = checkAccessPermission(false);
+    if (status != OK) {
+        return binder::Status::fromStatusT(status);
+    }
+
+    std::vector<ui::Hdr> hdrTypesVector;
+    for (int32_t i : hdrTypes) {
+        hdrTypesVector.push_back(static_cast<ui::Hdr>(i));
+    }
+    status = mFlinger->overrideHdrTypes(display, hdrTypesVector);
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) {
+    status_t status;
+    const int uid = IPCThreadState::self()->getCallingUid();
+    if (uid != AID_SYSTEM) {
+        status = PERMISSION_DENIED;
+    } else {
+        status = mFlinger->onPullAtom(atomId, &outPullData->data, &outPullData->success);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::enableVSyncInjections(bool enable) {
+    if (!mFlinger->hasMockHwc()) {
+        return binder::Status::fromStatusT(PERMISSION_DENIED);
+    }
+
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->enableVSyncInjections(enable);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::injectVSync(int64_t when) {
+    if (!mFlinger->hasMockHwc()) {
+        return binder::Status::fromStatusT(PERMISSION_DENIED);
+    }
+
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->injectVSync(when);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) {
+    if (!outLayers) {
+        return binder::Status::fromStatusT(UNEXPECTED_NULL);
+    }
+
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
+        ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid);
+        return binder::Status::fromStatusT(PERMISSION_DENIED);
+    }
+    status_t status = mFlinger->getLayerDebugInfo(outLayers);
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getColorManagement(bool* outGetColorManagement) {
+    status_t status = mFlinger->getColorManagement(outGetColorManagement);
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getCompositionPreference(gui::CompositionPreference* outPref) {
+    ui::Dataspace dataspace;
+    ui::PixelFormat pixelFormat;
+    ui::Dataspace wideColorGamutDataspace;
+    ui::PixelFormat wideColorGamutPixelFormat;
+    status_t status =
+            mFlinger->getCompositionPreference(&dataspace, &pixelFormat, &wideColorGamutDataspace,
+                                               &wideColorGamutPixelFormat);
+    if (status == NO_ERROR) {
+        outPref->defaultDataspace = static_cast<int32_t>(dataspace);
+        outPref->defaultPixelFormat = static_cast<int32_t>(pixelFormat);
+        outPref->wideColorGamutDataspace = static_cast<int32_t>(wideColorGamutDataspace);
+        outPref->wideColorGamutPixelFormat = static_cast<int32_t>(wideColorGamutPixelFormat);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getDisplayedContentSamplingAttributes(
+        const sp<IBinder>& display, gui::ContentSamplingAttributes* outAttrs) {
+    status_t status = checkAccessPermission();
+    if (status != OK) {
+        return binder::Status::fromStatusT(status);
+    }
+
+    ui::PixelFormat format;
+    ui::Dataspace dataspace;
+    uint8_t componentMask;
+    status = mFlinger->getDisplayedContentSamplingAttributes(display, &format, &dataspace,
+                                                             &componentMask);
+    if (status == NO_ERROR) {
+        outAttrs->format = static_cast<int32_t>(format);
+        outAttrs->dataspace = static_cast<int32_t>(dataspace);
+        outAttrs->componentMask = static_cast<int8_t>(componentMask);
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setDisplayContentSamplingEnabled(const sp<IBinder>& display,
+                                                                     bool enable,
+                                                                     int8_t componentMask,
+                                                                     int64_t maxFrames) {
+    status_t status = checkAccessPermission();
+    if (status == OK) {
+        status = mFlinger->setDisplayContentSamplingEnabled(display, enable,
+                                                            static_cast<uint8_t>(componentMask),
+                                                            static_cast<uint64_t>(maxFrames));
+    }
+    return binder::Status::fromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getProtectedContentSupport(bool* outSupported) {
+    status_t status = mFlinger->getProtectedContentSupport(outSupported);
+    return binder::Status::fromStatusT(status);
+}
+
 binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token,
                                                        bool* outIsWideColorDisplay) {
     status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bb0bc3f..b32462d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -32,6 +32,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/ITransactionCompletedListener.h>
+#include <gui/LayerDebugInfo.h>
 #include <gui/LayerState.h>
 #include <layerproto/LayerProtoHeader.h>
 #include <math/mat4.h>
@@ -65,6 +66,7 @@
 #include "Scheduler/Scheduler.h"
 #include "Scheduler/VsyncModulator.h"
 #include "SurfaceFlingerFactory.h"
+#include "ThreadContext.h"
 #include "TracedOrdinal.h"
 #include "Tracing/LayerTracing.h"
 #include "Tracing/TransactionTracing.h"
@@ -184,11 +186,6 @@
     std::atomic<nsecs_t> mLastSwapTime = 0;
 };
 
-struct SCOPED_CAPABILITY UnnecessaryLock {
-    explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {}
-    ~UnnecessaryLock() RELEASE() {}
-};
-
 class SurfaceFlinger : public BnSurfaceComposer,
                        public PriorityDumper,
                        private IBinder::DeathRecipient,
@@ -559,7 +556,7 @@
     void bootFinished() override;
     bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) const override;
-    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override;
+    virtual status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const;
     sp<IDisplayEventConnection> createDisplayEventConnection(
             ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
             ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override;
@@ -574,38 +571,36 @@
     status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*)
             EXCLUDES(mStateLock);
     status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*)
-            EXCLUDES(mStateLock) override;
-    status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
-                                       ui::DisplayPrimaries&) override;
-    status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
+            EXCLUDES(mStateLock);
+    status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken, ui::DisplayPrimaries&);
+    status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode);
     status_t getBootDisplayModeSupport(bool* outSupport) const;
-    status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override;
+    status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id);
     status_t clearBootDisplayMode(const sp<IBinder>& displayToken);
     void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
     void setGameContentType(const sp<IBinder>& displayToken, bool on);
     void setPowerMode(const sp<IBinder>& displayToken, int mode);
-    status_t clearAnimationFrameStats() override;
-    status_t getAnimationFrameStats(FrameStats* outStats) const override;
+    status_t clearAnimationFrameStats();
+    status_t getAnimationFrameStats(FrameStats* outStats) const;
     status_t overrideHdrTypes(const sp<IBinder>& displayToken,
-                              const std::vector<ui::Hdr>& hdrTypes) override;
-    status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) override;
-    status_t enableVSyncInjections(bool enable) override;
-    status_t injectVSync(nsecs_t when) override;
-    status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override;
-    status_t getColorManagement(bool* outGetColorManagement) const override;
+                              const std::vector<ui::Hdr>& hdrTypes);
+    status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success);
+    status_t enableVSyncInjections(bool enable);
+    status_t injectVSync(nsecs_t when);
+    status_t getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers);
+    status_t getColorManagement(bool* outGetColorManagement) const;
     status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
                                       ui::Dataspace* outWideColorGamutDataspace,
-                                      ui::PixelFormat* outWideColorGamutPixelFormat) const override;
+                                      ui::PixelFormat* outWideColorGamutPixelFormat) const;
     status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
                                                    ui::PixelFormat* outFormat,
                                                    ui::Dataspace* outDataspace,
-                                                   uint8_t* outComponentMask) const override;
+                                                   uint8_t* outComponentMask) const;
     status_t setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken, bool enable,
-                                              uint8_t componentMask, uint64_t maxFrames) override;
+                                              uint8_t componentMask, uint64_t maxFrames);
     status_t getDisplayedContentSample(const sp<IBinder>& displayToken, uint64_t maxFrames,
-                                       uint64_t timestamp,
-                                       DisplayedFrameStats* outStats) const override;
-    status_t getProtectedContentSupport(bool* outSupported) const override;
+                                       uint64_t timestamp, DisplayedFrameStats* outStats) const;
+    status_t getProtectedContentSupport(bool* outSupported) const;
     status_t isWideColorDisplay(const sp<IBinder>& displayToken, bool* outIsWideColorDisplay) const;
     status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
                                        const sp<IRegionSamplingListener>& listener) override;
@@ -752,7 +747,7 @@
     void updateLayerGeometry();
 
     void updateInputFlinger();
-    void persistDisplayBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
+    void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
     void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
                           std::vector<gui::DisplayInfo>& outDisplayInfos);
     void commitInputWindowCommands() REQUIRES(mStateLock);
@@ -985,7 +980,7 @@
     void setCompositorTimingSnapped(const DisplayStatInfo& stats,
                                     nsecs_t compositeToPresentLatency);
 
-    void postFrame();
+    void postFrame() REQUIRES(kMainThreadContext);
 
     /*
      * Display management
@@ -1100,7 +1095,7 @@
     void clearStatsLocked(const DumpArgs& args, std::string& result);
     void dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const;
     void dumpFrameTimeline(const DumpArgs& args, std::string& result) const;
-    void logFrameStats();
+    void logFrameStats() REQUIRES(kMainThreadContext);
 
     void dumpVSync(std::string& result) const REQUIRES(mStateLock);
     void dumpStaticScreenStats(std::string& result) const;
@@ -1443,7 +1438,7 @@
         nsecs_t commitStart;
         nsecs_t compositeStart;
         nsecs_t presentEnd;
-    } mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD);
+    } mPowerHintSessionData GUARDED_BY(kMainThreadContext);
 
     nsecs_t mAnimationTransactionTimeout = s2ns(5);
 
@@ -1461,12 +1456,19 @@
     binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override;
     binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
     binder::Status setPowerMode(const sp<IBinder>& display, int mode) override;
+    binder::Status getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) override;
     binder::Status getDisplayStats(const sp<IBinder>& display,
                                    gui::DisplayStatInfo* outStatInfo) override;
     binder::Status getDisplayState(const sp<IBinder>& display,
                                    gui::DisplayState* outState) override;
     binder::Status getStaticDisplayInfo(const sp<IBinder>& display,
                                         gui::StaticDisplayInfo* outInfo) override;
+    binder::Status getDynamicDisplayInfo(const sp<IBinder>& display,
+                                         gui::DynamicDisplayInfo* outInfo) override;
+    binder::Status getDisplayNativePrimaries(const sp<IBinder>& display,
+                                             gui::DisplayPrimaries* outPrimaries) override;
+    binder::Status setActiveColorMode(const sp<IBinder>& display, int colorMode) override;
+    binder::Status setBootDisplayMode(const sp<IBinder>& display, int displayModeId) override;
     binder::Status clearBootDisplayMode(const sp<IBinder>& display) override;
     binder::Status getBootDisplayModeSupport(bool* outMode) override;
     binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override;
@@ -1476,6 +1478,22 @@
     binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override;
     binder::Status captureLayers(const LayerCaptureArgs&,
                                  const sp<IScreenCaptureListener>&) override;
+    binder::Status clearAnimationFrameStats() override;
+    binder::Status getAnimationFrameStats(gui::FrameStats* outStats) override;
+    binder::Status overrideHdrTypes(const sp<IBinder>& display,
+                                    const std::vector<int32_t>& hdrTypes) override;
+    binder::Status onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) override;
+    binder::Status enableVSyncInjections(bool enable) override;
+    binder::Status injectVSync(int64_t when) override;
+    binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) override;
+    binder::Status getColorManagement(bool* outGetColorManagement) override;
+    binder::Status getCompositionPreference(gui::CompositionPreference* outPref) override;
+    binder::Status getDisplayedContentSamplingAttributes(
+            const sp<IBinder>& display, gui::ContentSamplingAttributes* outAttrs) override;
+    binder::Status setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                                    int8_t componentMask,
+                                                    int64_t maxFrames) override;
+    binder::Status getProtectedContentSupport(bool* outSupporte) override;
     binder::Status isWideColorDisplay(const sp<IBinder>& token,
                                       bool* outIsWideColorDisplay) override;
     binder::Status getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/services/surfaceflinger/ThreadContext.h
similarity index 65%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to services/surfaceflinger/ThreadContext.h
index d75777b..85c379d 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/services/surfaceflinger/ThreadContext.h
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-package android.gui;
+#pragma once
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
+namespace android {
 
-/** @hide */
-parcelable DisplayModelId {
-    int id;
-}
+// Enforces exclusive access by the main thread.
+constexpr class [[clang::capability("mutex")]] {
+} kMainThreadContext;
+
+} // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index a1374e5..e8ecf2f 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -430,7 +430,7 @@
                                                   bufferProto.height(), bufferProto.pixel_format(),
                                                   bufferProto.usage()));
         layer.bufferData->frameNumber = bufferProto.frame_number();
-        layer.bufferData->flags = Flags<BufferData::BufferDataChange>(bufferProto.flags());
+        layer.bufferData->flags = ftl::Flags<BufferData::BufferDataChange>(bufferProto.flags());
         layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id();
         layer.bufferData->acquireFence = Fence::NO_FENCE;
     }
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 1d0f62b..a80aca2 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -22,6 +22,7 @@
 #include <compositionengine/impl/CompositionEngine.h>
 #include <compositionengine/impl/Display.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <ftl/fake_guard.h>
 #include <gui/LayerDebugInfo.h>
 #include <gui/ScreenCaptureResults.h>
 #include <gui/SurfaceComposerClient.h>
@@ -50,6 +51,7 @@
 #include "SurfaceFlinger.h"
 #include "SurfaceFlingerDefaultFactory.h"
 #include "SurfaceInterceptor.h"
+#include "ThreadContext.h"
 #include "TimeStats/TimeStats.h"
 
 #include "renderengine/mock/RenderEngine.h"
@@ -445,7 +447,7 @@
         mFlinger->clearStatsLocked(dumpArgs, result);
 
         mFlinger->dumpTimeStats(dumpArgs, fdp->ConsumeBool(), result);
-        mFlinger->logFrameStats();
+        FTL_FAKE_GUARD(kMainThreadContext, mFlinger->logFrameStats());
 
         result = fdp->ConsumeRandomLengthString().c_str();
         mFlinger->dumpFrameTimeline(dumpArgs, result);
@@ -651,7 +653,7 @@
         updateCompositorTiming(&mFdp);
 
         mFlinger->setCompositorTimingSnapped({}, mFdp.ConsumeIntegral<nsecs_t>());
-        mFlinger->postFrame();
+        FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame());
         mFlinger->calculateExpectedPresentTime({});
 
         mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
index d70908e..4cd6ef8 100644
--- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp
+++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp
@@ -26,14 +26,14 @@
 namespace android {
 
 TEST(BootDisplayModeTest, setBootDisplayMode) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    sp<gui::ISurfaceComposer> sf_aidl(ComposerServiceAIDL::getComposerService());
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
     auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
     bool bootModeSupport = false;
-    binder::Status status = sf_aidl->getBootDisplayModeSupport(&bootModeSupport);
+    binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport);
     ASSERT_NO_FATAL_FAILURE(status.transactionError());
     if (bootModeSupport) {
-        ASSERT_EQ(NO_ERROR, sf->setBootDisplayMode(displayToken, 0));
+        status = sf->setBootDisplayMode(displayToken, 0);
+        ASSERT_EQ(NO_ERROR, status.transactionError());
     }
 }
 
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index d33bc10..6549a22 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -18,13 +18,13 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
 
+#include <android/gui/ISurfaceComposer.h>
 #include <gtest/gtest.h>
-#include <gui/ISurfaceComposer.h>
 #include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/android_filesystem_config.h>
-#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <ui/DisplayMode.h>
 #include <ui/DynamicDisplayInfo.h>
 #include <utils/String8.h>
@@ -34,6 +34,7 @@
 namespace android {
 
 using Transaction = SurfaceComposerClient::Transaction;
+using gui::LayerDebugInfo;
 using ui::ColorMode;
 
 namespace {
@@ -307,23 +308,26 @@
  */
 TEST_F(CredentialsTest, GetLayerDebugInfo) {
     setupBackgroundSurface();
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
 
     // Historically, only root and shell can access the getLayerDebugInfo which
     // is called when we call dumpsys. I don't see a reason why we should change this.
     std::vector<LayerDebugInfo> outLayers;
     // Check with root.
     seteuid(AID_ROOT);
-    ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers));
+    binder::Status status = sf->getLayerDebugInfo(&outLayers);
+    ASSERT_EQ(NO_ERROR, status.transactionError());
 
     // Check as a shell.
     seteuid(AID_SHELL);
-    ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers));
+    status = sf->getLayerDebugInfo(&outLayers);
+    ASSERT_EQ(NO_ERROR, status.transactionError());
 
     // Check as anyone else.
     seteuid(AID_ROOT);
     seteuid(AID_BIN);
-    ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers));
+    status = sf->getLayerDebugInfo(&outLayers);
+    ASSERT_EQ(PERMISSION_DENIED, status.transactionError());
 }
 
 TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 6bd7920..43386b2 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -26,6 +26,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <ui/DisplayMode.h>
 
 #include "BufferGenerator.h"
@@ -44,8 +45,9 @@
 
         ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
 
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
+        sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+        binder::Status status = sf->getColorManagement(&mColorManagementUsed);
+        ASSERT_NO_FATAL_FAILURE(status.transactionError());
 
         mCaptureArgs.displayToken = mDisplay;
     }
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 168b576..704815d 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -28,6 +28,7 @@
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
         "android.hardware.power@1.3",
+        "android.hardware.power-V2-cpp",
         "libbase",
         "libbinder",
         "libbinder_ndk",
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index b3b4ec1..12e5d46 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -43,6 +43,7 @@
 #include <hwbinder/ProcessState.h>
 #include <log/log.h>
 #include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
 #include <ui/DisplayMode.h>
 #include <ui/DynamicDisplayInfo.h>
 #include <utils/Looper.h>
@@ -992,7 +993,7 @@
 
 // Tests that VSYNC injection can be safely toggled while invalidating.
 TEST_F(DisplayTest_2_1, VsyncInjection) {
-    const auto flinger = ComposerService::getComposerService();
+    const auto flinger = ComposerServiceAIDL::getComposerService();
     bool enable = true;
 
     for (int i = 0; i < 100; i++) {
@@ -1238,9 +1239,10 @@
         sFakeComposer->clearFrames();
         ASSERT_EQ(0, sFakeComposer->getFrameCount());
 
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        std::vector<LayerDebugInfo> layers;
-        status_t result = sf->getLayerDebugInfo(&layers);
+        sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
+        std::vector<gui::LayerDebugInfo> layers;
+        binder::Status status = sf->getLayerDebugInfo(&layers);
+        status_t result = status.transactionError();
         if (result != NO_ERROR) {
             ALOGE("Failed to get layers %s %d", strerror(-result), result);
         } else {
diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
new file mode 100644
index 0000000..e25a0ae
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "AidlPowerHalWrapperTest"
+
+#include <android/hardware/power/IPower.h>
+#include <android/hardware/power/IPowerHintSession.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <algorithm>
+#include <chrono>
+#include <memory>
+#include "DisplayHardware/PowerAdvisor.h"
+#include "android/hardware/power/WorkDuration.h"
+#include "binder/Status.h"
+#include "log/log_main.h"
+#include "mock/DisplayHardware/MockIPower.h"
+#include "mock/DisplayHardware/MockIPowerHintSession.h"
+#include "utils/Timers.h"
+
+using namespace android;
+using namespace android::Hwc2::mock;
+using namespace android::hardware::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+namespace android::Hwc2::impl {
+
+class AidlPowerHalWrapperTest : public testing::Test {
+public:
+    void SetUp() override;
+
+protected:
+    std::unique_ptr<AidlPowerHalWrapper> mWrapper = nullptr;
+    sp<NiceMock<MockIPower>> mMockHal = nullptr;
+    sp<NiceMock<MockIPowerHintSession>> mMockSession = nullptr;
+    void verifyAndClearExpectations();
+    void sendActualWorkDurationGroup(std::vector<WorkDuration> durations,
+                                     std::chrono::nanoseconds sleepBeforeLastSend);
+};
+
+void AidlPowerHalWrapperTest::SetUp() {
+    mMockHal = new NiceMock<MockIPower>();
+    mMockSession = new NiceMock<MockIPowerHintSession>();
+    ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok()));
+    mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
+}
+
+void AidlPowerHalWrapperTest::verifyAndClearExpectations() {
+    Mock::VerifyAndClearExpectations(mMockHal.get());
+    Mock::VerifyAndClearExpectations(mMockSession.get());
+}
+
+void AidlPowerHalWrapperTest::sendActualWorkDurationGroup(
+        std::vector<WorkDuration> durations, std::chrono::nanoseconds sleepBeforeLastSend) {
+    for (size_t i = 0; i < durations.size(); i++) {
+        if (i == durations.size() - 1) {
+            std::this_thread::sleep_for(sleepBeforeLastSend);
+        }
+        auto duration = durations[i];
+        mWrapper->sendActualWorkDuration(duration.durationNanos, duration.timeStampNanos);
+    }
+}
+WorkDuration toWorkDuration(std::chrono::nanoseconds durationNanos, int64_t timeStampNanos) {
+    WorkDuration duration;
+    duration.durationNanos = durationNanos.count();
+    duration.timeStampNanos = timeStampNanos;
+    return duration;
+}
+
+namespace {
+TEST_F(AidlPowerHalWrapperTest, supportsPowerHintSession) {
+    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+    Mock::VerifyAndClearExpectations(mMockHal.get());
+    ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_))
+            .WillByDefault(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
+    auto newWrapper = AidlPowerHalWrapper(mMockHal);
+    EXPECT_FALSE(newWrapper.supportsPowerHintSession());
+}
+
+TEST_F(AidlPowerHalWrapperTest, startPowerHintSession) {
+    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+    std::vector<int32_t> threadIds = {1, 2};
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+    EXPECT_TRUE(mWrapper->startPowerHintSession());
+    EXPECT_FALSE(mWrapper->startPowerHintSession());
+}
+
+TEST_F(AidlPowerHalWrapperTest, restartNewPoserHintSessionWithNewThreadIds) {
+    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+    std::vector<int32_t> threadIds = {1, 2};
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds);
+    ASSERT_TRUE(mWrapper->startPowerHintSession());
+    verifyAndClearExpectations();
+
+    threadIds = {2, 3};
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+    EXPECT_CALL(*mMockSession.get(), close()).Times(1);
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds);
+    verifyAndClearExpectations();
+
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)).Times(0);
+    EXPECT_CALL(*mMockSession.get(), close()).Times(0);
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    verifyAndClearExpectations();
+}
+
+TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration) {
+    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+    std::vector<int32_t> threadIds = {1, 2};
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+    ASSERT_TRUE(mWrapper->startPowerHintSession());
+    verifyAndClearExpectations();
+
+    std::chrono::nanoseconds base = 100ms;
+    // test cases with target work duration and whether it should update hint against baseline 100ms
+    const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases = {{0ms, false},
+                                                                              {-1ms, false},
+                                                                              {200ms, true},
+                                                                              {2ms, true},
+                                                                              {96ms, false},
+                                                                              {104ms, false}};
+
+    for (const auto& test : testCases) {
+        // reset to 100ms baseline
+        mWrapper->setTargetWorkDuration(1);
+        mWrapper->setTargetWorkDuration(base.count());
+
+        auto target = test.first;
+        EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(target.count()))
+                .Times(test.second ? 1 : 0);
+        mWrapper->setTargetWorkDuration(target.count());
+        verifyAndClearExpectations();
+    }
+}
+
+TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration_shouldReconnectOnError) {
+    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+    std::vector<int32_t> threadIds = {1, 2};
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+    ASSERT_TRUE(mWrapper->startPowerHintSession());
+    verifyAndClearExpectations();
+
+    EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(1))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
+    mWrapper->setTargetWorkDuration(1);
+    EXPECT_TRUE(mWrapper->shouldReconnectHAL());
+}
+
+TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration) {
+    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+    std::vector<int32_t> threadIds = {1, 2};
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+    ASSERT_TRUE(mWrapper->startPowerHintSession());
+    verifyAndClearExpectations();
+
+    auto base = toWorkDuration(100ms, 0);
+    // test cases with actual work durations and whether it should update hint against baseline
+    // 100ms
+    const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
+            testCases = {{{{-1ms, 100}}, false},
+                         {{{91ms, 100}}, false},
+                         {{{109ms, 100}}, false},
+                         {{{100ms, 100}, {200ms, 200}}, true},
+                         {{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}};
+
+    for (const auto& test : testCases) {
+        // reset actual duration
+        sendActualWorkDurationGroup({base}, 80ms);
+
+        auto raw = test.first;
+        std::vector<WorkDuration> durations(raw.size());
+        std::transform(raw.begin(), raw.end(), durations.begin(),
+                       [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
+                           return toWorkDuration(d.first, d.second);
+                       });
+        EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
+                .Times(test.second ? 1 : 0);
+        sendActualWorkDurationGroup(durations, 0ms);
+        verifyAndClearExpectations();
+    }
+}
+
+TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
+    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+    std::vector<int32_t> threadIds = {1, 2};
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+    ASSERT_TRUE(mWrapper->startPowerHintSession());
+    verifyAndClearExpectations();
+
+    auto base = toWorkDuration(100ms, 0);
+    // test cases with actual work durations and whether it should update hint against baseline
+    // 100ms
+    const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
+            testCases = {{{{91ms, 100}}, true}, {{{109ms, 100}}, true}};
+
+    for (const auto& test : testCases) {
+        // reset actual duration
+        sendActualWorkDurationGroup({base}, 80ms);
+
+        auto raw = test.first;
+        std::vector<WorkDuration> durations(raw.size());
+        std::transform(raw.begin(), raw.end(), durations.begin(),
+                       [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
+                           return toWorkDuration(d.first, d.second);
+                       });
+        EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
+                .Times(test.second ? 1 : 0);
+        sendActualWorkDurationGroup(durations, 80ms);
+        verifyAndClearExpectations();
+    }
+}
+
+TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_shouldReconnectOnError) {
+    ASSERT_TRUE(mWrapper->supportsPowerHintSession());
+
+    std::vector<int32_t> threadIds = {1, 2};
+    mWrapper->setPowerHintSessionThreadIds(threadIds);
+    EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
+            .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
+    ASSERT_TRUE(mWrapper->startPowerHintSession());
+    verifyAndClearExpectations();
+    WorkDuration duration;
+    duration.durationNanos = 1;
+    EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
+            .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
+    sendActualWorkDurationGroup({duration}, 0ms);
+    EXPECT_TRUE(mWrapper->shouldReconnectHAL());
+}
+
+} // namespace
+} // namespace android::Hwc2::impl
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 1eea023..cc9d48c 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -26,6 +26,8 @@
     srcs: [
         "mock/DisplayHardware/MockComposer.cpp",
         "mock/DisplayHardware/MockHWC2.cpp",
+        "mock/DisplayHardware/MockIPower.cpp",
+        "mock/DisplayHardware/MockIPowerHintSession.cpp",
         "mock/DisplayHardware/MockPowerAdvisor.cpp",
         "mock/MockEventThread.cpp",
         "mock/MockFrameTimeline.cpp",
@@ -67,6 +69,7 @@
         ":libsurfaceflinger_mock_sources",
         ":libsurfaceflinger_sources",
         "libsurfaceflinger_unittest_main.cpp",
+        "AidlPowerHalWrapperTest.cpp",
         "CachingTest.cpp",
         "CompositionTest.cpp",
         "DispSyncSourceTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
index 73c60e1..225ad16 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
@@ -19,6 +19,7 @@
 
 #include "DisplayTransactionTestHelpers.h"
 
+#include <ftl/fake_guard.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -35,7 +36,7 @@
 };
 
 TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) {
-    MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+    ftl::FakeGuard guard(kMainThreadContext);
     sp<DisplayDevice> displayDevice = getDisplayDevice();
 
     EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
@@ -52,7 +53,7 @@
 }
 
 TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) {
-    MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+    ftl::FakeGuard guard(kMainThreadContext);
     sp<DisplayDevice> displayDevice = getDisplayDevice();
 
     EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
@@ -70,7 +71,7 @@
 }
 
 TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircuitsOnNoOp) {
-    MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+    ftl::FakeGuard guard(kMainThreadContext);
     sp<DisplayDevice> displayDevice = getDisplayDevice();
 
     EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 14d8f98..fa36d9c 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -34,12 +34,13 @@
 using namespace std::chrono_literals;
 using namespace std::placeholders;
 
-using namespace android::flag_operators;
 using testing::_;
 using testing::Invoke;
 
 namespace android {
 
+using namespace ftl::flag_operators;
+
 namespace {
 
 constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(111u);
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.cpp
similarity index 65%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.cpp
index d75777b..2323ebb 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.cpp
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-package android.gui;
+#include "mock/DisplayHardware/MockIPower.h"
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
+namespace android::Hwc2::mock {
 
-/** @hide */
-parcelable DisplayModelId {
-    int id;
-}
+// Explicit default instantiation is recommended.
+MockIPower::MockIPower() = default;
+
+} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
new file mode 100644
index 0000000..0ddc90d
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h
@@ -0,0 +1,50 @@
+/*
+ * 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
+
+#include "binder/Status.h"
+
+#include <android/hardware/power/IPower.h>
+#include <gmock/gmock.h>
+
+using android::binder::Status;
+using android::hardware::power::Boost;
+using android::hardware::power::IPower;
+using android::hardware::power::IPowerHintSession;
+using android::hardware::power::Mode;
+
+namespace android::Hwc2::mock {
+
+class MockIPower : public IPower {
+public:
+    MockIPower();
+
+    MOCK_METHOD(Status, isBoostSupported, (Boost boost, bool* ret), (override));
+    MOCK_METHOD(Status, setBoost, (Boost boost, int32_t durationMs), (override));
+    MOCK_METHOD(Status, isModeSupported, (Mode mode, bool* ret), (override));
+    MOCK_METHOD(Status, setMode, (Mode mode, bool enabled), (override));
+    MOCK_METHOD(Status, createHintSession,
+                (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
+                 int64_t durationNanos, sp<IPowerHintSession>* session),
+                (override));
+    MOCK_METHOD(Status, getHintSessionPreferredRate, (int64_t * rate), (override));
+    MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+    MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+} // namespace android::Hwc2::mock
diff --git a/libs/gui/aidl/android/gui/DisplayModelId.aidl b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.cpp
similarity index 65%
copy from libs/gui/aidl/android/gui/DisplayModelId.aidl
copy to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.cpp
index d75777b..770bc15 100644
--- a/libs/gui/aidl/android/gui/DisplayModelId.aidl
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.cpp
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-package android.gui;
+#include "mock/DisplayHardware/MockIPowerHintSession.h"
 
-// Product-specific information about the display or the directly connected device on the
-// display chain. For example, if the display is transitively connected, this field may contain
-// product information about the intermediate device.
+namespace android::Hwc2::mock {
 
-/** @hide */
-parcelable DisplayModelId {
-    int id;
-}
+// Explicit default instantiation is recommended.
+MockIPowerHintSession::MockIPowerHintSession() = default;
+
+} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h
new file mode 100644
index 0000000..439f6f4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h
@@ -0,0 +1,45 @@
+/*
+ * 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
+
+#include "binder/Status.h"
+
+#include <android/hardware/power/IPower.h>
+#include <gmock/gmock.h>
+
+using android::binder::Status;
+using android::hardware::power::IPowerHintSession;
+
+using namespace android::hardware::power;
+
+namespace android::Hwc2::mock {
+
+class MockIPowerHintSession : public IPowerHintSession {
+public:
+    MockIPowerHintSession();
+
+    MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+    MOCK_METHOD(Status, pause, (), (override));
+    MOCK_METHOD(Status, resume, (), (override));
+    MOCK_METHOD(Status, close, (), (override));
+    MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+    MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+    MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t), (override));
+    MOCK_METHOD(Status, reportActualWorkDuration, (const ::std::vector<WorkDuration>&), (override));
+};
+
+} // namespace android::Hwc2::mock