Merge "Add SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED to eventSizeBySensorType." into tm-dev
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 741b264..4e12579 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -118,6 +118,12 @@
 
 static std::atomic<bool> sAppDataIsolationEnabled(false);
 
+/**
+ * Flag to control if project ids are supported for internal storage
+ */
+static std::atomic<bool> sUsingProjectIdsFlag(false);
+static std::once_flag flag;
+
 namespace {
 
 constexpr const char* kDump = "android.permission.DUMP";
@@ -460,11 +466,14 @@
 }
 static bool internal_storage_has_project_id() {
     // The following path is populated in setFirstBoot, so if this file is present
-    // then project ids can be used.
-
-    auto using_project_ids =
-            StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
-    return access(using_project_ids.c_str(), F_OK) == 0;
+    // then project ids can be used. Using call once to cache the result of this check
+    // to avoid having to check the file presence again and again.
+    std::call_once(flag, []() {
+        auto using_project_ids =
+                StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+        sUsingProjectIdsFlag = access(using_project_ids.c_str(), F_OK) == 0;
+    });
+    return sUsingProjectIdsFlag;
 }
 
 static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
@@ -1167,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/ftl/Flags.h b/include/ftl/Flags.h
index 708eaf5..db3d9ea 100644
--- a/include/ftl/Flags.h
+++ b/include/ftl/Flags.h
@@ -19,13 +19,12 @@
 #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 and namespace.
 
 namespace android {
@@ -56,21 +55,22 @@
           : 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;
     };
 
     /*
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/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 a217a15..be50a75 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -569,6 +569,47 @@
     return mHasFds;
 }
 
+std::vector<sp<IBinder>> Parcel::debugReadAllStrongBinders() const {
+    std::vector<sp<IBinder>> ret;
+
+    size_t initPosition = dataPosition();
+    for (size_t i = 0; i < mObjectsSize; i++) {
+        binder_size_t offset = mObjects[i];
+        const flat_binder_object* flat =
+                reinterpret_cast<const flat_binder_object*>(mData + offset);
+        if (flat->hdr.type != BINDER_TYPE_BINDER) continue;
+
+        setDataPosition(offset);
+
+        sp<IBinder> binder = readStrongBinder();
+        if (binder != nullptr) ret.push_back(binder);
+    }
+
+    setDataPosition(initPosition);
+    return ret;
+}
+
+std::vector<int> Parcel::debugReadAllFileDescriptors() const {
+    std::vector<int> ret;
+
+    size_t initPosition = dataPosition();
+    for (size_t i = 0; i < mObjectsSize; i++) {
+        binder_size_t offset = mObjects[i];
+        const flat_binder_object* flat =
+                reinterpret_cast<const flat_binder_object*>(mData + offset);
+        if (flat->hdr.type != BINDER_TYPE_FD) continue;
+
+        setDataPosition(offset);
+
+        int fd = readFileDescriptor();
+        LOG_ALWAYS_FATAL_IF(fd == -1);
+        ret.push_back(fd);
+    }
+
+    setDataPosition(initPosition);
+    return ret;
+}
+
 status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool* result) const {
     if (len > INT32_MAX || offset > INT32_MAX) {
         // Don't accept size_t values which may have come from an inadvertent conversion from a
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 450e388..e2b2c51 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -95,6 +95,12 @@
     bool                hasFileDescriptors() const;
     status_t hasFileDescriptorsInRange(size_t offset, size_t length, bool* result) const;
 
+    // returns all binder objects in the Parcel
+    std::vector<sp<IBinder>> debugReadAllStrongBinders() const;
+    // returns all file descriptors in the Parcel
+    // does not dup
+    std::vector<int> debugReadAllFileDescriptors() const;
+
     // Zeros data when reallocating. Other mitigations may be added
     // in the future.
     //
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 42c85f9..88790a8 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -86,7 +86,7 @@
                 *ret = nullptr;
                 return android::BAD_VALUE;
             }
-            *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+            *ret = std::static_pointer_cast<T>(mParcelable);
             return android::OK;
         }
         this->mParcelPtr->setDataPosition(0);
@@ -105,7 +105,7 @@
             return status;
         }
         this->mParcelPtr = nullptr;
-        *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+        *ret = std::static_pointer_cast<T>(mParcelable);
         return android::OK;
     }
 
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/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index aee15d8..359c783 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -20,9 +20,12 @@
 #include <cutils/ashmem.h>
 #include <gtest/gtest.h>
 
+using android::BBinder;
+using android::IBinder;
 using android::IPCThreadState;
 using android::OK;
 using android::Parcel;
+using android::sp;
 using android::status_t;
 using android::String16;
 using android::String8;
@@ -75,6 +78,40 @@
     EXPECT_EQ(p.enforceNoDataAvail().exceptionCode(), Status::Exception::EX_NONE);
 }
 
+TEST(Parcel, DebugReadAllBinders) {
+    sp<IBinder> binder1 = sp<BBinder>::make();
+    sp<IBinder> binder2 = sp<BBinder>::make();
+
+    Parcel p;
+    p.writeInt32(4);
+    p.writeStrongBinder(binder1);
+    p.writeStrongBinder(nullptr);
+    p.writeInt32(4);
+    p.writeStrongBinder(binder2);
+    p.writeInt32(4);
+
+    auto ret = p.debugReadAllStrongBinders();
+
+    ASSERT_EQ(ret.size(), 2);
+    EXPECT_EQ(ret[0], binder1);
+    EXPECT_EQ(ret[1], binder2);
+}
+
+TEST(Parcel, DebugReadAllFds) {
+    Parcel p;
+    p.writeInt32(4);
+    p.writeFileDescriptor(STDOUT_FILENO, false /*takeOwnership*/);
+    p.writeInt32(4);
+    p.writeFileDescriptor(STDIN_FILENO, false /*takeOwnership*/);
+    p.writeInt32(4);
+
+    auto ret = p.debugReadAllFileDescriptors();
+
+    ASSERT_EQ(ret.size(), 2);
+    EXPECT_EQ(ret[0], STDOUT_FILENO);
+    EXPECT_EQ(ret[1], STDIN_FILENO);
+}
+
 // Tests a second operation results in a parcel at the same location as it
 // started.
 void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 13f7195..47ec776 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -109,6 +109,8 @@
     },
     PARCEL_READ_NO_STATUS(size_t, allowFds),
     PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
+    PARCEL_READ_NO_STATUS(std::vector<android::sp<android::IBinder>>, debugReadAllStrongBinders),
+    PARCEL_READ_NO_STATUS(std::vector<int>, debugReadAllFileDescriptors),
     [] (const ::android::Parcel& p, uint8_t len) {
         std::string interface(len, 'a');
         FUZZ_LOG() << "about to enforceInterface: " << interface;
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
index 0a083d7..843b6e3 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
@@ -16,12 +16,13 @@
 
 #pragma once
 
+#include <android-base/unique_fd.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
 namespace android {
 
-// ownership to callee, always valid or aborts
+// always valid or aborts
 // get a random FD for use in fuzzing, of a few different specific types
-int getRandomFd(FuzzedDataProvider* provider);
+base::unique_fd getRandomFd(FuzzedDataProvider* provider);
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 633626c..459fb12 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -20,8 +20,16 @@
 #include <fuzzer/FuzzedDataProvider.h>
 
 #include <functional>
+#include <vector>
 
 namespace android {
+
+struct RandomParcelOptions {
+    std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader;
+    std::vector<sp<IBinder>> extraBinders;
+    std::vector<base::unique_fd> extraFds;
+};
+
 /**
  * Fill parcel data, including some random binder objects and FDs
  *
@@ -30,7 +38,5 @@
  * writeHeader - optional function to write a specific header once the format of the parcel is
  *     picked (for instance, to write an interface header)
  */
-void fillRandomParcel(
-        Parcel* p, FuzzedDataProvider&& provider,
-        std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader = nullptr);
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, const RandomParcelOptions& = {});
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index be39bb9..d5aa353 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -20,24 +20,45 @@
 namespace android {
 
 void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) {
+    sp<IBinder> target;
+
+    RandomParcelOptions options{
+            .extraBinders = {binder},
+            .extraFds = {},
+    };
+
     while (provider.remaining_bytes() > 0) {
         uint32_t code = provider.ConsumeIntegral<uint32_t>();
         uint32_t flags = provider.ConsumeIntegral<uint32_t>();
         Parcel data;
 
+        sp<IBinder> target = options.extraBinders.at(
+                provider.ConsumeIntegralInRange<size_t>(0, options.extraBinders.size() - 1));
+        options.writeHeader = [&target](Parcel* p, FuzzedDataProvider& provider) {
+            // most code will be behind checks that the head of the Parcel
+            // is exactly this, so make it easier for fuzzers to reach this
+            if (provider.ConsumeBool()) {
+                p->writeInterfaceToken(target->getInterfaceDescriptor());
+            }
+        };
+
         std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>(
                 provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
-        fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()),
-                         [&binder](Parcel* p, FuzzedDataProvider& provider) {
-                             // most code will be behind checks that the head of the Parcel
-                             // is exactly this, so make it easier for fuzzers to reach this
-                             if (provider.ConsumeBool()) {
-                                 p->writeInterfaceToken(binder->getInterfaceDescriptor());
-                             }
-                         });
+        fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), options);
 
         Parcel reply;
-        (void)binder->transact(code, data, &reply, flags);
+        (void)target->transact(code, data, &reply, flags);
+
+        // feed back in binders and fds that are returned from the service, so that
+        // we can fuzz those binders, and use the fds and binders to feed back into
+        // the binders
+        auto retBinders = reply.debugReadAllStrongBinders();
+        options.extraBinders.insert(options.extraBinders.end(), retBinders.begin(),
+                                    retBinders.end());
+        auto retFds = reply.debugReadAllFileDescriptors();
+        for (size_t i = 0; i < retFds.size(); i++) {
+            options.extraFds.push_back(base::unique_fd(dup(retFds[i])));
+        }
     }
 }
 
diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
index cef6adb..ab0b7e3 100644
--- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
@@ -23,13 +23,13 @@
 
 namespace android {
 
-int getRandomFd(FuzzedDataProvider* provider) {
+base::unique_fd getRandomFd(FuzzedDataProvider* provider) {
     int fd = provider->PickValueInArray<std::function<int()>>({
             []() { return ashmem_create_region("binder test region", 1024); },
             []() { return open("/dev/null", O_RDWR); },
     })();
     CHECK(fd >= 0);
-    return fd;
+    return base::unique_fd(fd);
 }
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index cfabc1e..0204f5e 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -40,19 +40,23 @@
 }
 
 void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider,
-                      std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader) {
+                      const RandomParcelOptions& options) {
     if (provider.ConsumeBool()) {
         auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
         CHECK_EQ(OK, session->addNullDebuggingClient());
         p->markForRpc(session);
 
-        writeHeader(p, provider);
+        if (options.writeHeader) {
+            options.writeHeader(p, provider);
+        }
 
         fillRandomParcelData(p, std::move(provider));
         return;
     }
 
-    writeHeader(p, provider);
+    if (options.writeHeader) {
+        options.writeHeader(p, provider);
+    }
 
     while (provider.remaining_bytes() > 0) {
         auto fillFunc = provider.PickValueInArray<const std::function<void()>>({
@@ -65,8 +69,16 @@
                 },
                 // write FD
                 [&]() {
-                    int fd = getRandomFd(&provider);
-                    CHECK(OK == p->writeFileDescriptor(fd, true /*takeOwnership*/));
+                    if (options.extraFds.size() > 0 && provider.ConsumeBool()) {
+                        const base::unique_fd& fd = options.extraFds.at(
+                                provider.ConsumeIntegralInRange<size_t>(0,
+                                                                        options.extraFds.size() -
+                                                                                1));
+                        CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
+                    } else {
+                        base::unique_fd fd = getRandomFd(&provider);
+                        CHECK(OK == p->writeFileDescriptor(fd.release(), true /*takeOwnership*/));
+                    }
                 },
                 // write binder
                 [&]() {
@@ -85,7 +97,15 @@
                                 // candidate for checking usage of an actual BpBinder
                                 return IInterface::asBinder(defaultServiceManager());
                             },
-                            []() { return nullptr; },
+                            [&]() -> sp<IBinder> {
+                                if (options.extraBinders.size() > 0 && provider.ConsumeBool()) {
+                                    return options.extraBinders.at(
+                                            provider.ConsumeIntegralInRange<
+                                                    size_t>(0, options.extraBinders.size() - 1));
+                                } else {
+                                    return nullptr;
+                                }
+                            },
                     });
                     sp<IBinder> binder = makeFunc();
                     CHECK(OK == p->writeStrongBinder(binder));
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index bc2eb23..ef20196 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -18,6 +18,7 @@
         "cast_test.cpp",
         "concat_test.cpp",
         "enum_test.cpp",
+        "fake_guard_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/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 39d380d..dfdce20 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -197,4 +197,9 @@
     return gotVsync;
 }
 
+status_t DisplayEventDispatcher::getLatestVsyncEventData(
+        ParcelableVsyncEventData* outVsyncEventData) const {
+    return mReceiver.getLatestVsyncEventData(outVsyncEventData);
+}
+
 } // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 49b669e..34db5b1 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -774,7 +774,13 @@
 }; // namespace gui
 
 ReleaseCallbackId BufferData::generateReleaseCallbackId() const {
-    return {buffer->getId(), frameNumber};
+    uint64_t bufferId;
+    if (buffer) {
+        bufferId = buffer->getId();
+    } else {
+        bufferId = cachedBuffer.id;
+    }
+    return {bufferId, frameNumber};
 }
 
 status_t BufferData::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 063dda5..654fb33 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -70,6 +70,7 @@
     mLayerId = other->mLayerId;
     mWidth = other->mWidth;
     mHeight = other->mHeight;
+    mFormat = other->mFormat;
     mCreateFlags = other->mCreateFlags;
 }
 
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 71968fa..a342539 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -34,6 +34,7 @@
     void injectEvent(const DisplayEventReceiver::Event& event);
     int getFd() const;
     virtual int handleEvent(int receiveFd, int events, void* data);
+    status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const;
 
 protected:
     virtual ~DisplayEventDispatcher() = default;
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 1690e44..b72cf83 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -121,12 +121,12 @@
     mutable sp<Surface>         mSurfaceData;
     mutable sp<BLASTBufferQueue> mBbq;
     mutable sp<SurfaceControl> mBbqChild;
-    int32_t mLayerId;
-    uint32_t mTransformHint;
-    uint32_t mWidth;
-    uint32_t mHeight;
-    PixelFormat mFormat;
-    uint32_t mCreateFlags;
+    int32_t mLayerId = 0;
+    uint32_t mTransformHint = 0;
+    uint32_t mWidth = 0;
+    uint32_t mHeight = 0;
+    PixelFormat mFormat = PIXEL_FORMAT_NONE;
+    uint32_t mCreateFlags = 0;
     uint64_t mFallbackFrameNumber = 100;
 };
 
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index e69fc78..262987f 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -995,21 +995,6 @@
     EXPECT_EQ(surface->consumeEvent(100), nullptr);
 }
 
-TEST_F(InputSurfacesTest, layer_with_empty_crop_cannot_be_focused) {
-    std::unique_ptr<InputSurface> bufferSurface =
-            InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
-
-    bufferSurface->showAt(50, 50, Rect::EMPTY_RECT);
-
-    bufferSurface->requestFocus();
-    EXPECT_EQ(bufferSurface->consumeEvent(100), nullptr);
-
-    bufferSurface->showAt(50, 50, Rect::INVALID_RECT);
-
-    bufferSurface->requestFocus();
-    EXPECT_EQ(bufferSurface->consumeEvent(100), nullptr);
-}
-
 TEST_F(InputSurfacesTest, layer_with_valid_crop_can_be_focused) {
     std::unique_ptr<InputSurface> bufferSurface =
             InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index a6465ee..7f427f2 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -15,13 +15,6 @@
  */
 
 #define LOG_TAG "VelocityTracker"
-//#define LOG_NDEBUG 0
-
-// Log debug messages about velocity tracking.
-static constexpr bool DEBUG_VELOCITY = false;
-
-// Log debug messages about the progress of the algorithm itself.
-static constexpr bool DEBUG_STRATEGY = false;
 
 #include <array>
 #include <inttypes.h>
@@ -36,6 +29,27 @@
 
 namespace android {
 
+/**
+ * Log debug messages about velocity tracking.
+ * Enable this via "adb shell setprop log.tag.VelocityTrackerVelocity DEBUG" (requires restart)
+ */
+const bool DEBUG_VELOCITY =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Velocity", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about the progress of the algorithm itself.
+ * Enable this via "adb shell setprop log.tag.VelocityTrackerStrategy DEBUG" (requires restart)
+ */
+const bool DEBUG_STRATEGY =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Strategy", ANDROID_LOG_INFO);
+
+/**
+ * Log debug messages about the 'impulse' strategy.
+ * Enable this via "adb shell setprop log.tag.VelocityTrackerImpulse DEBUG" (requires restart)
+ */
+const bool DEBUG_IMPULSE =
+        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Impulse", ANDROID_LOG_INFO);
+
 // Nanoseconds per milliseconds.
 static const nsecs_t NANOS_PER_MS = 1000000;
 
@@ -141,7 +155,7 @@
             return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1);
 
         case VelocityTracker::Strategy::LSQ2:
-            if (DEBUG_STRATEGY) {
+            if (DEBUG_STRATEGY && !DEBUG_IMPULSE) {
                 ALOGI("Initializing lsq2 strategy");
             }
             return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2);
@@ -1172,7 +1186,25 @@
     outEstimator->degree = 2; // similar results to 2nd degree fit
     outEstimator->confidence = 1;
     if (DEBUG_STRATEGY) {
-        ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+        ALOGD("velocity: (%.1f, %.1f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+    }
+    if (DEBUG_IMPULSE) {
+        // TODO(b/134179997): delete this block once the switch to 'impulse' is complete.
+        // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons
+        VelocityTracker lsq2(VelocityTracker::Strategy::LSQ2);
+        BitSet32 idBits;
+        const uint32_t pointerId = 0;
+        idBits.markBit(pointerId);
+        for (ssize_t i = m - 1; i >= 0; i--) {
+            lsq2.addMovement(time[i], idBits, {{x[i], y[i]}});
+        }
+        float outVx = 0, outVy = 0;
+        const bool computed = lsq2.getVelocity(pointerId, &outVx, &outVy);
+        if (computed) {
+            ALOGD("lsq2 velocity: (%.1f, %.1f)", outVx, outVy);
+        } else {
+            ALOGD("lsq2 velocity: could not compute velocity");
+        }
     }
     return true;
 }
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 381900e..4a1784e 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 5e5618b..df9f8ab 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -39,6 +39,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>
@@ -872,18 +873,21 @@
             // save a snapshot of the activeSurface to use as input to the blur shaders
             blurInput = activeSurface->makeImageSnapshot();
 
-            // TODO we could skip this step if we know the blur will cover the entire image
-            //  blit the offscreen framebuffer into the destination AHB
-            SkPaint paint;
-            paint.setBlendMode(SkBlendMode::kSrc);
-            if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
-                uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
-                dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
-                                          String8::format("SurfaceID|%" PRId64, id).c_str(),
-                                          nullptr);
-                dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
-            } else {
-                activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+            // blit the offscreen framebuffer into the destination AHB, but only
+            // if there are blur regions. backgroundBlurRadius blurs the entire
+            // image below, so it can skip this step.
+            if (layer.blurRegions.size()) {
+                SkPaint paint;
+                paint.setBlendMode(SkBlendMode::kSrc);
+                if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+                    uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
+                    dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
+                                              String8::format("SurfaceID|%" PRId64, id).c_str(),
+                                              nullptr);
+                    dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
+                } else {
+                    activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+                }
             }
 
             // assign dstCanvas to canvas and ensure that the canvas state is up to date
@@ -1102,9 +1106,15 @@
                                                   .requiresLinearEffect = requiresLinearEffect,
                                                   .layerDimmingRatio = layerDimmingRatio}));
 
-            // 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/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 1a42642..c72ae1b 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -358,20 +358,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 +386,8 @@
                     }
 
                     sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
-                    if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2)) {
+                    if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) &&
+                        (sampleIncrementInBytes != 4)) {
                         unlock(bufferHandle);
                         return BAD_VALUE;
                     }
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3c164aa..8b81d48 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -2030,7 +2030,9 @@
     // Runtime permissions can't use the cache as they may change.
     if (sensor.isRequiredPermissionRuntime()) {
         hasPermission = checkPermission(String16(requiredPermission),
-                IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+                IPCThreadState::self()->getCallingPid(),
+                IPCThreadState::self()->getCallingUid(),
+                /*logPermissionFailure=*/ false);
     } else {
         hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission));
     }
@@ -2211,7 +2213,8 @@
     int targetSdk = getTargetSdkVersion(opPackageName);
     bool hasSamplingRatePermission = checkPermission(sAccessHighSensorSamplingRatePermission,
             IPCThreadState::self()->getCallingPid(),
-            IPCThreadState::self()->getCallingUid());
+            IPCThreadState::self()->getCallingUid(),
+            /*logPermissionFailure=*/ false);
     if (targetSdk < __ANDROID_API_S__ ||
             (targetSdk >= __ANDROID_API_S__ && hasSamplingRatePermission)) {
         return false;
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/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index cd03235..5cc0f97 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -165,7 +165,6 @@
         EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
         EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
-        EXPECT_CALL(mHwComposer, getBootDisplayModeSupport()).WillRepeatedly(Return(false));
     }
 
     DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() {
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/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 8b376f1..297a776 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -247,7 +247,6 @@
         case OptionalFeature::RefreshRateSwitching:
         case OptionalFeature::ExpectedPresentTime:
         case OptionalFeature::DisplayBrightnessCommand:
-        case OptionalFeature::BootDisplayConfig:
         case OptionalFeature::KernelIdleTimer:
         case OptionalFeature::PhysicalDisplayOrientation:
             return true;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 7d9946d..2dc0830 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -94,7 +94,6 @@
         ExpectedPresentTime,
         // Whether setDisplayBrightness is able to be applied as part of a display command.
         DisplayBrightnessCommand,
-        BootDisplayConfig,
         KernelIdleTimer,
         PhysicalDisplayOrientation,
     };
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index d78562d..a805566 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -94,82 +94,78 @@
     virtual bool hasDisplayIdleTimerCapability() const = 0;
     virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0;
 
-    [[clang::warn_unused_result]] virtual hal::Error acceptChanges() = 0;
-    [[clang::warn_unused_result]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>
+    [[nodiscard]] virtual hal::Error acceptChanges() = 0;
+    [[nodiscard]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>
     createLayer() = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getChangedCompositionTypes(
+    [[nodiscard]] virtual hal::Error getChangedCompositionTypes(
             std::unordered_map<Layer*, aidl::android::hardware::graphics::composer3::Composition>*
                     outTypes) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getColorModes(
-            std::vector<hal::ColorMode>* outModes) const = 0;
+    [[nodiscard]] virtual hal::Error getColorModes(std::vector<hal::ColorMode>* outModes) const = 0;
     // Returns a bitmask which contains HdrMetadata::Type::*.
-    [[clang::warn_unused_result]] virtual int32_t getSupportedPerFrameMetadata() const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getRenderIntents(
+    [[nodiscard]] virtual int32_t getSupportedPerFrameMetadata() const = 0;
+    [[nodiscard]] virtual hal::Error getRenderIntents(
             hal::ColorMode colorMode, std::vector<hal::RenderIntent>* outRenderIntents) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getDataspaceSaturationMatrix(
-            hal::Dataspace dataspace, android::mat4* outMatrix) = 0;
+    [[nodiscard]] virtual hal::Error getDataspaceSaturationMatrix(hal::Dataspace dataspace,
+                                                                  android::mat4* outMatrix) = 0;
 
-    [[clang::warn_unused_result]] virtual hal::Error getName(std::string* outName) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getRequests(
+    [[nodiscard]] virtual hal::Error getName(std::string* outName) const = 0;
+    [[nodiscard]] virtual hal::Error getRequests(
             hal::DisplayRequest* outDisplayRequests,
             std::unordered_map<Layer*, hal::LayerRequest>* outLayerRequests) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getConnectionType(
-            ui::DisplayConnectionType*) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error supportsDoze(bool* outSupport) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getHdrCapabilities(
+    [[nodiscard]] virtual hal::Error getConnectionType(ui::DisplayConnectionType*) const = 0;
+    [[nodiscard]] virtual hal::Error supportsDoze(bool* outSupport) const = 0;
+    [[nodiscard]] virtual hal::Error getHdrCapabilities(
             android::HdrCapabilities* outCapabilities) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getDisplayedContentSamplingAttributes(
+    [[nodiscard]] virtual hal::Error getDisplayedContentSamplingAttributes(
             hal::PixelFormat* outFormat, hal::Dataspace* outDataspace,
             uint8_t* outComponentMask) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setDisplayContentSamplingEnabled(
-            bool enabled, uint8_t componentMask, uint64_t maxFrames) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getDisplayedContentSample(
+    [[nodiscard]] virtual hal::Error setDisplayContentSamplingEnabled(bool enabled,
+                                                                      uint8_t componentMask,
+                                                                      uint64_t maxFrames) const = 0;
+    [[nodiscard]] virtual hal::Error getDisplayedContentSample(
             uint64_t maxFrames, uint64_t timestamp,
             android::DisplayedFrameStats* outStats) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getReleaseFences(
+    [[nodiscard]] virtual hal::Error getReleaseFences(
             std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error present(
-            android::sp<android::Fence>* outPresentFence) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setClientTarget(
+    [[nodiscard]] virtual hal::Error present(android::sp<android::Fence>* outPresentFence) = 0;
+    [[nodiscard]] virtual hal::Error setClientTarget(
             uint32_t slot, const android::sp<android::GraphicBuffer>& target,
             const android::sp<android::Fence>& acquireFence, hal::Dataspace dataspace) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setColorMode(
-            hal::ColorMode mode, hal::RenderIntent renderIntent) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setColorTransform(
-            const android::mat4& matrix) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setOutputBuffer(
+    [[nodiscard]] virtual hal::Error setColorMode(hal::ColorMode mode,
+                                                  hal::RenderIntent renderIntent) = 0;
+    [[nodiscard]] virtual hal::Error setColorTransform(const android::mat4& matrix) = 0;
+    [[nodiscard]] virtual hal::Error setOutputBuffer(
             const android::sp<android::GraphicBuffer>& buffer,
             const android::sp<android::Fence>& releaseFence) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setPowerMode(hal::PowerMode mode) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setVsyncEnabled(hal::Vsync enabled) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error validate(nsecs_t expectedPresentTime,
-                                                              uint32_t* outNumTypes,
-                                                              uint32_t* outNumRequests) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error presentOrValidate(
-            nsecs_t expectedPresentTime, uint32_t* outNumTypes, uint32_t* outNumRequests,
-            android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0;
-    [[clang::warn_unused_result]] virtual std::future<hal::Error> setDisplayBrightness(
+    [[nodiscard]] virtual hal::Error setPowerMode(hal::PowerMode mode) = 0;
+    [[nodiscard]] virtual hal::Error setVsyncEnabled(hal::Vsync enabled) = 0;
+    [[nodiscard]] virtual hal::Error validate(nsecs_t expectedPresentTime, uint32_t* outNumTypes,
+                                              uint32_t* outNumRequests) = 0;
+    [[nodiscard]] virtual hal::Error presentOrValidate(nsecs_t expectedPresentTime,
+                                                       uint32_t* outNumTypes,
+                                                       uint32_t* outNumRequests,
+                                                       android::sp<android::Fence>* outPresentFence,
+                                                       uint32_t* state) = 0;
+    [[nodiscard]] virtual std::future<hal::Error> setDisplayBrightness(
             float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints(
+    [[nodiscard]] virtual hal::Error setActiveConfigWithConstraints(
             hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints,
             hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setBootDisplayConfig(
-            hal::HWConfigId configId) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error clearBootDisplayConfig() = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getPreferredBootDisplayConfig(
+    [[nodiscard]] virtual hal::Error setBootDisplayConfig(hal::HWConfigId configId) = 0;
+    [[nodiscard]] virtual hal::Error clearBootDisplayConfig() = 0;
+    [[nodiscard]] virtual hal::Error getPreferredBootDisplayConfig(
             hal::HWConfigId* configId) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setAutoLowLatencyMode(bool on) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getSupportedContentTypes(
+    [[nodiscard]] virtual hal::Error setAutoLowLatencyMode(bool on) = 0;
+    [[nodiscard]] virtual hal::Error getSupportedContentTypes(
             std::vector<hal::ContentType>*) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getClientTargetProperty(
+    [[nodiscard]] virtual hal::Error setContentType(hal::ContentType) = 0;
+    [[nodiscard]] virtual hal::Error getClientTargetProperty(
             hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getDisplayDecorationSupport(
+    [[nodiscard]] virtual hal::Error getDisplayDecorationSupport(
             std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
                     support) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setIdleTimerEnabled(
-            std::chrono::milliseconds timeout) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getPhysicalDisplayOrientation(
+    [[nodiscard]] virtual hal::Error setIdleTimerEnabled(std::chrono::milliseconds timeout) = 0;
+    [[nodiscard]] virtual hal::Error getPhysicalDisplayOrientation(
             Hwc2::AidlTransform* outTransform) const = 0;
 };
 
@@ -299,45 +295,39 @@
 
     virtual hal::HWLayerId getId() const = 0;
 
-    [[clang::warn_unused_result]] virtual hal::Error setCursorPosition(int32_t x, int32_t y) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setBuffer(
-            uint32_t slot, const android::sp<android::GraphicBuffer>& buffer,
-            const android::sp<android::Fence>& acquireFence) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setSurfaceDamage(
-            const android::Region& damage) = 0;
+    [[nodiscard]] virtual hal::Error setCursorPosition(int32_t x, int32_t y) = 0;
+    [[nodiscard]] virtual hal::Error setBuffer(uint32_t slot,
+                                               const android::sp<android::GraphicBuffer>& buffer,
+                                               const android::sp<android::Fence>& acquireFence) = 0;
+    [[nodiscard]] virtual hal::Error setSurfaceDamage(const android::Region& damage) = 0;
 
-    [[clang::warn_unused_result]] virtual hal::Error setBlendMode(hal::BlendMode mode) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setColor(
+    [[nodiscard]] virtual hal::Error setBlendMode(hal::BlendMode mode) = 0;
+    [[nodiscard]] virtual hal::Error setColor(
             aidl::android::hardware::graphics::composer3::Color color) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setCompositionType(
+    [[nodiscard]] virtual hal::Error setCompositionType(
             aidl::android::hardware::graphics::composer3::Composition type) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setDataspace(hal::Dataspace dataspace) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setPerFrameMetadata(
-            const int32_t supportedPerFrameMetadata, const android::HdrMetadata& metadata) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setDisplayFrame(
-            const android::Rect& frame) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setPlaneAlpha(float alpha) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setSidebandStream(
-            const native_handle_t* stream) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setSourceCrop(
-            const android::FloatRect& crop) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setTransform(hal::Transform transform) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setVisibleRegion(
-            const android::Region& region) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setZOrder(uint32_t z) = 0;
+    [[nodiscard]] virtual hal::Error setDataspace(hal::Dataspace dataspace) = 0;
+    [[nodiscard]] virtual hal::Error setPerFrameMetadata(const int32_t supportedPerFrameMetadata,
+                                                         const android::HdrMetadata& metadata) = 0;
+    [[nodiscard]] virtual hal::Error setDisplayFrame(const android::Rect& frame) = 0;
+    [[nodiscard]] virtual hal::Error setPlaneAlpha(float alpha) = 0;
+    [[nodiscard]] virtual hal::Error setSidebandStream(const native_handle_t* stream) = 0;
+    [[nodiscard]] virtual hal::Error setSourceCrop(const android::FloatRect& crop) = 0;
+    [[nodiscard]] virtual hal::Error setTransform(hal::Transform transform) = 0;
+    [[nodiscard]] virtual hal::Error setVisibleRegion(const android::Region& region) = 0;
+    [[nodiscard]] virtual hal::Error setZOrder(uint32_t z) = 0;
 
     // Composer HAL 2.3
-    [[clang::warn_unused_result]] virtual hal::Error setColorTransform(
-            const android::mat4& matrix) = 0;
+    [[nodiscard]] virtual hal::Error setColorTransform(const android::mat4& matrix) = 0;
 
     // Composer HAL 2.4
-    [[clang::warn_unused_result]] virtual hal::Error setLayerGenericMetadata(
-            const std::string& name, bool mandatory, const std::vector<uint8_t>& value) = 0;
+    [[nodiscard]] virtual hal::Error setLayerGenericMetadata(const std::string& name,
+                                                             bool mandatory,
+                                                             const std::vector<uint8_t>& value) = 0;
 
     // AIDL HAL
-    [[clang::warn_unused_result]] virtual hal::Error setBrightness(float brightness) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setBlockingRegion(
-            const android::Region& region) = 0;
+    [[nodiscard]] virtual hal::Error setBrightness(float brightness) = 0;
+    [[nodiscard]] virtual hal::Error setBlockingRegion(const android::Region& region) = 0;
 };
 
 namespace impl {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index e2e4a99..459291a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -740,10 +740,6 @@
             });
 }
 
-bool HWComposer::getBootDisplayModeSupport() {
-    return mComposer->isSupported(Hwc2::Composer::OptionalFeature::BootDisplayConfig);
-}
-
 status_t HWComposer::setBootDisplayMode(PhysicalDisplayId displayId,
                                         hal::HWConfigId displayModeId) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 91fe1b7..0e15a7c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -267,7 +267,6 @@
     virtual std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const = 0;
 
     // Composer 3.0
-    virtual bool getBootDisplayModeSupport() = 0;
     virtual status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) = 0;
     virtual status_t clearBootDisplayMode(PhysicalDisplayId) = 0;
     virtual std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) = 0;
@@ -406,7 +405,6 @@
     const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata() const override;
 
     // Composer 3.0
-    bool getBootDisplayModeSupport() override;
     status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) override;
     status_t clearBootDisplayMode(PhysicalDisplayId) override;
     std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) override;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index e8dc084..d9af553 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -235,7 +235,6 @@
             return mClient_2_4 != nullptr;
         case OptionalFeature::ExpectedPresentTime:
         case OptionalFeature::DisplayBrightnessCommand:
-        case OptionalFeature::BootDisplayConfig:
         case OptionalFeature::KernelIdleTimer:
         case OptionalFeature::PhysicalDisplayOrientation:
             return false;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 3dab389..44c086d 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -542,7 +542,7 @@
     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
+    // 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;
 };
@@ -551,7 +551,7 @@
         base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
 
 const bool AidlPowerHalWrapper::sNormalizeTarget =
-        base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), true);
+        base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), false);
 
 PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
     static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ac7bcde..894fb8d 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>
@@ -833,6 +834,14 @@
         return false;
     }
 
+    if (CC_UNLIKELY(relative->usingRelativeZ(LayerVector::StateSet::Drawing)) &&
+        (relative->mDrawingState.zOrderRelativeOf == this)) {
+        ALOGE("Detected relative layer loop between %s and %s",
+              mName.c_str(), relative->mName.c_str());
+        ALOGE("Ignoring new call to set relative layer");
+        return false;
+    }
+
     mFlinger->mSomeChildrenChanged = true;
 
     mDrawingState.sequence++;
@@ -1990,6 +1999,18 @@
     }
 }
 
+bool Layer::findInHierarchy(const sp<Layer>& l) {
+    if (l == this) {
+        return true;
+    }
+    for (auto& child : mDrawingChildren) {
+      if (child->findInHierarchy(l)) {
+          return true;
+      }
+    }
+    return false;
+}
+
 void Layer::commitChildList() {
     for (size_t i = 0; i < mCurrentChildren.size(); i++) {
         const auto& child = mCurrentChildren[i];
@@ -1997,6 +2018,17 @@
     }
     mDrawingChildren = mCurrentChildren;
     mDrawingParent = mCurrentParent;
+    if (CC_UNLIKELY(usingRelativeZ(LayerVector::StateSet::Drawing))) {
+        auto zOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
+        if (zOrderRelativeOf == nullptr) return;
+        if (findInHierarchy(zOrderRelativeOf)) {
+            ALOGE("Detected Z ordering loop between %s and %s", mName.c_str(),
+                  zOrderRelativeOf->mName.c_str());
+            ALOGE("Severing rel Z loop, potentially dangerous");
+            mDrawingState.isRelativeOf = false;
+            zOrderRelativeOf->removeZOrderRelative(this);
+        }
+    }
 }
 
 
@@ -2014,10 +2046,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()),
@@ -2177,7 +2209,6 @@
 void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
     Rect tmpBounds = getInputBounds();
     if (!tmpBounds.isValid()) {
-        info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true);
         info.touchableRegion.clear();
         // A layer could have invalid input bounds and still expect to receive touch input if it has
         // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 48a9bc5..846460d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -1138,6 +1138,7 @@
     bool mIsAtRoot = false;
 
     uint32_t mLayerCreationFlags;
+    bool findInHierarchy(const sp<Layer>&);
 };
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate);
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/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 74d7739..3aa0a5f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -726,10 +726,6 @@
 }
 
 void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
-    if (timeline.refreshRequired) {
-        mSchedulerCallback.scheduleComposite(FrameHint::kNone);
-    }
-
     std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
     mLastVsyncPeriodChangeTimeline = std::make_optional(timeline);
 
@@ -739,23 +735,17 @@
     }
 }
 
-void Scheduler::onPostComposition(nsecs_t presentTime) {
-    const bool recomposite = [=] {
-        std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
-        if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
-            if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
-                // We need to composite again as refreshTimeNanos is still in the future.
-                return true;
-            }
-
-            mLastVsyncPeriodChangeTimeline->refreshRequired = false;
+bool Scheduler::onPostComposition(nsecs_t presentTime) {
+    std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
+    if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
+        if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
+            // We need to composite again as refreshTimeNanos is still in the future.
+            return true;
         }
-        return false;
-    }();
 
-    if (recomposite) {
-        mSchedulerCallback.scheduleComposite(FrameHint::kNone);
+        mLastVsyncPeriodChangeTimeline->refreshRequired = false;
     }
+    return false;
 }
 
 void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index a8113d4..0c72124 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -83,12 +83,8 @@
 namespace scheduler {
 
 struct ISchedulerCallback {
-    // Indicates frame activity, i.e. whether commit and/or composite is taking place.
-    enum class FrameHint { kNone, kActive };
-
     using DisplayModeEvent = scheduler::DisplayModeEvent;
 
-    virtual void scheduleComposite(FrameHint) = 0;
     virtual void setVsyncEnabled(bool) = 0;
     virtual void requestDisplayMode(DisplayModePtr, DisplayModeEvent) = 0;
     virtual void kernelTimerChanged(bool expired) = 0;
@@ -210,8 +206,8 @@
     // Notifies the scheduler about a refresh rate timeline change.
     void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
 
-    // Notifies the scheduler post composition.
-    void onPostComposition(nsecs_t presentTime);
+    // Notifies the scheduler post composition. Returns if recomposite is needed.
+    bool onPostComposition(nsecs_t presentTime);
 
     // Notifies the scheduler when the display size has changed. Called from SF's main thread
     void onActiveDisplayAreaChanged(uint32_t displayArea);
@@ -245,8 +241,6 @@
 private:
     friend class TestableScheduler;
 
-    using FrameHint = ISchedulerCallback::FrameHint;
-
     enum class ContentDetectionState { Off, On };
     enum class TimerState { Reset, Expired };
     enum class TouchState { Inactive, Active };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2edc05b..4fc9d27 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/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
@@ -49,6 +52,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>
@@ -123,6 +127,7 @@
 #include "LayerRenderArea.h"
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
+#include "MutexUtils.h"
 #include "NativeWindowSurface.h"
 #include "RefreshRateOverlay.h"
 #include "RegionSamplingThread.h"
@@ -138,49 +143,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;
@@ -191,6 +173,8 @@
 using ui::DisplayPrimaries;
 using ui::RenderIntent;
 
+using KernelIdleTimerController = scheduler::RefreshRateConfigs::KernelIdleTimerController;
+
 namespace hal = android::hardware::graphics::composer::hal;
 
 namespace {
@@ -222,38 +206,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;
 
@@ -690,10 +642,9 @@
     const nsecs_t duration = now - mBootTime;
     ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
 
-    mFlagManager = std::make_unique<android::FlagManager>();
     mFrameTracer->initialize();
     mFrameTimeline->onBootFinished();
-    getRenderEngine().setEnableTracing(mFlagManager->use_skia_tracing());
+    getRenderEngine().setEnableTracing(mFlagManager.use_skia_tracing());
 
     // wait patiently for the window manager death
     const String16 name("window");
@@ -721,22 +672,22 @@
         }
 
         readPersistentProperties();
-        std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
-        std::vector<int32_t> tidList;
-        tidList.emplace_back(gettid());
-        if (renderEngineTid.has_value()) {
-            tidList.emplace_back(*renderEngineTid);
-        }
         mPowerAdvisor.onBootFinished();
-        mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint());
+        mPowerAdvisor.enablePowerHint(mFlagManager.use_adpf_cpu_hint());
         if (mPowerAdvisor.usePowerHintSession()) {
+            std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
+            std::vector<int32_t> tidList;
+            tidList.emplace_back(gettid());
+            if (renderEngineTid.has_value()) {
+                tidList.emplace_back(*renderEngineTid);
+            }
             mPowerAdvisor.startPowerHintSession(tidList);
         }
 
         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 +888,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);
     }
@@ -1086,7 +1038,8 @@
             getHwComposer().supportsContentType(*displayId, hal::ContentType::GAME);
 
     info->preferredBootDisplayMode = static_cast<ui::DisplayModeId>(-1);
-    if (getHwComposer().getBootDisplayModeSupport()) {
+
+    if (getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
         if (const auto hwcId = getHwComposer().getPreferredBootDisplayMode(*displayId)) {
             if (const auto modeId = display->translateModeId(*hwcId)) {
                 info->preferredBootDisplayMode = modeId->value();
@@ -1142,7 +1095,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());
@@ -1183,7 +1136,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.
@@ -1202,9 +1157,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();
@@ -1289,8 +1243,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.
@@ -1300,7 +1256,7 @@
         mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
 
         if (outTimeline.refreshRequired) {
-            // Scheduler will submit an empty frame to HWC.
+            scheduleComposite(FrameHint::kNone);
             mSetActiveModePending = true;
         } else {
             // Updating the internal state should be done outside the loop,
@@ -1323,7 +1279,7 @@
 }
 
 void SurfaceFlinger::disableExpensiveRendering() {
-    auto future = mScheduler->schedule([=]() MAIN_THREAD {
+    auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
         ATRACE_CALL();
         if (mPowerAdvisor.isUsingExpensiveRendering()) {
             for (const auto& [_, display] : mDisplays) {
@@ -1372,7 +1328,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",
@@ -1407,17 +1363,17 @@
 }
 
 status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const {
-    auto future = mScheduler->schedule([=]() MAIN_THREAD mutable -> status_t {
-        *outSupport = getHwComposer().getBootDisplayModeSupport();
-        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());
@@ -1444,7 +1400,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 {
@@ -1457,7 +1413,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 {
@@ -1468,7 +1424,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);
@@ -1533,7 +1489,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);
@@ -1610,7 +1566,7 @@
 status_t SurfaceFlinger::getLayerDebugInfo(std::vector<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()));
         });
@@ -1722,7 +1678,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(
@@ -1736,7 +1692,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);
@@ -1806,6 +1764,7 @@
 }
 
 status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) {
+    using hardware::power::Boost;
     Boost powerBoost = static_cast<Boost>(boostId);
 
     if (powerBoost == Boost::INTERACTION) {
@@ -1941,6 +1900,10 @@
         hal::HWDisplayId, const hal::VsyncPeriodChangeTimeline& timeline) {
     Mutex::Autolock lock(mStateLock);
     mScheduler->onNewVsyncPeriodChangeTimeline(timeline);
+
+    if (timeline.refreshRequired) {
+        scheduleComposite(FrameHint::kNone);
+    }
 }
 
 void SurfaceFlinger::onComposerHalSeamlessPossible(hal::HWDisplayId) {
@@ -1962,7 +1925,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();
@@ -2010,8 +1973,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) {
@@ -2177,20 +2140,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());
@@ -2248,7 +2212,9 @@
 
     mTimeStats->recordFrameDuration(frameTime, systemTime());
 
-    mScheduler->onPostComposition(presentTime);
+    if (mScheduler->onPostComposition(presentTime)) {
+        scheduleComposite(FrameHint::kNone);
+    }
 
     postFrame();
     postComposition();
@@ -2426,7 +2392,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;
@@ -2626,44 +2592,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) {
@@ -2917,7 +2876,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);
     }
 
@@ -3287,7 +3247,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 =
@@ -3310,7 +3270,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();
 
@@ -3355,7 +3315,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());
         }
@@ -3540,7 +3500,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);
@@ -3670,16 +3630,13 @@
     return mTransactionFlags.fetch_and(~mask) & mask;
 }
 
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask) {
-    return setTransactionFlags(mask, TransactionSchedule::Late);
-}
-
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
-                                             const sp<IBinder>& applyToken) {
-    const uint32_t old = mTransactionFlags.fetch_or(mask);
+void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
+                                         const sp<IBinder>& applyToken) {
     modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken);
-    if ((old & mask) == 0) scheduleCommit(FrameHint::kActive);
-    return old;
+
+    if (const bool scheduled = mTransactionFlags.fetch_or(mask) & mask; !scheduled) {
+        scheduleCommit(FrameHint::kActive);
+    }
 }
 
 bool SurfaceFlinger::stopTransactionProcessing(
@@ -3695,6 +3652,15 @@
     return false;
 }
 
+int SurfaceFlinger::flushUnsignaledPendingTransactionQueues(
+        std::vector<TransactionState>& transactions,
+        std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
+        std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions) {
+    return flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+                                         applyTokensWithUnsignaledTransactions,
+                                         /*tryApplyUnsignaled*/ true);
+}
+
 int SurfaceFlinger::flushPendingTransactionQueues(
         std::vector<TransactionState>& transactions,
         std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
@@ -3729,8 +3695,8 @@
                 break;
             }
             transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
-                const bool frameNumberChanged = 
-                    state.bufferData->flags.test(BufferData::BufferDataChange::frameNumberChanged);
+                const bool frameNumberChanged = state.bufferData->flags.test(
+                        BufferData::BufferDataChange::frameNumberChanged);
                 if (frameNumberChanged) {
                     bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber;
                 } else {
@@ -3810,8 +3776,8 @@
                     mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
                 } else {
                     transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
-                        const bool frameNumberChanged = 
-                            state.bufferData->flags.test(BufferData::BufferDataChange::frameNumberChanged);
+                        const bool frameNumberChanged = state.bufferData->flags.test(
+                                BufferData::BufferDataChange::frameNumberChanged);
                         if (frameNumberChanged) {
                             bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber;
                         } else {
@@ -3820,7 +3786,7 @@
                             bufferLayersReadyToPresent[state.surface] =
                                 std::numeric_limits<uint64_t>::max();
                         }
-                      });
+                    });
                     transactions.emplace_back(std::move(transaction));
                 }
                 mTransactionQueue.pop_front();
@@ -3849,9 +3815,8 @@
             // If we are allowing latch unsignaled of some form, now it's the time to go over the
             // transactions that were not applied and try to apply them unsignaled.
             if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
-                flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
-                                              applyTokensWithUnsignaledTransactions,
-                                              /*tryApplyUnsignaled*/ true);
+                flushUnsignaledPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+                                                        applyTokensWithUnsignaledTransactions);
             }
 
             return applyTransactions(transactions, vsyncId);
@@ -4821,7 +4786,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) {
@@ -4921,7 +4887,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,
@@ -4968,7 +4934,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);
@@ -5056,8 +5022,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();
@@ -5215,7 +5179,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());
@@ -5459,9 +5423,7 @@
     /*
      * Dump flag/property manager state
      */
-    if (mFlagManager != nullptr) {
-        mFlagManager->dump(result);
-    }
+    mFlagManager.dump(result);
 
     result.append(mTimeStats->miniDump());
     result.append("\n");
@@ -5858,7 +5820,7 @@
                         int64_t startingTime =
                                 (fixedStartingTime) ? fixedStartingTime : systemTime();
                         mScheduler
-                                ->schedule([&]() MAIN_THREAD {
+                                ->schedule([&]() FTL_FAKE_GUARD(mStateLock) {
                                     mLayerTracing.notify("start", startingTime);
                                 })
                                 .wait();
@@ -5971,10 +5933,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 +5976,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 +5998,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 +6114,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 +6912,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 +7157,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();
         }
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index df59d50..97b0e8d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -56,6 +56,7 @@
 #include "DisplayHardware/PowerAdvisor.h"
 #include "DisplayIdGenerator.h"
 #include "Effects/Daltonizer.h"
+#include "FlagManager.h"
 #include "FrameTracker.h"
 #include "LayerVector.h"
 #include "Scheduler/RefreshRateConfigs.h"
@@ -63,6 +64,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"
@@ -182,11 +184,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,
@@ -286,10 +283,13 @@
     SurfaceFlingerBE& getBE() { return mBE; }
     const SurfaceFlingerBE& getBE() const { return mBE; }
 
+    // Indicates frame activity, i.e. whether commit and/or composite is taking place.
+    enum class FrameHint { kNone, kActive };
+
     // Schedule commit of transactions on the main thread ahead of the next VSYNC.
     void scheduleCommit(FrameHint);
     // As above, but also force composite regardless if transactions were committed.
-    void scheduleComposite(FrameHint) override;
+    void scheduleComposite(FrameHint);
     // As above, but also force dirty geometry to repaint.
     void scheduleRepaint();
     // Schedule sampling independently from commit or composite.
@@ -736,7 +736,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);
@@ -770,27 +770,27 @@
             std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions,
             bool tryApplyUnsignaled) REQUIRES(mStateLock, mQueueLock);
 
+    int flushUnsignaledPendingTransactionQueues(
+            std::vector<TransactionState>& transactions,
+            std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
+            std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions)
+            REQUIRES(mStateLock, mQueueLock);
+
     uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&,
                                   int64_t desiredPresentTime, bool isAutoTimestamp,
                                   int64_t postTime, uint32_t permissions) REQUIRES(mStateLock);
 
     uint32_t getTransactionFlags() const;
 
-    // Sets the masked bits, and returns the old flags.
-    uint32_t setTransactionFlags(uint32_t mask);
+    // Sets the masked bits, and schedules a commit if needed.
+    void setTransactionFlags(uint32_t mask, TransactionSchedule = TransactionSchedule::Late,
+                             const sp<IBinder>& applyToken = nullptr);
 
     // Clears and returns the masked bits.
     uint32_t clearTransactionFlags(uint32_t mask);
 
-    // Indicate SF should call doTraversal on layers, but don't trigger a wakeup! We use this cases
-    // where there are still pending transactions but we know they won't be ready until a frame
-    // arrives from a different layer. So we need to ensure we performTransaction from invalidate
-    // but there is no need to try and wake up immediately to do it. Rather we rely on
-    // onFrameAvailable or another layer update to wake us up.
-    void setTraversalNeeded();
-    uint32_t setTransactionFlags(uint32_t mask, TransactionSchedule,
-                                 const sp<IBinder>& applyToken = {});
     void commitOffscreenLayers();
+
     enum class TransactionReadiness {
         NotReady,
         NotReadyBarrier,
@@ -969,7 +969,7 @@
     void setCompositorTimingSnapped(const DisplayStatInfo& stats,
                                     nsecs_t compositeToPresentLatency);
 
-    void postFrame();
+    void postFrame() REQUIRES(kMainThreadContext);
 
     /*
      * Display management
@@ -1084,7 +1084,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;
@@ -1415,7 +1415,7 @@
 
     const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
 
-    std::unique_ptr<FlagManager> mFlagManager;
+    FlagManager mFlagManager;
 
     // returns the framerate of the layer with the given sequence ID
     float getLayerFramerate(nsecs_t now, int32_t id) const {
@@ -1427,7 +1427,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);
 
diff --git a/services/surfaceflinger/ThreadContext.h b/services/surfaceflinger/ThreadContext.h
new file mode 100644
index 0000000..85c379d
--- /dev/null
+++ b/services/surfaceflinger/ThreadContext.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+
+// Enforces exclusive access by the main thread.
+constexpr class [[clang::capability("mutex")]] {
+} kMainThreadContext;
+
+} // namespace android
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index a5a716d..f25043c 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -140,10 +140,8 @@
 
     mFlinger->enableLatchUnsignaledConfig = mFdp.PickValueInArray(kLatchUnsignaledConfig);
 
-    mFlinger->scheduleComposite(mFdp.ConsumeBool()
-                                        ? scheduler::ISchedulerCallback::FrameHint::kActive
-                                        : scheduler::ISchedulerCallback::FrameHint::kNone);
-
+    using FrameHint = SurfaceFlinger::FrameHint;
+    mFlinger->scheduleComposite(mFdp.ConsumeBool() ? FrameHint::kActive : FrameHint::kNone);
     mFlinger->scheduleRepaint();
     mFlinger->scheduleSample();
 
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 93abc9f..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());
@@ -810,7 +812,6 @@
     }
 
 private:
-    void scheduleComposite(FrameHint) override {}
     void setVsyncEnabled(bool) override {}
     void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override {}
     void kernelTimerChanged(bool) override {}
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/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 5083d56..5267586 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -23,7 +23,6 @@
 namespace android::scheduler::mock {
 
 struct SchedulerCallback final : ISchedulerCallback {
-    MOCK_METHOD(void, scheduleComposite, (FrameHint), (override));
     MOCK_METHOD(void, setVsyncEnabled, (bool), (override));
     MOCK_METHOD(void, requestDisplayMode, (DisplayModePtr, DisplayModeEvent), (override));
     MOCK_METHOD(void, kernelTimerChanged, (bool), (override));
@@ -31,7 +30,6 @@
 };
 
 struct NoOpSchedulerCallback final : ISchedulerCallback {
-    void scheduleComposite(FrameHint) override {}
     void setVsyncEnabled(bool) override {}
     void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override {}
     void kernelTimerChanged(bool) override {}