Merge "Use strong reference to parent Handle when creating layer"
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 83e6787..3722383 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -38,11 +38,6 @@
 #include "DumpPool.h"
 #include "TaskQueue.h"
 
-// Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
-// std::vector<std::string>
-// TODO: remove once not used
-#define MAX_ARGS_ARRAY_SIZE 1000
-
 // TODO: move everything under this namespace
 // TODO: and then remove explicitly android::os::dumpstate:: prefixes
 namespace android {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 5082eb0..157d259 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -25,6 +25,7 @@
 #include <functional>
 #include <inttypes.h>
 #include <regex>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
@@ -281,36 +282,31 @@
 }
 
 status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
-    auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
     const binder::Status dump_permission = checkPermission(kDump);
     if (!dump_permission.isOk()) {
-        out << dump_permission.toString8() << endl;
+        dprintf(fd, "%s\n", dump_permission.toString8().c_str());
         return PERMISSION_DENIED;
     }
-    std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    out << "installd is happy!" << endl;
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     {
         std::lock_guard<std::recursive_mutex> lock(mMountsLock);
-        out << endl << "Storage mounts:" << endl;
+        dprintf(fd, "Storage mounts:\n");
         for (const auto& n : mStorageMounts) {
-            out << "    " << n.first << " = " << n.second << endl;
+            dprintf(fd, "    %s = %s\n", n.first.c_str(), n.second.c_str());
         }
     }
 
     {
         std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
-        out << endl << "Per-UID cache quotas:" << endl;
+        dprintf(fd, "Per-UID cache quotas:\n");
         for (const auto& n : mCacheQuotas) {
-            out << "    " << n.first << " = " << n.second << endl;
+            dprintf(fd, "    %d = %" PRId64 "\n", n.first, n.second);
         }
     }
 
-    out << "is_dexopt_blocked:" << android::installd::is_dexopt_blocked() << endl;
-
-    out << endl;
-    out.flush();
+    dprintf(fd, "is_dexopt_blocked:%d\n", android::installd::is_dexopt_blocked());
 
     return NO_ERROR;
 }
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 94b2806..4f21cda 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -89,13 +89,21 @@
     return init(nullptr, false /*requireDefault*/);
 }
 
+[[clang::no_destroy]] static sp<ProcessState> gProcess;
+[[clang::no_destroy]] static std::mutex gProcessMutex;
+
+static void verifyNotForked(bool forked) {
+    LOG_ALWAYS_FATAL_IF(forked, "libbinder ProcessState can not be used after fork");
+}
+
 sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
 {
-    [[clang::no_destroy]] static sp<ProcessState> gProcess;
-    [[clang::no_destroy]] static std::mutex gProcessMutex;
 
     if (driver == nullptr) {
         std::lock_guard<std::mutex> l(gProcessMutex);
+        if (gProcess) {
+            verifyNotForked(gProcess->mForked);
+        }
         return gProcess;
     }
 
@@ -106,6 +114,14 @@
             driver = "/dev/binder";
         }
 
+        // we must install these before instantiating the gProcess object,
+        // otherwise this would race with creating it, and there could be the
+        // possibility of an invalid gProcess object forked by another thread
+        // before these are installed
+        int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
+                                 ProcessState::childPostFork);
+        LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));
+
         std::lock_guard<std::mutex> l(gProcessMutex);
         gProcess = sp<ProcessState>::make(driver);
     });
@@ -119,6 +135,7 @@
                             gProcess->getDriverName().c_str(), driver);
     }
 
+    verifyNotForked(gProcess->mForked);
     return gProcess;
 }
 
@@ -137,6 +154,24 @@
     return context;
 }
 
+void ProcessState::onFork() {
+    // make sure another thread isn't currently retrieving ProcessState
+    gProcessMutex.lock();
+}
+
+void ProcessState::parentPostFork() {
+    gProcessMutex.unlock();
+}
+
+void ProcessState::childPostFork() {
+    // another thread might call fork before gProcess is instantiated, but after
+    // the thread handler is installed
+    if (gProcess) {
+        gProcess->mForked = true;
+    }
+    gProcessMutex.unlock();
+}
+
 void ProcessState::startThreadPool()
 {
     AutoMutex _l(mLock);
@@ -426,6 +461,7 @@
         mWaitingForThreads(0),
         mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
         mStarvationStartTimeMs(0),
+        mForked(false),
         mThreadPoolStarted(false),
         mThreadPoolSeq(1),
         mCallRestriction(CallRestriction::NONE) {
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index cf30f17..32056d9 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -1237,7 +1237,9 @@
      */
     size_t getOpenAshmemSize() const;
 
-    // TODO(b/202029388): Remove 'getBlobAshmemSize' once ABI can be changed.
+private:
+    // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference
+    // this
     size_t getBlobAshmemSize() const;
 };
 
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 72c2ab7..cf8d8e4 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -94,6 +94,10 @@
 private:
     static sp<ProcessState> init(const char* defaultDriver, bool requireDefault);
 
+    static void onFork();
+    static void parentPostFork();
+    static void childPostFork();
+
     friend class IPCThreadState;
     friend class sp<ProcessState>;
 
@@ -132,6 +136,7 @@
 
     Vector<handle_entry> mHandleToObject;
 
+    bool mForked;
     bool mThreadPoolStarted;
     volatile int32_t mThreadPoolSeq;
 
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 49c7b7c..81aa551 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -780,3 +780,7 @@
     AIBinder_incStrong(ndkBinder.get());
     return ndkBinder.get();
 }
+
+void AIBinder_setMinSchedulerPolicy(AIBinder* binder, int policy, int priority) {
+    binder->asABBinder()->setMinSchedulerPolicy(policy, priority);
+}
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 4a7b664..2b18a0a 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -550,8 +550,8 @@
                                                                 const void* vectorData,
                                                                 size_t index) {
     const std::optional<std::vector<P>>* vector =
-            static_cast<const std::optional<std::vector<P>*>>(vectorData);
-    return AParcel_writeNullableParcelable(parcel, vector->at(index));
+            static_cast<const std::optional<std::vector<P>>*>(vectorData);
+    return AParcel_writeNullableParcelable(parcel, (*vector)->at(index));
 }
 
 /**
@@ -561,7 +561,7 @@
 binder_status_t AParcel_readNullableStdVectorParcelableElement(const AParcel* parcel,
                                                                void* vectorData, size_t index) {
     std::optional<std::vector<P>>* vector = static_cast<std::optional<std::vector<P>>*>(vectorData);
-    return AParcel_readNullableParcelable(parcel, &vector->at(index));
+    return AParcel_readNullableParcelable(parcel, &(*vector)->at(index));
 }
 
 /**
@@ -573,11 +573,7 @@
         AParcel* parcel, const void* vectorData, size_t index) {
     const std::vector<ScopedFileDescriptor>* vector =
             static_cast<const std::vector<ScopedFileDescriptor>*>(vectorData);
-    int writeFd = vector->at(index).get();
-    if (writeFd < 0) {
-        return STATUS_UNEXPECTED_NULL;
-    }
-    return AParcel_writeParcelFileDescriptor(parcel, writeFd);
+    return AParcel_writeRequiredParcelFileDescriptor(parcel, vector->at(index));
 }
 
 /**
@@ -589,15 +585,31 @@
         const AParcel* parcel, void* vectorData, size_t index) {
     std::vector<ScopedFileDescriptor>* vector =
             static_cast<std::vector<ScopedFileDescriptor>*>(vectorData);
-    int readFd;
-    binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
-    if (status == STATUS_OK) {
-        if (readFd < 0) {
-            return STATUS_UNEXPECTED_NULL;
-        }
-        vector->at(index).set(readFd);
-    }
-    return status;
+    return AParcel_readRequiredParcelFileDescriptor(parcel, &vector->at(index));
+}
+
+/**
+ * Writes a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
+ * index 'index' to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<ScopedFileDescriptor>(
+        AParcel* parcel, const void* vectorData, size_t index) {
+    const std::optional<std::vector<ScopedFileDescriptor>>* vector =
+            static_cast<const std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
+    return AParcel_writeNullableParcelFileDescriptor(parcel, (*vector)->at(index));
+}
+
+/**
+ * Reads a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
+ * index 'index' from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readNullableStdVectorParcelableElement<ScopedFileDescriptor>(
+        const AParcel* parcel, void* vectorData, size_t index) {
+    std::optional<std::vector<ScopedFileDescriptor>>* vector =
+            static_cast<std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
+    return AParcel_readNullableParcelFileDescriptor(parcel, &(*vector)->at(index));
 }
 
 /**
diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
index e315c79..b0217c4 100644
--- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
@@ -55,4 +55,17 @@
  */
 __attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31);
 
+/**
+ * Sets a minimum scheduler policy for all transactions coming into this
+ * AIBinder.
+ *
+ * This must be called before the object is sent to another process.
+ * Aborts on invalid values. Not thread safe.
+ *
+ * \param binder local server binder to set the policy for
+ * \param policy scheduler policy as defined in linux UAPI
+ * \param priority priority. [-20..19] for SCHED_NORMAL, [1..99] for RT
+ */
+void AIBinder_setMinSchedulerPolicy(AIBinder* binder, int policy, int priority) __INTRODUCED_IN(33);
+
 __END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 8605686..64170af 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -145,6 +145,7 @@
   global:
     AIBinder_Class_disableInterfaceTokenHeader;
     AIBinder_DeathRecipient_setOnUnlinked;
+    AIBinder_setMinSchedulerPolicy; # llndk
     AParcel_marshal;
     AParcel_unmarshal;
 };
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index f71a686..8bcc5d0 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -94,8 +94,6 @@
     }
 }
 
-impl SerializeArray for Option<ParcelFileDescriptor> {}
-
 impl DeserializeOption for ParcelFileDescriptor {
     fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
         let mut fd = -1i32;
@@ -126,8 +124,6 @@
     }
 }
 
-impl DeserializeArray for Option<ParcelFileDescriptor> {}
-
 impl Deserialize for ParcelFileDescriptor {
     fn deserialize(parcel: &Parcel) -> Result<Self> {
         Deserialize::deserialize(parcel)
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 499ef09..ec00e1d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -383,6 +383,9 @@
     };
 }
 
+impl<T: DeserializeOption> DeserializeArray for Option<T> {}
+impl<T: SerializeOption> SerializeArray for Option<T> {}
+
 parcelable_primitives! {
     impl Serialize for bool = sys::AParcel_writeBool;
     impl Deserialize for bool = sys::AParcel_readBool;
@@ -537,8 +540,6 @@
     }
 }
 
-impl SerializeArray for Option<&str> {}
-
 impl Serialize for str {
     fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
         Some(self).serialize(parcel)
@@ -561,8 +562,6 @@
     }
 }
 
-impl SerializeArray for Option<String> {}
-
 impl Deserialize for Option<String> {
     fn deserialize(parcel: &Parcel) -> Result<Self> {
         let mut vec: Option<Vec<u8>> = None;
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 6a4af07..2c5b0a8 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -429,8 +429,6 @@
 }
 
 impl SerializeArray for SpIBinder {}
-impl SerializeArray for Option<&SpIBinder> {}
-impl SerializeArray for Option<SpIBinder> {}
 
 impl Deserialize for SpIBinder {
     fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
@@ -448,7 +446,6 @@
 }
 
 impl DeserializeArray for SpIBinder {}
-impl DeserializeArray for Option<SpIBinder> {}
 
 /// A weak reference to a Binder remote object.
 ///
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index c69203b..c41f424 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -436,6 +436,11 @@
         };
 };
 
+TEST_F(BinderLibTest, CannotUseBinderAfterFork) {
+    // EXPECT_DEATH works by forking the process
+    EXPECT_DEATH({ ProcessState::self(); }, "libbinder ProcessState can not be used after fork");
+}
+
 TEST_F(BinderLibTest, WasParceled) {
     auto binder = sp<BBinder>::make();
     EXPECT_FALSE(binder->wasParceled());
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 8267702..f132ff7 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1307,6 +1307,16 @@
     ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
 }
 
+TEST_P(BinderRpc, AidlDelegatorTest) {
+    auto proc = createRpcTestSocketServerProcess({});
+    auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
+    ASSERT_NE(nullptr, myDelegator);
+
+    std::string doubled;
+    EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
+    EXPECT_EQ("cool cool ", doubled);
+}
+
 static bool testSupportVsockLoopback() {
     // We don't need to enable TLS to know if vsock is supported.
     unsigned int vsockPort = allocateVsockPort();
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 55eb847..8e8994b 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -284,7 +284,6 @@
         FUZZ_LOG() << "readObject: " << obj;
     },
     PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
-    PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
     PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
 
     // additional parcelable objects defined in libbinder
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 6b783a4..c0a762d 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -95,6 +95,11 @@
         PARCEL_READ(std::vector<std::string>, ndk::AParcel_readVector),
         PARCEL_READ(std::optional<std::vector<std::optional<std::string>>>, ndk::AParcel_readVector),
         PARCEL_READ(std::vector<SomeParcelable>, ndk::AParcel_readVector),
+        PARCEL_READ(std::optional<std::vector<std::optional<SomeParcelable>>>, ndk::AParcel_readVector),
+        PARCEL_READ(std::vector<ndk::SpAIBinder>, ndk::AParcel_readVector),
+        PARCEL_READ(std::optional<std::vector<ndk::SpAIBinder>>, ndk::AParcel_readVector),
+        PARCEL_READ(std::vector<ndk::ScopedFileDescriptor>, ndk::AParcel_readVector),
+        PARCEL_READ(std::optional<std::vector<ndk::ScopedFileDescriptor>>, ndk::AParcel_readVector),
         PARCEL_READ(std::vector<int32_t>, ndk::AParcel_readVector),
         PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_readVector),
         PARCEL_READ(std::vector<uint32_t>, ndk::AParcel_readVector),
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
index c0f0a12..71e847f 100644
--- a/libs/binder/tests/rpc_fuzzer/Android.bp
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -14,6 +14,7 @@
     fuzz_config: {
         cc: ["smoreland@google.com"],
     },
+    corpus: ["corpus/*"],
     dictionary: "binder_rpc_fuzzer.dict",
 
     srcs: [
diff --git a/libs/binder/tests/rpc_fuzzer/corpus/special_transaction b/libs/binder/tests/rpc_fuzzer/corpus/special_transaction
new file mode 100644
index 0000000..37228ee
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/corpus/special_transaction
Binary files differ
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index 518849a..83f2ebe 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -158,6 +158,8 @@
         }
     }
 
+    usleep(10000);
+
     if (hangupBeforeShutdown) {
         connections.clear();
         while (!server->listSessions().empty() || server->numUninitializedSessions()) {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dfbb863..1ae90f3 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -319,9 +319,6 @@
 
 void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
                                            const std::vector<SurfaceControlStats>& stats) {
-    std::function<void(int64_t)> transactionCompleteCallback = nullptr;
-    uint64_t currFrameNumber = 0;
-
     {
         std::unique_lock _lock{mMutex};
         ATRACE_CALL();
@@ -348,18 +345,6 @@
                                                     stat.latchTime,
                                                     stat.frameEventStats.dequeueReadyTime);
                 }
-                currFrameNumber = stat.frameEventStats.frameNumber;
-
-                if (mTransactionCompleteCallback &&
-                    currFrameNumber >= mTransactionCompleteFrameNumber) {
-                    if (currFrameNumber > mTransactionCompleteFrameNumber) {
-                        BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64
-                                 " than expected=%" PRIu64,
-                                 currFrameNumber, mTransactionCompleteFrameNumber);
-                    }
-                    transactionCompleteCallback = std::move(mTransactionCompleteCallback);
-                    mTransactionCompleteFrameNumber = 0;
-                }
             } else {
                 BQA_LOGE("Failed to find matching SurfaceControl in transaction callback");
             }
@@ -370,10 +355,6 @@
 
         decStrong((void*)transactionCallbackThunk);
     }
-
-    if (transactionCompleteCallback) {
-        transactionCompleteCallback(currFrameNumber);
-    }
 }
 
 // Unlike transactionCallbackThunk the release buffer callback does not extend the life of the
@@ -698,17 +679,6 @@
     return mSize != bufferSize;
 }
 
-void BLASTBufferQueue::setTransactionCompleteCallback(
-        uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback) {
-    std::lock_guard _lock{mMutex};
-    if (transactionCompleteCallback == nullptr) {
-        mTransactionCompleteCallback = nullptr;
-    } else {
-        mTransactionCompleteCallback = std::move(transactionCompleteCallback);
-        mTransactionCompleteFrameNumber = frameNumber;
-    }
-}
-
 // Check if we have acquired the maximum number of buffers.
 // Consumer can acquire an additional buffer if that buffer is not droppable. Set
 // includeExtraAcquire is true to include this buffer to the count. Since this depends on the state
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 4a1d475..3881620 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -88,8 +88,8 @@
     void onFrameDequeued(const uint64_t) override;
     void onFrameCancelled(const uint64_t) override;
 
-    void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
-                                      const std::vector<SurfaceControlStats>& stats);
+    virtual void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+                                              const std::vector<SurfaceControlStats>& stats);
     void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
             const std::vector<SurfaceControlStats>& stats);
     void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
@@ -97,8 +97,6 @@
     void setNextTransaction(SurfaceComposerClient::Transaction *t);
     void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
     void applyPendingTransactions(uint64_t frameNumber);
-    void setTransactionCompleteCallback(uint64_t frameNumber,
-                                        std::function<void(int64_t)>&& transactionCompleteCallback);
 
     void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format,
                 SurfaceComposerClient::Transaction* outTransaction = nullptr);
@@ -224,9 +222,6 @@
     // Tracks the last acquired frame number
     uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0;
 
-    std::function<void(int64_t)> mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr;
-    uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0};
-
     // Queues up transactions using this token in SurfaceFlinger. This prevents queued up
     // transactions from other parts of the client from blocking this transaction.
     const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = new BBinder();
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 8e4898d..b2d5048 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -66,11 +66,44 @@
     int32_t mNumReleased GUARDED_BY(mMutex) = 0;
 };
 
+class TestBLASTBufferQueue : public BLASTBufferQueue {
+public:
+    TestBLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
+                         int height, int32_t format)
+          : BLASTBufferQueue(name, surface, width, height, format) {}
+
+    void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+                                      const std::vector<SurfaceControlStats>& stats) override {
+        BLASTBufferQueue::transactionCommittedCallback(latchTime, presentFence, stats);
+
+        uint64_t frameNumber = stats[0].frameEventStats.frameNumber;
+
+        {
+            std::unique_lock lock{frameNumberMutex};
+            mLastTransactionCommittedFrameNumber = frameNumber;
+            mCommittedCV.notify_all();
+        }
+    }
+
+    void waitForCallback(int64_t frameNumber) {
+        std::unique_lock lock{frameNumberMutex};
+        // Wait until all but one of the submitted buffers have been released.
+        while (mLastTransactionCommittedFrameNumber < frameNumber) {
+            mCommittedCV.wait(lock);
+        }
+    }
+
+private:
+    std::mutex frameNumberMutex;
+    std::condition_variable mCommittedCV;
+    int64_t mLastTransactionCommittedFrameNumber = -1;
+};
+
 class BLASTBufferQueueHelper {
 public:
     BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) {
-        mBlastBufferQueueAdapter = new BLASTBufferQueue("TestBLASTBufferQueue", sc, width, height,
-                                                        PIXEL_FORMAT_RGBA_8888);
+        mBlastBufferQueueAdapter = new TestBLASTBufferQueue("TestBLASTBufferQueue", sc, width,
+                                                            height, PIXEL_FORMAT_RGBA_8888);
     }
 
     void update(const sp<SurfaceControl>& sc, int width, int height) {
@@ -107,28 +140,12 @@
         }
     }
 
-    void setTransactionCompleteCallback(int64_t frameNumber) {
-        mBlastBufferQueueAdapter->setTransactionCompleteCallback(frameNumber, [&](int64_t frame) {
-            std::unique_lock lock{mMutex};
-            mLastTransactionCompleteFrameNumber = frame;
-            mCallbackCV.notify_all();
-        });
-    }
-
     void waitForCallback(int64_t frameNumber) {
-        std::unique_lock lock{mMutex};
-        // Wait until all but one of the submitted buffers have been released.
-        while (mLastTransactionCompleteFrameNumber < frameNumber) {
-            mCallbackCV.wait(lock);
-        }
+        mBlastBufferQueueAdapter->waitForCallback(frameNumber);
     }
 
 private:
-    sp<BLASTBufferQueue> mBlastBufferQueueAdapter;
-
-    std::mutex mMutex;
-    std::condition_variable mCallbackCV;
-    int64_t mLastTransactionCompleteFrameNumber = -1;
+    sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
 };
 
 class BLASTBufferQueueTest : public ::testing::Test {
@@ -1366,7 +1383,6 @@
     IGraphicBufferProducer::QueueBufferOutput qbOutput;
     nsecs_t requestedPresentTimeA = 0;
     nsecs_t postedTimeA = 0;
-    adapter.setTransactionCompleteCallback(1);
     setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
     history.applyDelta(qbOutput.frameTimestamps);
 
@@ -1435,7 +1451,6 @@
     // queue another buffer so the first can be dropped
     nsecs_t requestedPresentTimeB = 0;
     nsecs_t postedTimeB = 0;
-    adapter.setTransactionCompleteCallback(2);
     presentTime = systemTime() + std::chrono::nanoseconds(1ms).count();
     setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true,
                         presentTime);
@@ -1501,7 +1516,6 @@
     IGraphicBufferProducer::QueueBufferOutput qbOutput;
     nsecs_t requestedPresentTimeA = 0;
     nsecs_t postedTimeA = 0;
-    adapter.setTransactionCompleteCallback(1);
     setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
     history.applyDelta(qbOutput.frameTimestamps);
     adapter.waitForCallback(1);
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 2db9992..93e7239 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -133,7 +133,6 @@
 
 int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) {
     static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN));
-    static_assert(static_cast<int>(STANDARD_SHIFT) == static_cast<int>(HAL_DATASPACE_STANDARD_SHIFT));
     static_assert(static_cast<int>(STANDARD_MASK) == static_cast<int>(HAL_DATASPACE_STANDARD_MASK));
     static_assert(static_cast<int>(STANDARD_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_STANDARD_UNSPECIFIED));
     static_assert(static_cast<int>(STANDARD_BT709) == static_cast<int>(HAL_DATASPACE_STANDARD_BT709));
@@ -145,7 +144,6 @@
     static_assert(static_cast<int>(STANDARD_FILM) == static_cast<int>(HAL_DATASPACE_STANDARD_FILM));
     static_assert(static_cast<int>(STANDARD_DCI_P3) == static_cast<int>(HAL_DATASPACE_STANDARD_DCI_P3));
     static_assert(static_cast<int>(STANDARD_ADOBE_RGB) == static_cast<int>(HAL_DATASPACE_STANDARD_ADOBE_RGB));
-    static_assert(static_cast<int>(TRANSFER_SHIFT) == static_cast<int>(HAL_DATASPACE_TRANSFER_SHIFT));
     static_assert(static_cast<int>(TRANSFER_MASK) == static_cast<int>(HAL_DATASPACE_TRANSFER_MASK));
     static_assert(static_cast<int>(TRANSFER_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_TRANSFER_UNSPECIFIED));
     static_assert(static_cast<int>(TRANSFER_LINEAR) == static_cast<int>(HAL_DATASPACE_TRANSFER_LINEAR));
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 612fb39..a299488 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -56,9 +56,7 @@
      * Defines the chromaticity coordinates of the source primaries in terms of
      * the CIE 1931 definition of x and y specified in ISO 11664-1.
      */
-    STANDARD_SHIFT = 16,
-
-    STANDARD_MASK = 63 << 16, // 63 << STANDARD_SHIFT = 0x3F
+    STANDARD_MASK = 63 << 16,
 
     /**
      * Chromacity coordinates are unknown or are determined by the application.
@@ -73,7 +71,7 @@
      * For all other formats standard is undefined, and implementations should use
      * an appropriate standard for the data represented.
      */
-    STANDARD_UNSPECIFIED = 0 << 16, // STANDARD_SHIFT
+    STANDARD_UNSPECIFIED = 0 << 16,
 
     /**
      * Primaries:       x       y
@@ -85,7 +83,7 @@
      * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
      * for RGB conversion.
      */
-    STANDARD_BT709 = 1 << 16, // 1 << STANDARD_SHIFT
+    STANDARD_BT709 = 1 << 16,
 
     /**
      * Primaries:       x       y
@@ -99,7 +97,7 @@
      *  to minimize the color shift into RGB space that uses BT.709
      *  primaries.
      */
-    STANDARD_BT601_625 = 2 << 16, // 2 << STANDARD_SHIFT,
+    STANDARD_BT601_625 = 2 << 16,
 
     /**
      * Primaries:       x       y
@@ -111,7 +109,7 @@
      * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
      * for RGB conversion.
      */
-    STANDARD_BT601_625_UNADJUSTED = 3 << 16, // 3 << STANDARD_SHIFT
+    STANDARD_BT601_625_UNADJUSTED = 3 << 16,
 
     /**
      * Primaries:       x       y
@@ -125,7 +123,7 @@
      *  to minimize the color shift into RGB space that uses BT.709
      *  primaries.
      */
-    STANDARD_BT601_525 = 4 << 16, // 4 << STANDARD_SHIFT
+    STANDARD_BT601_525 = 4 << 16,
 
     /**
      * Primaries:       x       y
@@ -137,7 +135,7 @@
      * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
      * for RGB conversion (as in SMPTE 240M).
      */
-    STANDARD_BT601_525_UNADJUSTED = 5 << 16, // 5 << STANDARD_SHIFT
+    STANDARD_BT601_525_UNADJUSTED = 5 << 16,
 
     /**
      * Primaries:       x       y
@@ -149,7 +147,7 @@
      * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
      * for RGB conversion.
      */
-    STANDARD_BT2020 = 6 << 16, // 6 << STANDARD_SHIFT
+    STANDARD_BT2020 = 6 << 16,
 
     /**
      * Primaries:       x       y
@@ -161,7 +159,7 @@
      * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
      * for RGB conversion using the linear domain.
      */
-    STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16, // 7 << STANDARD_SHIFT
+    STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16,
 
     /**
      * Primaries:       x      y
@@ -173,7 +171,7 @@
      * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
      * for RGB conversion.
      */
-    STANDARD_BT470M = 8 << 16, // 8 << STANDARD_SHIFT
+    STANDARD_BT470M = 8 << 16,
 
     /**
      * Primaries:       x       y
@@ -185,7 +183,7 @@
      * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
      * for RGB conversion.
      */
-    STANDARD_FILM = 9 << 16, // 9 << STANDARD_SHIFT
+    STANDARD_FILM = 9 << 16,
 
     /**
      * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
@@ -195,7 +193,7 @@
      *  red             0.680   0.320
      *  white (D65)     0.3127  0.3290
      */
-    STANDARD_DCI_P3 = 10 << 16, // 10 << STANDARD_SHIFT
+    STANDARD_DCI_P3 = 10 << 16,
 
     /**
      * Adobe RGB
@@ -205,7 +203,7 @@
      *  red             0.640   0.330
      *  white (D65)     0.3127  0.3290
      */
-    STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
+    STANDARD_ADOBE_RGB = 11 << 16,
 
     /**
      * Transfer aspect
@@ -220,9 +218,7 @@
      * component. Implementation may apply the transfer function in RGB space
      * for all pixel formats if desired.
      */
-    TRANSFER_SHIFT = 22,
-
-    TRANSFER_MASK = 31 << 22, // 31 << TRANSFER_SHIFT = 0x1F
+    TRANSFER_MASK = 31 << 22,
 
     /**
      * Transfer characteristics are unknown or are determined by the
@@ -236,7 +232,7 @@
      * For all other formats transfer function is undefined, and implementations
      * should use an appropriate standard for the data represented.
      */
-    TRANSFER_UNSPECIFIED = 0 << 22, // 0 << TRANSFER_SHIFT
+    TRANSFER_UNSPECIFIED = 0 << 22,
 
     /**
      * Transfer characteristic curve:
@@ -244,7 +240,7 @@
      *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      *      E - corresponding electrical signal
      */
-    TRANSFER_LINEAR = 1 << 22, // 1 << TRANSFER_SHIFT
+    TRANSFER_LINEAR = 1 << 22,
 
     /**
      * Transfer characteristic curve:
@@ -254,7 +250,7 @@
      *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
      *     E - corresponding electrical signal
      */
-    TRANSFER_SRGB = 2 << 22, // 2 << TRANSFER_SHIFT
+    TRANSFER_SRGB = 2 << 22,
 
     /**
      * BT.601 525, BT.601 625, BT.709, BT.2020
@@ -265,7 +261,7 @@
      *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      *      E - corresponding electrical signal
      */
-    TRANSFER_SMPTE_170M = 3 << 22, // 3 << TRANSFER_SHIFT
+    TRANSFER_SMPTE_170M = 3 << 22,
 
     /**
      * Assumed display gamma 2.2.
@@ -275,7 +271,7 @@
      *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      *      E - corresponding electrical signal
      */
-    TRANSFER_GAMMA2_2 = 4 << 22, // 4 << TRANSFER_SHIFT
+    TRANSFER_GAMMA2_2 = 4 << 22,
 
     /**
      *  display gamma 2.6.
@@ -285,7 +281,7 @@
      *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      *      E - corresponding electrical signal
      */
-    TRANSFER_GAMMA2_6 = 5 << 22, // 5 << TRANSFER_SHIFT
+    TRANSFER_GAMMA2_6 = 5 << 22,
 
     /**
      *  display gamma 2.8.
@@ -295,7 +291,7 @@
      *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      *      E - corresponding electrical signal
      */
-    TRANSFER_GAMMA2_8 = 6 << 22, // 6 << TRANSFER_SHIFT
+    TRANSFER_GAMMA2_8 = 6 << 22,
 
     /**
      * SMPTE ST 2084 (Dolby Perceptual Quantizer)
@@ -311,7 +307,7 @@
      *          L = 1 corresponds to 10000 cd/m2
      *      E - corresponding electrical signal
      */
-    TRANSFER_ST2084 = 7 << 22, // 7 << TRANSFER_SHIFT
+    TRANSFER_ST2084 = 7 << 22,
 
     /**
      * ARIB STD-B67 Hybrid Log Gamma
@@ -327,7 +323,7 @@
      *          to reference white level of 100 cd/m2
      *      E - corresponding electrical signal
      */
-    TRANSFER_HLG = 8 << 22, // 8 << TRANSFER_SHIFT
+    TRANSFER_HLG = 8 << 22,
 
     /**
      * Range aspect
@@ -335,9 +331,7 @@
      * Defines the range of values corresponding to the unit range of 0-1.
      * This is defined for YCbCr only, but can be expanded to RGB space.
      */
-    RANGE_SHIFT = 27,
-
-    RANGE_MASK = 7 << 27, // 7 << RANGE_SHIFT = 0x7
+    RANGE_MASK = 7 << 27,
 
     /**
      * Range is unknown or are determined by the application.  Implementations
@@ -350,13 +344,13 @@
      * For all other formats range is undefined, and implementations should use
      * an appropriate range for the data represented.
      */
-    RANGE_UNSPECIFIED = 0 << 27, // 0 << RANGE_SHIFT = 0x0
+    RANGE_UNSPECIFIED = 0 << 27,
 
     /**
      * Full range uses all values for Y, Cb and Cr from
      * 0 to 2^b-1, where b is the bit depth of the color format.
      */
-    RANGE_FULL = 1 << 27, // 1 << RANGE_SHIFT = 0x8000000
+    RANGE_FULL = 1 << 27,
 
     /**
      * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
@@ -371,7 +365,7 @@
      * Luma (Y) samples should range from 64 to 940, inclusive
      * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
      */
-    RANGE_LIMITED = 2 << 27, // 2 << RANGE_SHIFT = 0x10000000
+    RANGE_LIMITED = 2 << 27,
 
     /**
      * Extended range is used for scRGB. Intended for use with
@@ -380,7 +374,7 @@
      * color outside the sRGB gamut.
      * Used to blend / merge multiple dataspaces on a single display.
      */
-    RANGE_EXTENDED = 3 << 27, // 3 << RANGE_SHIFT = 0x18000000
+    RANGE_EXTENDED = 3 << 27,
 
     /**
      * scRGB linear encoding:
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 2174df5..a9ea690 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -96,7 +96,7 @@
 }
 
 std::future<RenderEngineResult> RenderEngine::drawLayers(
-        const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
         const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
         base::unique_fd&& bufferFence) {
     const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 2375cb7..22dd866 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1080,7 +1080,7 @@
 
 void GLESRenderEngine::drawLayersInternal(
         const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
-        const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
         const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
         base::unique_fd&& bufferFence) {
     ATRACE_CALL();
@@ -1110,10 +1110,10 @@
     std::unique_ptr<BindNativeBufferAsFramebuffer> fbo;
     // Gathering layers that requested blur, we'll need them to decide when to render to an
     // offscreen buffer, and when to render to the native buffer.
-    std::deque<const LayerSettings*> blurLayers;
+    std::deque<const LayerSettings> blurLayers;
     if (CC_LIKELY(mBlurFilter != nullptr)) {
-        for (auto layer : layers) {
-            if (layer->backgroundBlurRadius > 0) {
+        for (const auto& layer : layers) {
+            if (layer.backgroundBlurRadius > 0) {
                 blurLayers.push_back(layer);
             }
         }
@@ -1137,7 +1137,7 @@
     } else {
         setViewportAndProjection(display.physicalDisplay, display.clip);
         auto status =
-                mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius);
+                mBlurFilter->setAsDrawTarget(display, blurLayers.front().backgroundBlurRadius);
         if (status != NO_ERROR) {
             ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
                   buffer->getBuffer()->handle);
@@ -1167,7 +1167,7 @@
                         .setTexCoords(2 /* size */)
                         .setCropCoords(2 /* size */)
                         .build();
-    for (auto const layer : layers) {
+    for (const auto& layer : layers) {
         if (blurLayers.size() > 0 && blurLayers.front() == layer) {
             blurLayers.pop_front();
 
@@ -1193,7 +1193,7 @@
                 // There's still something else to blur, so let's keep rendering to our FBO
                 // instead of to the display.
                 status = mBlurFilter->setAsDrawTarget(display,
-                                                      blurLayers.front()->backgroundBlurRadius);
+                                                      blurLayers.front().backgroundBlurRadius);
             }
             if (status != NO_ERROR) {
                 ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
@@ -1214,42 +1214,42 @@
         }
 
         // Ensure luminance is at least 100 nits to avoid div-by-zero
-        const float maxLuminance = std::max(100.f, layer->source.buffer.maxLuminanceNits);
+        const float maxLuminance = std::max(100.f, layer.source.buffer.maxLuminanceNits);
         mState.maxMasteringLuminance = maxLuminance;
         mState.maxContentLuminance = maxLuminance;
-        mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform;
+        mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
 
-        const FloatRect bounds = layer->geometry.boundaries;
+        const FloatRect bounds = layer.geometry.boundaries;
         Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
         position[0] = vec2(bounds.left, bounds.top);
         position[1] = vec2(bounds.left, bounds.bottom);
         position[2] = vec2(bounds.right, bounds.bottom);
         position[3] = vec2(bounds.right, bounds.top);
 
-        setupLayerCropping(*layer, mesh);
-        setColorTransform(layer->colorTransform);
+        setupLayerCropping(layer, mesh);
+        setColorTransform(layer.colorTransform);
 
         bool usePremultipliedAlpha = true;
         bool disableTexture = true;
         bool isOpaque = false;
-        if (layer->source.buffer.buffer != nullptr) {
+        if (layer.source.buffer.buffer != nullptr) {
             disableTexture = false;
-            isOpaque = layer->source.buffer.isOpaque;
+            isOpaque = layer.source.buffer.isOpaque;
 
-            sp<GraphicBuffer> gBuf = layer->source.buffer.buffer->getBuffer();
+            sp<GraphicBuffer> gBuf = layer.source.buffer.buffer->getBuffer();
             validateInputBufferUsage(gBuf);
-            bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf,
-                                      layer->source.buffer.fence);
+            bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
+                                      layer.source.buffer.fence);
 
-            usePremultipliedAlpha = layer->source.buffer.usePremultipliedAlpha;
-            Texture texture(Texture::TEXTURE_EXTERNAL, layer->source.buffer.textureName);
-            mat4 texMatrix = layer->source.buffer.textureTransform;
+            usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
+            Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
+            mat4 texMatrix = layer.source.buffer.textureTransform;
 
             texture.setMatrix(texMatrix.asArray());
-            texture.setFiltering(layer->source.buffer.useTextureFiltering);
+            texture.setFiltering(layer.source.buffer.useTextureFiltering);
 
             texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
-            setSourceY410BT2020(layer->source.buffer.isY410BT2020);
+            setSourceY410BT2020(layer.source.buffer.isY410BT2020);
 
             renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
             texCoords[0] = vec2(0.0, 0.0);
@@ -1264,32 +1264,32 @@
             }
         }
 
-        const half3 solidColor = layer->source.solidColor;
-        const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer->alpha);
+        const half3 solidColor = layer.source.solidColor;
+        const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
         // Buffer sources will have a black solid color ignored in the shader,
         // so in that scenario the solid color passed here is arbitrary.
         setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
-                           layer->geometry.roundedCornersRadius);
-        if (layer->disableBlending) {
+                           layer.geometry.roundedCornersRadius);
+        if (layer.disableBlending) {
             glDisable(GL_BLEND);
         }
-        setSourceDataSpace(layer->sourceDataspace);
+        setSourceDataSpace(layer.sourceDataspace);
 
-        if (layer->shadow.length > 0.0f) {
-            handleShadow(layer->geometry.boundaries, layer->geometry.roundedCornersRadius,
-                         layer->shadow);
+        if (layer.shadow.length > 0.0f) {
+            handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius,
+                         layer.shadow);
         }
         // We only want to do a special handling for rounded corners when having rounded corners
         // is the only reason it needs to turn on blending, otherwise, we handle it like the
         // usual way since it needs to turn on blending anyway.
-        else if (layer->geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
-            handleRoundedCorners(display, *layer, mesh);
+        else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+            handleRoundedCorners(display, layer, mesh);
         } else {
             drawMesh(mesh);
         }
 
         // Cleanup if there's a buffer source
-        if (layer->source.buffer.buffer != nullptr) {
+        if (layer.source.buffer.buffer != nullptr) {
             disableBlending();
             setSourceY410BT2020(false);
             disableTexturing();
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index c4adfdf..1d7c2ca 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -104,7 +104,7 @@
     bool canSkipPostRenderCleanup() const override;
     void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
                             const DisplaySettings& display,
-                            const std::vector<const LayerSettings*>& layers,
+                            const std::vector<LayerSettings>& layers,
                             const std::shared_ptr<ExternalTexture>& buffer,
                             const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
 
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 701c1f2..b9cc648 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -160,7 +160,7 @@
     // @return A future object of RenderEngineResult struct indicating whether
     // drawing was successful in async mode.
     virtual std::future<RenderEngineResult> drawLayers(
-            const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+            const DisplaySettings& display, const std::vector<LayerSettings>& layers,
             const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
             base::unique_fd&& bufferFence);
 
@@ -231,7 +231,7 @@
 
     virtual void drawLayersInternal(
             const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
-            const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+            const DisplaySettings& display, const std::vector<LayerSettings>& layers,
             const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
             base::unique_fd&& bufferFence) = 0;
 };
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index a7e6809..248bd65 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -49,12 +49,12 @@
     MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool());
     MOCK_METHOD5(drawLayers,
                  std::future<RenderEngineResult>(const DisplaySettings&,
-                                                 const std::vector<const LayerSettings*>&,
+                                                 const std::vector<LayerSettings>&,
                                                  const std::shared_ptr<ExternalTexture>&,
                                                  const bool, base::unique_fd&&));
     MOCK_METHOD6(drawLayersInternal,
                  void(const std::shared_ptr<std::promise<RenderEngineResult>>&&,
-                      const DisplaySettings&, const std::vector<const LayerSettings*>&,
+                      const DisplaySettings&, const std::vector<LayerSettings>&,
                       const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&));
     MOCK_METHOD0(cleanFramebufferCache, void());
     MOCK_METHOD0(getContextPriority, int());
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index c4fa1bb..b18a872 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -95,7 +95,7 @@
             .alpha = 1,
     };
 
-    auto layers = std::vector<const LayerSettings*>{&layer, &caster};
+    auto layers = std::vector<LayerSettings>{layer, caster};
     // Four combinations of settings are used (two transforms here, and drawShadowLayers is
     // called with two different destination data spaces) They're all rounded rect.
     // Three of these are cache misses that generate new shaders.
@@ -140,7 +140,7 @@
                                           }},
     };
 
-    auto layers = std::vector<const LayerSettings*>{&layer};
+    auto layers = std::vector<LayerSettings>{layer};
     for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
         layer.sourceDataspace = dataspace;
         // Cache shaders for both rects and round rects.
@@ -176,7 +176,7 @@
             .alpha = 0.5,
     };
 
-    auto layers = std::vector<const LayerSettings*>{&layer};
+    auto layers = std::vector<LayerSettings>{layer};
     for (auto transform : {mat4(), kScaleAndTranslate}) {
         layer.geometry.positionTransform = transform;
         for (float roundedCornersRadius : {0.0f, 50.f}) {
@@ -201,7 +201,7 @@
             .skipContentDraw = true,
     };
 
-    auto layers = std::vector<const LayerSettings*>{&layer};
+    auto layers = std::vector<LayerSettings>{layer};
     // Different blur code is invoked for radii less and greater than 30 pixels
     for (int radius : {9, 60}) {
         layer.backgroundBlurRadius = radius;
@@ -242,7 +242,7 @@
                     },
     };
 
-    auto layers = std::vector<const LayerSettings*>{&layer};
+    auto layers = std::vector<LayerSettings>{layer};
     for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
         layer.source = pixelSource;
         for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
@@ -289,7 +289,7 @@
 
     };
 
-    auto layers = std::vector<const LayerSettings*>{&layer};
+    auto layers = std::vector<LayerSettings>{layer};
     renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd());
 }
 
@@ -317,7 +317,7 @@
 
     };
 
-    auto layers = std::vector<const LayerSettings*>{&layer};
+    auto layers = std::vector<LayerSettings>{layer};
     renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd());
 }
 
@@ -429,7 +429,7 @@
         LayerSettings layer{
                 .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)},
         };
-        auto layers = std::vector<const LayerSettings*>{&layer};
+        auto layers = std::vector<LayerSettings>{layer};
         // call get() to make it synchronous
         renderengine
                 ->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd())
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index cb686a6..d5ec774 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -610,17 +610,18 @@
     AutoBackendTexture::CleanupManager& mMgr;
 };
 
-sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(
-        sk_sp<SkShader> shader,
-        const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha,
-        bool requiresLinearEffect) {
-    const auto stretchEffect = layer->stretchEffect;
+sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> shader,
+                                                              const LayerSettings& layer,
+                                                              const DisplaySettings& display,
+                                                              bool undoPremultipliedAlpha,
+                                                              bool requiresLinearEffect) {
+    const auto stretchEffect = layer.stretchEffect;
     // The given surface will be stretched by HWUI via matrix transformation
     // which gets similar results for most surfaces
     // Determine later on if we need to leverage the stertch shader within
     // surface flinger
     if (stretchEffect.hasEffect()) {
-        const auto targetBuffer = layer->source.buffer.buffer;
+        const auto targetBuffer = layer.source.buffer.buffer;
         const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
         if (graphicBuffer && shader) {
             shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
@@ -629,7 +630,7 @@
 
     if (requiresLinearEffect) {
         const ui::Dataspace inputDataspace =
-                mUseColorManagement ? layer->sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR;
+                mUseColorManagement ? layer.sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR;
         const ui::Dataspace outputDataspace =
                 mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR;
 
@@ -645,13 +646,13 @@
         } else {
             runtimeEffect = effectIter->second;
         }
-        float maxLuminance = layer->source.buffer.maxLuminanceNits;
+        float maxLuminance = layer.source.buffer.maxLuminanceNits;
         // If the buffer doesn't have a max luminance, treat it as SDR & use the display's SDR
         // white point
         if (maxLuminance <= 0.f) {
             maxLuminance = display.sdrWhitePointNits;
         }
-        return createLinearEffectShader(shader, effect, runtimeEffect, layer->colorTransform,
+        return createLinearEffectShader(shader, effect, runtimeEffect, layer.colorTransform,
                                         display.maxLuminance, maxLuminance);
     }
     return shader;
@@ -729,7 +730,7 @@
 
 void SkiaGLRenderEngine::drawLayersInternal(
         const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
-        const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
         const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
         base::unique_fd&& bufferFence) {
     ATRACE_NAME("SkiaGL::drawLayers");
@@ -801,11 +802,11 @@
             if (!layerHasBlur(layer, ctModifiesAlpha)) {
                 continue;
             }
-            if (layer->backgroundBlurRadius > 0 &&
-                layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) {
+            if (layer.backgroundBlurRadius > 0 &&
+                layer.backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) {
                 requiresCompositionLayer = true;
             }
-            for (auto region : layer->blurRegions) {
+            for (auto region : layer.blurRegions) {
                 if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) {
                     requiresCompositionLayer = true;
                 }
@@ -813,7 +814,7 @@
             if (requiresCompositionLayer) {
                 activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
                 canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
-                blurCompositionLayer = layer;
+                blurCompositionLayer = &layer;
                 break;
             }
         }
@@ -825,11 +826,11 @@
     initCanvas(canvas, display);
 
     for (const auto& layer : layers) {
-        ATRACE_FORMAT("DrawLayer: %s", layer->name.c_str());
+        ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str());
 
         if (kPrintLayerSettings) {
             std::stringstream ls;
-            PrintTo(*layer, &ls);
+            PrintTo(layer, &ls);
             auto debugs = ls.str();
             int pos = 0;
             while (pos < debugs.size()) {
@@ -839,7 +840,7 @@
         }
 
         sk_sp<SkImage> blurInput;
-        if (blurCompositionLayer == layer) {
+        if (blurCompositionLayer == &layer) {
             LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
             LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
 
@@ -878,17 +879,17 @@
         if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
             // Record the name of the layer if the capture is running.
             std::stringstream layerSettings;
-            PrintTo(*layer, &layerSettings);
+            PrintTo(layer, &layerSettings);
             // Store the LayerSettings in additional information.
-            canvas->drawAnnotation(SkRect::MakeEmpty(), layer->name.c_str(),
+            canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(),
                                    SkData::MakeWithCString(layerSettings.str().c_str()));
         }
         // Layers have a local transform that should be applied to them
-        canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());
+        canvas->concat(getSkM44(layer.geometry.positionTransform).asM33());
 
         const auto [bounds, roundRectClip] =
-                getBoundsAndClip(layer->geometry.boundaries, layer->geometry.roundedCornersCrop,
-                                 layer->geometry.roundedCornersRadius);
+                getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop,
+                                 layer.geometry.roundedCornersRadius);
         if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) {
             std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
 
@@ -909,20 +910,19 @@
 
             // TODO(b/182216890): Filter out empty layers earlier
             if (blurRect.width() > 0 && blurRect.height() > 0) {
-                if (layer->backgroundBlurRadius > 0) {
+                if (layer.backgroundBlurRadius > 0) {
                     ATRACE_NAME("BackgroundBlur");
-                    auto blurredImage =
-                            mBlurFilter->generate(grContext, layer->backgroundBlurRadius, blurInput,
-                                                  blurRect);
+                    auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius,
+                                                              blurInput, blurRect);
 
-                    cachedBlurs[layer->backgroundBlurRadius] = blurredImage;
+                    cachedBlurs[layer.backgroundBlurRadius] = blurredImage;
 
-                    mBlurFilter->drawBlurRegion(canvas, bounds, layer->backgroundBlurRadius, 1.0f,
+                    mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f,
                                                 blurRect, blurredImage, blurInput);
                 }
 
-                canvas->concat(getSkM44(layer->blurRegionTransform).asM33());
-                for (auto region : layer->blurRegions) {
+                canvas->concat(getSkM44(layer.blurRegionTransform).asM33());
+                for (auto region : layer.blurRegions) {
                     if (cachedBlurs[region.blurRadius] == nullptr) {
                         ATRACE_NAME("BlurRegion");
                         cachedBlurs[region.blurRadius] =
@@ -937,19 +937,18 @@
             }
         }
 
-        if (layer->shadow.length > 0) {
+        if (layer.shadow.length > 0) {
             // This would require a new parameter/flag to SkShadowUtils::DrawShadow
-            LOG_ALWAYS_FATAL_IF(layer->disableBlending, "Cannot disableBlending with a shadow");
+            LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow");
 
             SkRRect shadowBounds, shadowClip;
-            if (layer->geometry.boundaries == layer->shadow.boundaries) {
+            if (layer.geometry.boundaries == layer.shadow.boundaries) {
                 shadowBounds = bounds;
                 shadowClip = roundRectClip;
             } else {
                 std::tie(shadowBounds, shadowClip) =
-                        getBoundsAndClip(layer->shadow.boundaries,
-                                         layer->geometry.roundedCornersCrop,
-                                         layer->geometry.roundedCornersRadius);
+                        getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop,
+                                         layer.geometry.roundedCornersRadius);
             }
 
             // Technically, if bounds is a rect and roundRectClip is not empty,
@@ -960,18 +959,18 @@
             // looks more like the intent.
             const auto& rrect =
                     shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds;
-            drawShadow(canvas, rrect, layer->shadow);
+            drawShadow(canvas, rrect, layer.shadow);
         }
 
-        const bool requiresLinearEffect = layer->colorTransform != mat4() ||
+        const bool requiresLinearEffect = layer.colorTransform != mat4() ||
                 (mUseColorManagement &&
-                 needsToneMapping(layer->sourceDataspace, display.outputDataspace)) ||
+                 needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
                 (display.sdrWhitePointNits > 0.f &&
                  display.sdrWhitePointNits != display.maxLuminance);
 
         // quick abort from drawing the remaining portion of the layer
-        if (layer->skipContentDraw ||
-            (layer->alpha == 0 && !requiresLinearEffect && !layer->disableBlending &&
+        if (layer.skipContentDraw ||
+            (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending &&
              (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) {
             continue;
         }
@@ -981,13 +980,13 @@
         // management is a no-op.
         const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect)
                 ? dstDataspace
-                : layer->sourceDataspace;
+                : layer.sourceDataspace;
 
         SkPaint paint;
-        if (layer->source.buffer.buffer) {
+        if (layer.source.buffer.buffer) {
             ATRACE_NAME("DrawImage");
-            validateInputBufferUsage(layer->source.buffer.buffer->getBuffer());
-            const auto& item = layer->source.buffer;
+            validateInputBufferUsage(layer.source.buffer.buffer->getBuffer());
+            const auto& item = layer.source.buffer;
             std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
 
             if (const auto& iter = cache.find(item.buffer->getBuffer()->getId());
@@ -1006,8 +1005,8 @@
 
             // if the layer's buffer has a fence, then we must must respect the fence prior to using
             // the buffer.
-            if (layer->source.buffer.fence != nullptr) {
-                waitFence(layer->source.buffer.fence->get());
+            if (layer.source.buffer.fence != nullptr) {
+                waitFence(layer.source.buffer.fence->get());
             }
 
             // isOpaque means we need to ignore the alpha in the image,
@@ -1051,7 +1050,7 @@
 
             sk_sp<SkShader> shader;
 
-            if (layer->source.buffer.useTextureFiltering) {
+            if (layer.source.buffer.useTextureFiltering) {
                 shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
                                            SkSamplingOptions(
                                                    {SkFilterMode::kLinear, SkMipmapMode::kNone}),
@@ -1069,21 +1068,21 @@
             paint.setShader(createRuntimeEffectShader(shader, layer, display,
                                                       !item.isOpaque && item.usePremultipliedAlpha,
                                                       requiresLinearEffect));
-            paint.setAlphaf(layer->alpha);
+            paint.setAlphaf(layer.alpha);
         } else {
             ATRACE_NAME("DrawColor");
-            const auto color = layer->source.solidColor;
+            const auto color = layer.source.solidColor;
             sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
                                                                 .fG = color.g,
                                                                 .fB = color.b,
-                                                                .fA = layer->alpha},
+                                                                .fA = layer.alpha},
                                                       toSkColorSpace(layerDataspace));
             paint.setShader(createRuntimeEffectShader(shader, layer, display,
                                                       /* undoPremultipliedAlpha */ false,
                                                       requiresLinearEffect));
         }
 
-        if (layer->disableBlending) {
+        if (layer.disableBlending) {
             paint.setBlendMode(SkBlendMode::kSrc);
         }
 
@@ -1251,13 +1250,13 @@
     return {SkRRect::MakeRect(bounds), clip};
 }
 
-inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer,
+inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings& layer,
                                              bool colorTransformModifiesAlpha) {
-    if (layer->backgroundBlurRadius > 0 || layer->blurRegions.size()) {
+    if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) {
         // return false if the content is opaque and would therefore occlude the blur
-        const bool opaqueContent = !layer->source.buffer.buffer || layer->source.buffer.isOpaque;
-        const bool opaqueAlpha = layer->alpha == 1.0f && !colorTransformModifiesAlpha;
-        return layer->skipContentDraw || !(opaqueContent && opaqueAlpha);
+        const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque;
+        const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha;
+        return layer.skipContentDraw || !(opaqueContent && opaqueAlpha);
     }
     return false;
 }
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index e010c35..74ce651 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -74,7 +74,7 @@
     bool canSkipPostRenderCleanup() const override;
     void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
                             const DisplaySettings& display,
-                            const std::vector<const LayerSettings*>& layers,
+                            const std::vector<LayerSettings>& layers,
                             const std::shared_ptr<ExternalTexture>& buffer,
                             const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
 
@@ -92,7 +92,7 @@
     inline SkRect getSkRect(const Rect& layer);
     inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const FloatRect& bounds,
                                                         const FloatRect& crop, float cornerRadius);
-    inline bool layerHasBlur(const LayerSettings* layer, bool colorTransformModifiesAlpha);
+    inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha);
     inline SkColor getSkColor(const vec4& color);
     inline SkM44 getSkM44(const mat4& matrix);
     inline SkPoint3 getSkPoint3(const vec3& vector);
@@ -108,8 +108,7 @@
                     const ShadowSettings& shadowSettings);
     // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned.
     // Otherwise it returns the input shader.
-    sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader,
-                                              const LayerSettings* layer,
+    sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings& layer,
                                               const DisplaySettings& display,
                                               bool undoPremultipliedAlpha,
                                               bool requiresLinearEffect);
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index f61653b..eb65e83 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -55,7 +55,7 @@
 
     virtual void drawLayersInternal(
             const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
-            const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+            const DisplaySettings& display, const std::vector<LayerSettings>& layers,
             const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
             base::unique_fd&& bufferFence) override {
         resultPromise->set_value({NO_ERROR, base::unique_fd()});
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 694bda6..c2c05f4 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -417,10 +417,11 @@
                     DEFAULT_DISPLAY_HEIGHT - DEFAULT_DISPLAY_OFFSET);
     }
 
-    void invokeDraw(renderengine::DisplaySettings settings,
-                    std::vector<const renderengine::LayerSettings*> layers) {
+    void invokeDraw(const renderengine::DisplaySettings& settings,
+                    const std::vector<renderengine::LayerSettings>& layers) {
         std::future<renderengine::RenderEngineResult> result =
                 mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
+
         ASSERT_TRUE(result.valid());
         auto [status, fence] = result.get();
 
@@ -436,7 +437,7 @@
 
     void drawEmptyLayers() {
         renderengine::DisplaySettings settings;
-        std::vector<const renderengine::LayerSettings*> layers;
+        std::vector<renderengine::LayerSettings> layers;
         invokeDraw(settings, layers);
     }
 
@@ -629,7 +630,7 @@
     settings.clip = fullscreenRect();
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
     layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -637,7 +638,7 @@
     SourceVariant::fillColor(layer, r, g, b, this);
     layer.alpha = a;
 
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     invokeDraw(settings, layers);
 }
@@ -673,7 +674,7 @@
     settings.physicalDisplay = offsetRect();
     settings.clip = offsetRectAtZero();
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
     layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -681,7 +682,7 @@
     SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
     layer.alpha = 1.0f;
 
-    layers.push_back(&layer);
+    layers.push_back(layer);
     invokeDraw(settings, layers);
 }
 
@@ -708,7 +709,7 @@
     settings.clip = Rect(2, 2);
     settings.orientation = orientationFlag;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layerOne;
     layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -731,9 +732,9 @@
     SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this);
     layerThree.alpha = 1.0f;
 
-    layers.push_back(&layerOne);
-    layers.push_back(&layerTwo);
-    layers.push_back(&layerThree);
+    layers.push_back(layerOne);
+    layers.push_back(layerTwo);
+    layers.push_back(layerThree);
 
     invokeDraw(settings, layers);
 }
@@ -810,7 +811,7 @@
     settings.clip = Rect(2, 2);
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
     layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -821,7 +822,7 @@
     layer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
     layer.alpha = 1.0f;
 
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     invokeDraw(settings, layers);
 }
@@ -843,7 +844,7 @@
     settings.clip = Rect(1, 1);
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
     layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -860,7 +861,7 @@
     layer.alpha = 1.0f;
     layer.geometry.boundaries = Rect(1, 1).toFloatRect();
 
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     invokeDraw(settings, layers);
 }
@@ -877,7 +878,7 @@
     settings.physicalDisplay = fullscreenRect();
     settings.clip = Rect(1, 1);
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
     layer.geometry.boundaries = Rect(1, 1).toFloatRect();
@@ -890,7 +891,7 @@
 
     layer.geometry.boundaries = Rect(1, 1).toFloatRect();
 
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     invokeDraw(settings, layers);
 }
@@ -908,7 +909,7 @@
     settings.clip = fullscreenRect();
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
     layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -918,7 +919,7 @@
     SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
     layer.alpha = 1.0f;
 
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     invokeDraw(settings, layers);
 }
@@ -949,14 +950,14 @@
     settings.physicalDisplay = fullscreenRect();
     settings.clip = fullscreenRect();
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings backgroundLayer;
     backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
     SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this);
     backgroundLayer.alpha = 1.0f;
-    layers.push_back(&backgroundLayer);
+    layers.emplace_back(backgroundLayer);
 
     renderengine::LayerSettings leftLayer;
     leftLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -964,7 +965,7 @@
             Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect();
     SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this);
     leftLayer.alpha = 1.0f;
-    layers.push_back(&leftLayer);
+    layers.emplace_back(leftLayer);
 
     renderengine::LayerSettings blurLayer;
     blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -972,7 +973,7 @@
     blurLayer.backgroundBlurRadius = blurRadius;
     SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
     blurLayer.alpha = 0;
-    layers.push_back(&blurLayer);
+    layers.emplace_back(blurLayer);
 
     invokeDraw(settings, layers);
 
@@ -994,14 +995,14 @@
     settings.physicalDisplay = fullscreenRect();
     settings.clip = fullscreenRect();
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings backgroundLayer;
     backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
     SourceVariant::fillColor(backgroundLayer, 1.0f, 0.0f, 0.0f, this);
     backgroundLayer.alpha = 1.0f;
-    layers.push_back(&backgroundLayer);
+    layers.push_back(backgroundLayer);
 
     renderengine::LayerSettings blurLayer;
     blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1009,7 +1010,7 @@
     blurLayer.backgroundBlurRadius = blurRadius;
     SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
     blurLayer.alpha = 0;
-    layers.push_back(&blurLayer);
+    layers.push_back(blurLayer);
 
     invokeDraw(settings, layers);
 
@@ -1026,7 +1027,7 @@
     settings.clip = fullscreenRect();
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layersFirst;
+    std::vector<renderengine::LayerSettings> layersFirst;
 
     renderengine::LayerSettings layerOne;
     layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1035,14 +1036,14 @@
     SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
     layerOne.alpha = 0.2;
 
-    layersFirst.push_back(&layerOne);
+    layersFirst.push_back(layerOne);
     invokeDraw(settings, layersFirst);
     expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
     expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
                            DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                       0, 0, 0, 0);
 
-    std::vector<const renderengine::LayerSettings*> layersSecond;
+    std::vector<renderengine::LayerSettings> layersSecond;
     renderengine::LayerSettings layerTwo;
     layerTwo.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     layerTwo.geometry.boundaries =
@@ -1051,7 +1052,7 @@
     SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
     layerTwo.alpha = 1.0f;
 
-    layersSecond.push_back(&layerTwo);
+    layersSecond.push_back(layerTwo);
     invokeDraw(settings, layersSecond);
 
     expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
@@ -1066,7 +1067,7 @@
     settings.clip = Rect(1, 1);
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
     layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1102,7 +1103,7 @@
     layer.alpha = 1.0f;
     layer.geometry.boundaries = Rect(1, 1).toFloatRect();
 
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     invokeDraw(settings, layers);
 }
@@ -1118,7 +1119,7 @@
     // Here logical space is 1x1
     settings.clip = Rect(1, 1);
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
     const auto buf = allocateSourceBuffer(1, 1);
@@ -1141,7 +1142,7 @@
     layer.alpha = 0.5f;
     layer.geometry.boundaries = Rect(1, 1).toFloatRect();
 
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     invokeDraw(settings, layers);
 }
@@ -1157,7 +1158,7 @@
     // Here logical space is 1x1
     settings.clip = Rect(1, 1);
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
     const auto buf = allocateSourceBuffer(1, 1);
@@ -1180,7 +1181,7 @@
     layer.alpha = 0.5f;
     layer.geometry.boundaries = Rect(1, 1).toFloatRect();
 
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     invokeDraw(settings, layers);
 }
@@ -1199,7 +1200,7 @@
     settings.physicalDisplay = fullscreenRect();
     settings.clip = fullscreenRect();
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     // add background layer
     renderengine::LayerSettings bgLayer;
@@ -1208,7 +1209,7 @@
     ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f,
                                   backgroundColor.b / 255.0f, this);
     bgLayer.alpha = backgroundColor.a / 255.0f;
-    layers.push_back(&bgLayer);
+    layers.push_back(bgLayer);
 
     // add shadow layer
     renderengine::LayerSettings shadowLayer;
@@ -1216,14 +1217,14 @@
     shadowLayer.geometry.boundaries = castingLayer.geometry.boundaries;
     shadowLayer.alpha = castingLayer.alpha;
     shadowLayer.shadow = shadow;
-    layers.push_back(&shadowLayer);
+    layers.push_back(shadowLayer);
 
     // add layer casting the shadow
     renderengine::LayerSettings layer = castingLayer;
     layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
     SourceVariant::fillColor(layer, casterColor.r / 255.0f, casterColor.g / 255.0f,
                              casterColor.b / 255.0f, this);
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     invokeDraw(settings, layers);
 }
@@ -1236,7 +1237,7 @@
     settings.physicalDisplay = fullscreenRect();
     settings.clip = fullscreenRect();
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     // add background layer
     renderengine::LayerSettings bgLayer;
@@ -1245,7 +1246,7 @@
     ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f,
                                   backgroundColor.b / 255.0f, this);
     bgLayer.alpha = backgroundColor.a / 255.0f;
-    layers.push_back(&bgLayer);
+    layers.push_back(bgLayer);
 
     // add shadow layer
     renderengine::LayerSettings shadowLayer;
@@ -1255,7 +1256,7 @@
     shadowLayer.alpha = 1.0f;
     ColorSourceVariant::fillColor(shadowLayer, 0, 0, 0, this);
     shadowLayer.shadow = shadow;
-    layers.push_back(&shadowLayer);
+    layers.push_back(shadowLayer);
 
     invokeDraw(settings, layers);
 }
@@ -1291,8 +1292,8 @@
     // Transform the red color.
     bgLayer.colorTransform = mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
 
-    std::vector<const renderengine::LayerSettings*> layers;
-    layers.push_back(&bgLayer);
+    std::vector<renderengine::LayerSettings> layers;
+    layers.push_back(bgLayer);
 
     invokeDraw(settings, layers);
 
@@ -1306,11 +1307,11 @@
 
     renderengine::DisplaySettings settings;
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
     renderengine::LayerSettings layer;
     layer.geometry.boundaries = fullscreenRect().toFloatRect();
     BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
-    layers.push_back(&layer);
+    layers.push_back(layer);
     std::future<renderengine::RenderEngineResult> result =
             mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd());
 
@@ -1335,12 +1336,12 @@
     settings.physicalDisplay = fullscreenRect();
     settings.clip = fullscreenRect();
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
     renderengine::LayerSettings layer;
     layer.geometry.boundaries = fullscreenRect().toFloatRect();
     BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
     layer.alpha = 1.0;
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     std::future<renderengine::RenderEngineResult> result =
             mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd());
@@ -1743,12 +1744,12 @@
     settings.clip = fullscreenRect();
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
     renderengine::LayerSettings layer;
     layer.geometry.boundaries = fullscreenRect().toFloatRect();
     BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
     layer.alpha = 1.0;
-    layers.push_back(&layer);
+    layers.push_back(layer);
 
     std::future<renderengine::RenderEngineResult> resultOne =
             mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
@@ -1779,7 +1780,7 @@
     settings.clip = fullscreenRect();
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings redLayer;
     redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1790,7 +1791,7 @@
     redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
     redLayer.alpha = 1.0f;
 
-    layers.push_back(&redLayer);
+    layers.push_back(redLayer);
 
     // Green layer with 1/3 size.
     renderengine::LayerSettings greenLayer;
@@ -1805,7 +1806,7 @@
     greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f);
     greenLayer.alpha = 1.0f;
 
-    layers.push_back(&greenLayer);
+    layers.push_back(greenLayer);
 
     invokeDraw(settings, layers);
 
@@ -1828,7 +1829,7 @@
     settings.clip = fullscreenRect();
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings redLayer;
     redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1839,7 +1840,7 @@
     redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
     redLayer.alpha = 1.0f;
 
-    layers.push_back(&redLayer);
+    layers.push_back(redLayer);
 
     // Green layer with 1/2 size with parent crop rect.
     renderengine::LayerSettings greenLayer = redLayer;
@@ -1847,7 +1848,7 @@
             FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2);
     greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f);
 
-    layers.push_back(&greenLayer);
+    layers.push_back(greenLayer);
 
     invokeDraw(settings, layers);
 
@@ -1873,7 +1874,7 @@
     settings.clip = fullscreenRect();
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
 
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings redLayer;
     redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1884,7 +1885,7 @@
     redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
     redLayer.alpha = 1.0f;
 
-    layers.push_back(&redLayer);
+    layers.push_back(redLayer);
     invokeDraw(settings, layers);
 
     // Due to roundedCornersRadius, the top corners are untouched.
@@ -1923,7 +1924,7 @@
             .disableBlending = true,
     };
 
-    std::vector<const renderengine::LayerSettings*> layers{&redLayer, &clearLayer};
+    std::vector<renderengine::LayerSettings> layers{redLayer, clearLayer};
     invokeDraw(display, layers);
     expectBufferColor(rect, 0, 0, 0, 0);
 }
@@ -1971,7 +1972,7 @@
             .disableBlending = true,
     };
 
-    std::vector<const renderengine::LayerSettings*> layers{&redLayer, &greenLayer};
+    std::vector<renderengine::LayerSettings> layers{redLayer, greenLayer};
     invokeDraw(display, layers);
     expectBufferColor(rect, 0, 128, 0, 128);
 }
@@ -2017,7 +2018,7 @@
             .alpha = 1.0f,
     };
 
-    std::vector<const renderengine::LayerSettings*> layers{&greenLayer};
+    std::vector<renderengine::LayerSettings> layers{greenLayer};
     invokeDraw(display, layers);
 
     if (GetParam()->useColorManagement()) {
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 99250c1..db7e12b 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -172,20 +172,21 @@
 
 TEST_F(RenderEngineThreadedTest, drawLayers) {
     renderengine::DisplaySettings settings;
-    std::vector<const renderengine::LayerSettings*> layers;
+    std::vector<renderengine::LayerSettings> layers;
     std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
             renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine,
                                            renderengine::ExternalTexture::Usage::READABLE |
                                                    renderengine::ExternalTexture::Usage::WRITEABLE);
+
     base::unique_fd bufferFence;
 
     EXPECT_CALL(*mRenderEngine, drawLayersInternal)
             .WillOnce([&](const std::shared_ptr<std::promise<renderengine::RenderEngineResult>>&&
                                   resultPromise,
                           const renderengine::DisplaySettings&,
-                          const std::vector<const renderengine::LayerSettings*>&,
+                          const std::vector<renderengine::LayerSettings>&,
                           const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                          base::unique_fd &&) -> void {
+                          base::unique_fd&&) -> void {
                 resultPromise->set_value({NO_ERROR, base::unique_fd()});
             });
 
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index a549672..3d446e8 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -306,7 +306,7 @@
 
 void RenderEngineThreaded::drawLayersInternal(
         const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
-        const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
         const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
         base::unique_fd&& bufferFence) {
     resultPromise->set_value({NO_ERROR, base::unique_fd()});
@@ -314,19 +314,20 @@
 }
 
 std::future<RenderEngineResult> RenderEngineThreaded::drawLayers(
-        const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
         const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
         base::unique_fd&& bufferFence) {
     ATRACE_CALL();
     const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
     std::future<RenderEngineResult> resultFuture = resultPromise->get_future();
+    int fd = bufferFence.release();
     {
         std::lock_guard lock(mThreadMutex);
-        mFunctionCalls.push([resultPromise, &display, &layers, &buffer, useFramebufferCache,
-                             &bufferFence](renderengine::RenderEngine& instance) {
+        mFunctionCalls.push([resultPromise, display, layers, buffer, useFramebufferCache,
+                             fd](renderengine::RenderEngine& instance) {
             ATRACE_NAME("REThreaded::drawLayers");
             instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer,
-                                        useFramebufferCache, std::move(bufferFence));
+                                        useFramebufferCache, base::unique_fd(fd));
         });
     }
     mCondition.notify_one();
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 2303caa..0159cfa 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -57,7 +57,7 @@
     void cleanupPostRender() override;
 
     std::future<RenderEngineResult> drawLayers(const DisplaySettings& display,
-                                               const std::vector<const LayerSettings*>& layers,
+                                               const std::vector<LayerSettings>& layers,
                                                const std::shared_ptr<ExternalTexture>& buffer,
                                                const bool useFramebufferCache,
                                                base::unique_fd&& bufferFence) override;
@@ -73,7 +73,7 @@
     bool canSkipPostRenderCleanup() const override;
     void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
                             const DisplaySettings& display,
-                            const std::vector<const LayerSettings*>& layers,
+                            const std::vector<LayerSettings>& layers,
                             const std::shared_ptr<ExternalTexture>& buffer,
                             const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
 
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 75b2ba9..ea6de06 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -45,7 +45,7 @@
         "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
-        "android.hardware.power-V1-cpp",
+        "android.hardware.power-V2-cpp",
         "libbase",
         "libbinder",
         "libcutils",
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 52bd420..4e5d2d0 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -48,7 +48,9 @@
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
 
-void BufferQueueLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+void BufferQueueLayer::onLayerDisplayed(
+        std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
+    sp<Fence> releaseFence = new Fence(dup(futureRenderEngineResult.get().drawFence));
     mConsumer->setReleaseFence(releaseFence);
 
     // Prevent tracing the same release multiple times.
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index a3bd725..dfdb5c0 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -42,7 +42,8 @@
     // Implements Layer.
     const char* getType() const override { return "BufferQueueLayer"; }
 
-    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+    void onLayerDisplayed(
+            std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
 
     // If a buffer was replaced this frame, release the former buffer
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index fda7a92..c213570 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -70,69 +70,11 @@
     }
 }
 
-status_t BufferStateLayer::addReleaseFence(const sp<CallbackHandle>& ch,
-                                           const sp<Fence>& fence) {
-    if (ch == nullptr) {
-        return OK;
-    }
-    ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
-    if (!ch->previousReleaseFence.get()) {
-        ch->previousReleaseFence = fence;
-        return OK;
-    }
-
-    // Below logic is lifted from ConsumerBase.cpp:
-    // Check status of fences first because merging is expensive.
-    // Merging an invalid fence with any other fence results in an
-    // invalid fence.
-    auto currentStatus = ch->previousReleaseFence->getStatus();
-    if (currentStatus == Fence::Status::Invalid) {
-        ALOGE("Existing fence has invalid state, layer: %s", mName.c_str());
-        return BAD_VALUE;
-    }
-
-    auto incomingStatus = fence->getStatus();
-    if (incomingStatus == Fence::Status::Invalid) {
-        ALOGE("New fence has invalid state, layer: %s", mName.c_str());
-        ch->previousReleaseFence = fence;
-        return BAD_VALUE;
-    }
-
-    // If both fences are signaled or both are unsignaled, we need to merge
-    // them to get an accurate timestamp.
-    if (currentStatus == incomingStatus) {
-        char fenceName[32] = {};
-        snprintf(fenceName, 32, "%.28s", mName.c_str());
-        sp<Fence> mergedFence = Fence::merge(
-                fenceName, ch->previousReleaseFence, fence);
-        if (!mergedFence.get()) {
-            ALOGE("failed to merge release fences, layer: %s", mName.c_str());
-            // synchronization is broken, the best we can do is hope fences
-            // signal in order so the new fence will act like a union
-            ch->previousReleaseFence = fence;
-            return BAD_VALUE;
-        }
-        ch->previousReleaseFence = mergedFence;
-    } else if (incomingStatus == Fence::Status::Unsignaled) {
-        // If one fence has signaled and the other hasn't, the unsignaled
-        // fence will approximately correspond with the correct timestamp.
-        // There's a small race if both fences signal at about the same time
-        // and their statuses are retrieved with unfortunate timing. However,
-        // by this point, they will have both signaled and only the timestamp
-        // will be slightly off; any dependencies after this point will
-        // already have been met.
-        ch->previousReleaseFence = fence;
-    }
-    // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
-
-    return OK;
-}
-
 // -----------------------------------------------------------------------
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
-
+void BufferStateLayer::onLayerDisplayed(
+        std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) {
     // If a layer has been displayed again we may need to clear
     // the mLastClientComposition fence that we use for early release in setBuffer
     // (as we now have a new fence which won't pass through the client composition path in some cases
@@ -146,9 +88,6 @@
         mLastClientCompositionDisplayed = true;
     }
 
-    if (!releaseFence->isValid()) {
-        return;
-    }
     // The previous release fence notifies the client that SurfaceFlinger is done with the previous
     // buffer that was presented on this layer. The first transaction that came in this frame that
     // replaced the previous buffer on this layer needs this release fence, because the fence will
@@ -173,17 +112,17 @@
             break;
         }
     }
-    auto status = addReleaseFence(ch, releaseFence);
-    if (status != OK) {
-        ALOGE("Failed to add release fence for layer %s", getName().c_str());
-    }
-
-    mPreviousReleaseFence = releaseFence;
 
     // Prevent tracing the same release multiple times.
     if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
         mPreviousReleasedFrameNumber = mPreviousFrameNumber;
     }
+
+    if (ch != nullptr) {
+        ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
+        ch->previousReleaseFences.emplace_back(futureRenderEngineResult);
+        ch->name = mName;
+    }
 }
 
 void BufferStateLayer::onSurfaceFrameCreated(
@@ -231,9 +170,18 @@
     mFlinger->getTransactionCallbackInvoker().addCallbackHandles(
             mDrawingState.callbackHandles, jankData);
 
+    sp<Fence> releaseFence = Fence::NO_FENCE;
+    for (auto& handle : mDrawingState.callbackHandles) {
+        if (handle->releasePreviousBuffer &&
+            mDrawingState.releaseBufferEndpoint == handle->listener) {
+            releaseFence =
+                    handle->previousReleaseFence ? handle->previousReleaseFence : Fence::NO_FENCE;
+            break;
+        }
+    }
+
     mDrawingState.callbackHandles = {};
 
-    const sp<Fence>& releaseFence(mPreviousReleaseFence);
     std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(releaseFence);
     {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 87b68ea..eea700c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -39,7 +39,9 @@
     // Implements Layer.
     const char* getType() const override { return "BufferStateLayer"; }
 
-    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+    void onLayerDisplayed(
+            std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
+
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
 
     void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
@@ -115,8 +117,6 @@
     bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
                                  nsecs_t requestedPresentTime);
 
-    status_t addReleaseFence(const sp<CallbackHandle>& ch, const sp<Fence>& releaseFence);
-
     bool latchSidebandStream(bool& recomputeVisibleRegions) override;
 
     bool hasFrameUpdate() const override;
@@ -139,7 +139,6 @@
     std::shared_ptr<renderengine::ExternalTexture> getBufferFromBufferData(
             const BufferData& bufferData);
 
-    sp<Fence> mPreviousReleaseFence;
     ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
     uint64_t mPreviousReleasedFrameNumber = 0;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index f7b71cf..ac243c0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <future>
 #include <optional>
 #include <ostream>
 #include <unordered_set>
@@ -26,6 +27,7 @@
 #pragma clang diagnostic ignored "-Wextra"
 
 #include <renderengine/LayerSettings.h>
+#include <renderengine/RenderEngine.h>
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
@@ -151,7 +153,7 @@
             ClientCompositionTargetSettings&) = 0;
 
     // Called after the layer is displayed to update the presentation fence
-    virtual void onLayerDisplayed(const sp<Fence>&) = 0;
+    virtual void onLayerDisplayed(std::shared_future<renderengine::RenderEngineResult>) = 0;
 
     // Gets some kind of identifier for the layer for debug purposes.
     virtual const char* getDebugName() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index d215bda..16aebef 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -39,7 +39,7 @@
                  std::vector<compositionengine::LayerFE::LayerSettings>(
                          compositionengine::LayerFE::ClientCompositionTargetSettings&));
 
-    MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
+    MOCK_METHOD1(onLayerDisplayed, void(std::shared_future<renderengine::RenderEngineResult>));
 
     MOCK_CONST_METHOD0(getDebugName, const char*());
     MOCK_CONST_METHOD0(getSequence, int32_t());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index fad1fa7..6800004 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -27,6 +27,7 @@
 #include <compositionengine/impl/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <compositionengine/impl/planner/Planner.h>
+#include <ftl/future.h>
 
 #include <thread>
 
@@ -1097,12 +1098,12 @@
         setExpensiveRenderingExpected(true);
     }
 
-    std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
-    clientCompositionLayerPointers.reserve(clientCompositionLayers.size());
+    std::vector<renderengine::LayerSettings> clientRenderEngineLayers;
+    clientRenderEngineLayers.reserve(clientCompositionLayers.size());
     std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
-                   std::back_inserter(clientCompositionLayerPointers),
-                   [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings* {
-                       return &settings;
+                   std::back_inserter(clientRenderEngineLayers),
+                   [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings {
+                       return settings;
                    });
 
     const nsecs_t renderEngineStart = systemTime();
@@ -1115,7 +1116,7 @@
     const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay;
     auto [status, drawFence] =
             renderEngine
-                    .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex,
+                    .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex,
                                 useFramebufferCache, std::move(fd))
                     .get();
 
@@ -1295,8 +1296,10 @@
             releaseFence =
                     Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
         }
-
-        layer->getLayerFE().onLayerDisplayed(releaseFence);
+        layer->getLayerFE().onLayerDisplayed(
+                ftl::yield<renderengine::RenderEngineResult>(
+                        {NO_ERROR, base::unique_fd(releaseFence->dup())})
+                        .share());
     }
 
     // We've got a list of layers needing fences, that are disjoint with
@@ -1304,7 +1307,9 @@
     // supply them with the present fence.
     for (auto& weakLayer : mReleasedLayers) {
         if (auto layer = weakLayer.promote(); layer != nullptr) {
-            layer->onLayerDisplayed(frame.presentFence);
+            layer->onLayerDisplayed(ftl::yield<renderengine::RenderEngineResult>(
+                                            {NO_ERROR, base::unique_fd(frame.presentFence->dup())})
+                                            .share());
         }
     }
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index e6b716e..ec52e59 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -193,11 +193,6 @@
                              clientCompositionList.cend());
     }
 
-    std::vector<const renderengine::LayerSettings*> layerSettingsPointers;
-    std::transform(layerSettings.cbegin(), layerSettings.cend(),
-                   std::back_inserter(layerSettingsPointers),
-                   [](const renderengine::LayerSettings& settings) { return &settings; });
-
     renderengine::LayerSettings blurLayerSettings;
     if (mBlurLayer) {
         auto blurSettings = targetSettings;
@@ -212,7 +207,7 @@
         blurLayerSettings.name = std::string("blur layer");
         // Clear out the shadow settings
         blurLayerSettings.shadow = {};
-        layerSettingsPointers.push_back(&blurLayerSettings);
+        layerSettings.push_back(blurLayerSettings);
     }
 
     renderengine::LayerSettings holePunchSettings;
@@ -230,7 +225,7 @@
         holePunchSettings.disableBlending = true;
         holePunchSettings.alpha = 0.0f;
         holePunchSettings.name = std::string("hole punch layer");
-        layerSettingsPointers.push_back(&holePunchSettings);
+        layerSettings.push_back(holePunchSettings);
 
         // Add a solid background as the first layer in case there is no opaque
         // buffer behind the punch hole
@@ -239,7 +234,7 @@
         holePunchBackgroundSettings.geometry.boundaries = holePunchSettings.geometry.boundaries;
         holePunchBackgroundSettings.geometry.positionTransform =
                 holePunchSettings.geometry.positionTransform;
-        layerSettingsPointers.insert(layerSettingsPointers.begin(), &holePunchBackgroundSettings);
+        layerSettings.emplace(layerSettings.begin(), holePunchBackgroundSettings);
     }
 
     if (sDebugHighlighLayers) {
@@ -257,7 +252,7 @@
                 .alpha = half(0.05f),
         };
 
-        layerSettingsPointers.emplace_back(&highlight);
+        layerSettings.emplace_back(highlight);
     }
 
     auto texture = texturePool.borrowTexture();
@@ -273,8 +268,8 @@
     }
 
     auto [status, drawFence] = renderEngine
-                                       .drawLayers(displaySettings, layerSettingsPointers,
-                                                   texture->get(), false, std::move(bufferFence))
+                                       .drawLayers(displaySettings, layerSettings, texture->get(),
+                                                   false, std::move(bufferFence))
                                        .get();
 
     if (status == NO_ERROR) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index fc8cb50..db4151b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -29,11 +29,21 @@
     PowerAdvisor();
     ~PowerAdvisor() override;
 
-    MOCK_METHOD0(init, void());
-    MOCK_METHOD0(onBootFinished, void());
-    MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
-    MOCK_METHOD0(isUsingExpensiveRendering, bool());
-    MOCK_METHOD0(notifyDisplayUpdateImminent, void());
+    MOCK_METHOD(void, init, (), (override));
+    MOCK_METHOD(void, onBootFinished, (), (override));
+    MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected),
+                (override));
+    MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override));
+    MOCK_METHOD(void, notifyDisplayUpdateImminent, (), (override));
+    MOCK_METHOD(bool, usePowerHintSession, (), (override));
+    MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
+    MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
+    MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
+    MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
+                (override));
+    MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
+                (override));
+    MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 8f0028c..cf63ef5 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -24,6 +24,7 @@
 #include <compositionengine/mock/LayerFE.h>
 #include <compositionengine/mock/OutputLayer.h>
 #include <compositionengine/mock/RenderSurface.h>
+#include <ftl/future.h>
 #include <gtest/gtest.h>
 #include <renderengine/mock/RenderEngine.h>
 #include <ui/Rect.h>
@@ -2884,12 +2885,24 @@
     // are passed. This happens to work with the current implementation, but
     // would not survive certain calls like Fence::merge() which would return a
     // new instance.
-    EXPECT_CALL(*mLayer1.layerFE,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer1Fence.get()))));
-    EXPECT_CALL(*mLayer2.layerFE,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer2Fence.get()))));
-    EXPECT_CALL(*mLayer3.layerFE,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(layer3Fence.get()))));
+    base::unique_fd layer1FD(layer1Fence->dup());
+    base::unique_fd layer2FD(layer2Fence->dup());
+    base::unique_fd layer3FD(layer3Fence->dup());
+    EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_))
+            .WillOnce([&layer1FD](std::shared_future<renderengine::RenderEngineResult>
+                                          futureRenderEngineResult) {
+                EXPECT_EQ(layer1FD, futureRenderEngineResult.get().drawFence);
+            });
+    EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_))
+            .WillOnce([&layer2FD](std::shared_future<renderengine::RenderEngineResult>
+                                          futureRenderEngineResult) {
+                EXPECT_EQ(layer2FD, futureRenderEngineResult.get().drawFence);
+            });
+    EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_))
+            .WillOnce([&layer3FD](std::shared_future<renderengine::RenderEngineResult>
+                                          futureRenderEngineResult) {
+                EXPECT_EQ(layer3FD, futureRenderEngineResult.get().drawFence);
+            });
 
     mOutput.postFramebuffer();
 }
@@ -2915,9 +2928,9 @@
     // Fence::merge is called, and since none of the fences are actually valid,
     // Fence::NO_FENCE is returned and passed to each onLayerDisplayed() call.
     // This is the best we can do without creating a real kernel fence object.
-    EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(Fence::NO_FENCE));
-    EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(Fence::NO_FENCE));
-    EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(Fence::NO_FENCE));
+    EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed).WillOnce(Return());
+    EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed).WillOnce(Return());
+    EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed).WillOnce(Return());
 
     mOutput.postFramebuffer();
 }
@@ -2949,12 +2962,22 @@
     EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
 
     // Each released layer should be given the presentFence.
-    EXPECT_CALL(*releasedLayer1,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(presentFence.get()))));
-    EXPECT_CALL(*releasedLayer2,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(presentFence.get()))));
-    EXPECT_CALL(*releasedLayer3,
-                onLayerDisplayed(Property(&sp<Fence>::get, Eq(presentFence.get()))));
+    base::unique_fd layerFD(presentFence.get()->dup());
+    EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_))
+            .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
+                                         futureRenderEngineResult) {
+                EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+            });
+    EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_))
+            .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
+                                         futureRenderEngineResult) {
+                EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+            });
+    EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_))
+            .WillOnce([&layerFD](std::shared_future<renderengine::RenderEngineResult>
+                                         futureRenderEngineResult) {
+                EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence);
+            });
 
     mOutput.postFramebuffer();
 
@@ -3131,9 +3154,9 @@
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
     EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _))
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
-                                const std::vector<const renderengine::LayerSettings*>&,
+                                const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd &&)
+                                base::unique_fd&&)
                                     -> std::future<renderengine::RenderEngineResult> {
                 return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
             });
@@ -3161,11 +3184,11 @@
                     }));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
-                                const std::vector<const renderengine::LayerSettings*>&,
+                                const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd &&)
+                                base::unique_fd&&)
                                     -> std::future<renderengine::RenderEngineResult> {
                 return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
             });
@@ -3196,11 +3219,11 @@
                     }));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, true, _))
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
-                                const std::vector<const renderengine::LayerSettings*>&,
+                                const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd &&)
+                                base::unique_fd&&)
                                     -> std::future<renderengine::RenderEngineResult> {
                 return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
             });
@@ -3226,7 +3249,7 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .Times(2)
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))))
@@ -3258,7 +3281,7 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -3294,11 +3317,11 @@
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
             .WillOnce(Return(mOutputBuffer))
             .WillOnce(Return(otherOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .WillRepeatedly([&](const renderengine::DisplaySettings&,
-                                const std::vector<const renderengine::LayerSettings*>&,
+                                const std::vector<renderengine::LayerSettings>&,
                                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                                base::unique_fd &&)
+                                base::unique_fd&&)
                                     -> std::future<renderengine::RenderEngineResult> {
                 return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
             });
@@ -3330,10 +3353,10 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r3), _, false, _))
             .WillOnce(Return(ByMove(
                     futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
 
@@ -3487,9 +3510,9 @@
         EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
                 .WillRepeatedly(
                         [&](const renderengine::DisplaySettings&,
-                            const std::vector<const renderengine::LayerSettings*>&,
+                            const std::vector<renderengine::LayerSettings>&,
                             const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                            base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                            base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
                             return futureOf<renderengine::RenderEngineResult>(
                                     {NO_ERROR, base::unique_fd()});
                         });
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index ecb05f8..42b3d97 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -346,15 +346,15 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
         EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
         EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
                   displaySettings.orientation);
-        EXPECT_EQ(0.5f, layers[0]->alpha);
-        EXPECT_EQ(0.75f, layers[1]->alpha);
+        EXPECT_EQ(0.5f, layers[0].alpha);
+        EXPECT_EQ(0.75f, layers[1].alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
     };
@@ -398,15 +398,15 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
         EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
         EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
                   displaySettings.orientation);
-        EXPECT_EQ(0.5f, layers[0]->alpha);
-        EXPECT_EQ(0.75f, layers[1]->alpha);
+        EXPECT_EQ(0.5f, layers[0].alpha);
+        EXPECT_EQ(0.75f, layers[1].alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -453,15 +453,15 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings& displaySettings,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
         EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
         EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
                   displaySettings.orientation);
-        EXPECT_EQ(0.5f, layers[0]->alpha);
-        EXPECT_EQ(0.75f, layers[1]->alpha);
+        EXPECT_EQ(0.5f, layers[0].alpha);
+        EXPECT_EQ(0.75f, layers[1].alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -656,26 +656,26 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings&,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         // If the highlight layer is enabled, it will increase the size by 1.
         // We're interested in the third layer either way.
         EXPECT_GE(layers.size(), 4u);
         {
-            const auto* holePunchSettings = layers[3];
-            EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
-            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
-            EXPECT_TRUE(holePunchSettings->disableBlending);
-            EXPECT_EQ(0.0f, holePunchSettings->alpha);
+            const auto holePunchSettings = layers[3];
+            EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer);
+            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor);
+            EXPECT_TRUE(holePunchSettings.disableBlending);
+            EXPECT_EQ(0.0f, holePunchSettings.alpha);
         }
 
         {
-            const auto* holePunchBackgroundSettings = layers[0];
-            EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer);
-            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor);
-            EXPECT_FALSE(holePunchBackgroundSettings->disableBlending);
-            EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
+            const auto holePunchBackgroundSettings = layers[0];
+            EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer);
+            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor);
+            EXPECT_FALSE(holePunchBackgroundSettings.disableBlending);
+            EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha);
         }
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -717,27 +717,27 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings&,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         // If the highlight layer is enabled, it will increase the size by 1.
         // We're interested in the third layer either way.
         EXPECT_GE(layers.size(), 4u);
 
         {
-            const auto* holePunchSettings = layers[3];
-            EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer);
-            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor);
-            EXPECT_TRUE(holePunchSettings->disableBlending);
-            EXPECT_EQ(0.0f, holePunchSettings->alpha);
+            const auto holePunchSettings = layers[3];
+            EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer);
+            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor);
+            EXPECT_TRUE(holePunchSettings.disableBlending);
+            EXPECT_EQ(0.0f, holePunchSettings.alpha);
         }
 
         {
-            const auto* holePunchBackgroundSettings = layers[0];
-            EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer);
-            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor);
-            EXPECT_FALSE(holePunchBackgroundSettings->disableBlending);
-            EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
+            const auto holePunchBackgroundSettings = layers[0];
+            EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer);
+            EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor);
+            EXPECT_FALSE(holePunchBackgroundSettings.disableBlending);
+            EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha);
         }
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
@@ -867,16 +867,16 @@
 
     const auto drawLayers =
             [&](const renderengine::DisplaySettings&,
-                const std::vector<const renderengine::LayerSettings*>& layers,
+                const std::vector<renderengine::LayerSettings>& layers,
                 const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
         // If the highlight layer is enabled, it will increase the size by 1.
         // We're interested in the third layer either way.
         EXPECT_GE(layers.size(), 3u);
-        const auto* blurSettings = layers[2];
-        EXPECT_TRUE(blurSettings->skipContentDraw);
-        EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings->source.solidColor);
-        EXPECT_EQ(0.0f, blurSettings->alpha);
+        const auto blurSettings = layers[2];
+        EXPECT_TRUE(blurSettings.skipContentDraw);
+        EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings.source.solidColor);
+        EXPECT_EQ(0.0f, blurSettings.alpha);
 
         return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
     };
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index bb2888e..02d0658 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -166,4 +166,15 @@
     }
 }
 
+inline std::string to_string(hardware::graphics::composer::hal::Vsync vsync) {
+    switch (vsync) {
+        case hardware::graphics::composer::hal::Vsync::ENABLE:
+            return "Enable";
+        case hardware::graphics::composer::hal::Vsync::DISABLE:
+            return "Disable";
+        default:
+            return "Unknown";
+    }
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 1765caf..5c2390e 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -19,7 +19,10 @@
 #undef LOG_TAG
 #define LOG_TAG "PowerAdvisor"
 
+#include <unistd.h>
 #include <cinttypes>
+#include <cstdint>
+#include <optional>
 
 #include <android-base/properties.h>
 #include <utils/Log.h>
@@ -27,6 +30,9 @@
 
 #include <android/hardware/power/1.3/IPower.h>
 #include <android/hardware/power/IPower.h>
+#include <android/hardware/power/IPowerHintSession.h>
+#include <android/hardware/power/WorkDuration.h>
+
 #include <binder/IServiceManager.h>
 
 #include "../SurfaceFlingerProperties.h"
@@ -47,10 +53,14 @@
 
 using android::hardware::power::Boost;
 using android::hardware::power::IPower;
+using android::hardware::power::IPowerHintSession;
 using android::hardware::power::Mode;
-using base::GetIntProperty;
+using android::hardware::power::WorkDuration;
+
 using scheduler::OneShotTimer;
 
+class AidlPowerHalWrapper;
+
 PowerAdvisor::~PowerAdvisor() = default;
 
 namespace {
@@ -83,6 +93,13 @@
 
 void PowerAdvisor::onBootFinished() {
     mBootFinished.store(true);
+    {
+        std::lock_guard lock(mPowerHalMutex);
+        HalWrapper* halWrapper = getPowerHal();
+        if (halWrapper != nullptr && usePowerHintSession()) {
+            mPowerHintSessionRunning = halWrapper->startPowerHintSession();
+        }
+    }
 }
 
 void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
@@ -136,6 +153,80 @@
     }
 }
 
+// checks both if it supports and if it's enabled
+bool PowerAdvisor::usePowerHintSession() {
+    // uses cached value since the underlying support and flag are unlikely to change at runtime
+    ALOGE_IF(!mPowerHintEnabled.has_value(), "Power hint session cannot be used before boot!");
+    return mPowerHintEnabled.value_or(false) && supportsPowerHintSession();
+}
+
+bool PowerAdvisor::supportsPowerHintSession() {
+    // cache to avoid needing lock every time
+    if (!mSupportsPowerHint.has_value()) {
+        std::lock_guard lock(mPowerHalMutex);
+        HalWrapper* const halWrapper = getPowerHal();
+        mSupportsPowerHint = halWrapper->supportsPowerHintSession();
+    }
+    return *mSupportsPowerHint;
+}
+
+bool PowerAdvisor::isPowerHintSessionRunning() {
+    return mPowerHintSessionRunning;
+}
+
+void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) {
+    // we check "supports" here not "usePowerHintSession" because this needs to work
+    // before the session is actually running, and "use" will always fail before boot
+    // we store the values passed in before boot to start the session with during onBootFinished
+    if (!supportsPowerHintSession()) {
+        ALOGV("Power hint session target duration cannot be set, skipping");
+        return;
+    }
+    {
+        std::lock_guard lock(mPowerHalMutex);
+        HalWrapper* const halWrapper = getPowerHal();
+        if (halWrapper != nullptr) {
+            halWrapper->setTargetWorkDuration(targetDurationNanos);
+        }
+    }
+}
+
+void PowerAdvisor::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) {
+    // we check "supports" here not "usePowerHintSession" because this needs to wsork
+    // before the session is actually running, and "use" will always fail before boot.
+    // we store the values passed in before boot to start the session with during onBootFinished
+    if (!supportsPowerHintSession()) {
+        ALOGV("Power hint session thread ids cannot be set, skipping");
+        return;
+    }
+    {
+        std::lock_guard lock(mPowerHalMutex);
+        HalWrapper* const halWrapper = getPowerHal();
+        if (halWrapper != nullptr) {
+            halWrapper->setPowerHintSessionThreadIds(const_cast<std::vector<int32_t>&>(threadIds));
+        }
+    }
+}
+
+void PowerAdvisor::sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) {
+    if (!mBootFinished || !usePowerHintSession()) {
+        ALOGV("Actual work duration power hint cannot be sent, skipping");
+        return;
+    }
+    {
+        std::lock_guard lock(mPowerHalMutex);
+        HalWrapper* const halWrapper = getPowerHal();
+        if (halWrapper != nullptr) {
+            halWrapper->sendActualWorkDuration(actualDurationNanos, timeStampNanos);
+        }
+    }
+}
+
+// needs to be set after the flag is known but before PowerAdvisor enters onBootFinished
+void PowerAdvisor::enablePowerHint(bool enabled) {
+    mPowerHintEnabled = enabled;
+}
+
 class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
 public:
     HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
@@ -178,6 +269,26 @@
         return true;
     }
 
+    bool supportsPowerHintSession() override { return false; }
+
+    bool isPowerHintSessionRunning() override { return false; }
+
+    void restartPowerHintSession() override {}
+
+    void setPowerHintSessionThreadIds(const std::vector<int32_t>&) override {}
+
+    bool startPowerHintSession() override { return false; }
+
+    void setTargetWorkDuration(int64_t) override {}
+
+    void sendActualWorkDuration(int64_t, nsecs_t) override {}
+
+    bool shouldReconnectHAL() override { return false; }
+
+    std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; }
+
+    std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; }
+
 private:
     const sp<V1_3::IPower> mPowerHal = nullptr;
 };
@@ -195,9 +306,21 @@
         if (!ret.isOk()) {
             mHasDisplayUpdateImminent = false;
         }
+
+        // This just gives a number not a binder status, so no .isOk()
+        mSupportsPowerHints = mPowerHal->getInterfaceVersion() >= 2;
+
+        if (mSupportsPowerHints) {
+            mPowerHintQueue.reserve(MAX_QUEUE_SIZE);
+        }
     }
 
-    ~AidlPowerHalWrapper() override = default;
+    ~AidlPowerHalWrapper() override {
+        if (mPowerHintSession != nullptr) {
+            mPowerHintSession->close();
+            mPowerHintSession = nullptr;
+        }
+    };
 
     static std::unique_ptr<HalWrapper> connect() {
         // This only waits if the service is actually declared
@@ -232,10 +355,147 @@
         return ret.isOk();
     }
 
+    // only version 2+ of the aidl supports power hint sessions, hidl has no support
+    bool supportsPowerHintSession() override { return mSupportsPowerHints; }
+
+    bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; }
+
+    void closePowerHintSession() {
+        if (mPowerHintSession != nullptr) {
+            mPowerHintSession->close();
+            mPowerHintSession = nullptr;
+        }
+    }
+
+    void restartPowerHintSession() {
+        closePowerHintSession();
+        startPowerHintSession();
+    }
+
+    void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override {
+        if (threadIds != mPowerHintThreadIds) {
+            mPowerHintThreadIds = threadIds;
+            if (isPowerHintSessionRunning()) {
+                restartPowerHintSession();
+            }
+        }
+    }
+
+    bool startPowerHintSession() override {
+        if (mPowerHintSession != nullptr || !mPowerHintTargetDuration.has_value() ||
+            mPowerHintThreadIds.empty()) {
+            ALOGV("Cannot start power hint session, skipping");
+            return false;
+        }
+        auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
+                                                mPowerHintThreadIds, *mPowerHintTargetDuration,
+                                                &mPowerHintSession);
+        if (!ret.isOk()) {
+            ALOGW("Failed to start power hint session with error: %s",
+                  ret.exceptionToString(ret.exceptionCode()).c_str());
+            // Indicate to the poweradvisor that this wrapper likely needs to be remade
+            mShouldReconnectHal = true;
+        }
+        return isPowerHintSessionRunning();
+    }
+
+    bool shouldSetTargetDuration(int64_t targetDurationNanos) {
+        if (!mLastTargetDurationSent.has_value()) {
+            return true;
+        }
+
+        // report if the change in target from our last submission to now exceeds the threshold
+        return abs(1.0 -
+                   static_cast<double>(*mLastTargetDurationSent) /
+                           static_cast<double>(targetDurationNanos)) >=
+                ALLOWED_TARGET_DEVIATION_PERCENT;
+    }
+
+    void setTargetWorkDuration(int64_t targetDurationNanos) override {
+        mPowerHintTargetDuration = targetDurationNanos;
+        if (shouldSetTargetDuration(targetDurationNanos) && isPowerHintSessionRunning()) {
+            mLastTargetDurationSent = targetDurationNanos;
+            auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
+            if (!ret.isOk()) {
+                ALOGW("Failed to set power hint target work duration with error: %s",
+                      ret.exceptionMessage().c_str());
+                mShouldReconnectHal = true;
+            }
+        }
+    }
+
+    bool shouldReportActualDurationsNow() {
+        // report if we have never reported before or have exceeded the max queue size
+        if (!mLastMessageReported.has_value() || mPowerHintQueue.size() >= MAX_QUEUE_SIZE) {
+            return true;
+        }
+
+        // duration of most recent timing
+        const double mostRecentActualDuration =
+                static_cast<double>(mPowerHintQueue.back().durationNanos);
+        // duration of the last timing actually reported to the powerhal
+        const double lastReportedActualDuration =
+                static_cast<double>(mLastMessageReported->durationNanos);
+
+        // report if the change in duration from then to now exceeds the threshold
+        return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
+                ALLOWED_ACTUAL_DEVIATION_PERCENT;
+    }
+
+    void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override {
+        if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
+            ALOGV("Failed to send actual work duration, skipping");
+            return;
+        }
+
+        WorkDuration duration;
+        duration.durationNanos = actualDurationNanos;
+        duration.timeStampNanos = timeStampNanos;
+        mPowerHintQueue.push_back(duration);
+
+        // This rate limiter queues similar duration reports to the powerhal into
+        // batches to avoid excessive binder calls. The criteria to send a given batch
+        // are outlined in shouldReportActualDurationsNow()
+        if (shouldReportActualDurationsNow()) {
+            auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
+            if (!ret.isOk()) {
+                ALOGW("Failed to report actual work durations with error: %s",
+                      ret.exceptionMessage().c_str());
+                mShouldReconnectHal = true;
+            }
+            mPowerHintQueue.clear();
+            mLastMessageReported = duration;
+        }
+    }
+
+    bool shouldReconnectHAL() override { return mShouldReconnectHal; }
+
+    std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; }
+
+    std::optional<int64_t> getTargetWorkDuration() override { return mPowerHintTargetDuration; }
+
 private:
+    // max number of messages allowed in mPowerHintQueue before reporting is forced
+    static constexpr int32_t MAX_QUEUE_SIZE = 15;
+    // max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
+    static constexpr double ALLOWED_ACTUAL_DEVIATION_PERCENT = 0.1;
+    // max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
+    static constexpr double ALLOWED_TARGET_DEVIATION_PERCENT = 0.05;
+
     const sp<IPower> mPowerHal = nullptr;
     bool mHasExpensiveRendering = false;
     bool mHasDisplayUpdateImminent = false;
+    bool mShouldReconnectHal = false; // used to indicate an error state and need for reconstruction
+    // This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
+    sp<IPowerHintSession> mPowerHintSession = nullptr;
+    std::vector<WorkDuration> mPowerHintQueue;
+    // halwrapper owns these values so we can init when we want and reconnect if broken
+    std::optional<int64_t> mPowerHintTargetDuration;
+    std::vector<int32_t> mPowerHintThreadIds;
+    // keep track of the last messages sent for rate limiter change detection
+    std::optional<WorkDuration> mLastMessageReported;
+    std::optional<int64_t> mLastTargetDurationSent;
+    bool mSupportsPowerHints;
 };
 
 PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
@@ -246,6 +506,15 @@
         return nullptr;
     }
 
+    // grab old hint session values before we destroy any existing wrapper
+    std::vector<int32_t> oldPowerHintSessionThreadIds;
+    std::optional<int64_t> oldTargetWorkDuration;
+
+    if (sHalWrapper != nullptr) {
+        oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds();
+        oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration();
+    }
+
     // If we used to have a HAL, but it stopped responding, attempt to reconnect
     if (mReconnectPowerHal) {
         sHalWrapper = nullptr;
@@ -253,15 +522,34 @@
     }
 
     if (sHalWrapper != nullptr) {
-        return sHalWrapper.get();
+        auto wrapper = sHalWrapper.get();
+        // if the wrapper is fine, return it, but if it indicates a reconnect, remake it
+        if (!wrapper->shouldReconnectHAL()) {
+            return wrapper;
+        }
+        sHalWrapper = nullptr;
     }
 
+    // at this point, we know for sure there is no running session
+    mPowerHintSessionRunning = false;
+
     // First attempt to connect to the AIDL Power HAL
     sHalWrapper = AidlPowerHalWrapper::connect();
 
     // If that didn't succeed, attempt to connect to the HIDL Power HAL
     if (sHalWrapper == nullptr) {
         sHalWrapper = HidlPowerHalWrapper::connect();
+    } else { // if AIDL, pass on any existing hint session values
+        // thread ids always safe to set
+        sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
+        // only set duration and start if duration is defined
+        if (oldTargetWorkDuration.has_value()) {
+            sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration);
+            // only start if possible to run and both threadids and duration are defined
+            if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) {
+                mPowerHintSessionRunning = sHalWrapper->startPowerHintSession();
+            }
+        }
     }
 
     // If we make it to this point and still don't have a HAL, it's unlikely we
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index f2d0766..b8fd17d 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -40,6 +40,13 @@
     virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
     virtual bool isUsingExpensiveRendering() = 0;
     virtual void notifyDisplayUpdateImminent() = 0;
+    virtual bool usePowerHintSession() = 0;
+    virtual bool supportsPowerHintSession() = 0;
+    virtual bool isPowerHintSessionRunning() = 0;
+    virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0;
+    virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0;
+    virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) = 0;
+    virtual void enablePowerHint(bool enabled) = 0;
 };
 
 namespace impl {
@@ -54,6 +61,17 @@
 
         virtual bool setExpensiveRendering(bool enabled) = 0;
         virtual bool notifyDisplayUpdateImminent() = 0;
+        virtual bool supportsPowerHintSession() = 0;
+        virtual bool isPowerHintSessionRunning() = 0;
+        virtual void restartPowerHintSession() = 0;
+        virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0;
+        virtual bool startPowerHintSession() = 0;
+        virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0;
+        virtual void sendActualWorkDuration(int64_t actualDurationNanos,
+                                            nsecs_t timeStampNanos) = 0;
+        virtual bool shouldReconnectHAL() = 0;
+        virtual std::vector<int32_t> getPowerHintSessionThreadIds() = 0;
+        virtual std::optional<int64_t> getTargetWorkDuration() = 0;
     };
 
     PowerAdvisor(SurfaceFlinger& flinger);
@@ -62,8 +80,15 @@
     void init() override;
     void onBootFinished() override;
     void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
-    bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; }
+    bool isUsingExpensiveRendering() override { return mNotifiedExpensiveRendering; };
     void notifyDisplayUpdateImminent() override;
+    bool usePowerHintSession() override;
+    bool supportsPowerHintSession() override;
+    bool isPowerHintSessionRunning() override;
+    void setTargetWorkDuration(int64_t targetDurationNanos) override;
+    void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
+    void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) override;
+    void enablePowerHint(bool enabled) override;
 
 private:
     HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
@@ -71,6 +96,9 @@
     std::mutex mPowerHalMutex;
 
     std::atomic_bool mBootFinished = false;
+    std::optional<bool> mPowerHintEnabled;
+    std::optional<bool> mSupportsPowerHint;
+    bool mPowerHintSessionRunning = false;
 
     std::unordered_set<DisplayId> mExpensiveDisplays;
     bool mNotifiedExpensiveRendering = false;
diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h
index e9f06e5..639b3e5 100644
--- a/services/surfaceflinger/Fps.h
+++ b/services/surfaceflinger/Fps.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 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.
@@ -19,94 +19,110 @@
 #include <cmath>
 #include <ostream>
 #include <string>
+#include <type_traits>
 
 #include <android-base/stringprintf.h>
 #include <utils/Timers.h>
 
 namespace android {
 
-// Value which represents "frames per second". This class is a wrapper around
-// float, providing some useful utilities, such as comparisons with tolerance
-// and converting between period duration and frequency.
+// Frames per second, stored as floating-point frequency. Provides conversion from/to period in
+// nanoseconds, and relational operators with precision threshold.
+//
+//     const Fps fps = 60_Hz;
+//
+//     using namespace fps_approx_ops;
+//     assert(fps == Fps::fromPeriodNsecs(16'666'667));
+//
 class Fps {
 public:
-    static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); }
+    constexpr Fps() = default;
 
-    Fps() = default;
-    explicit constexpr Fps(float fps)
-          : fps(fps), period(fps == 0.0f ? 0 : static_cast<nsecs_t>(1e9f / fps)) {}
-
-    constexpr float getValue() const { return fps; }
-
-    constexpr nsecs_t getPeriodNsecs() const { return period; }
-
-    bool equalsWithMargin(const Fps& other) const { return std::abs(fps - other.fps) < kMargin; }
-
-    // DO NOT use for std::sort. Instead use comparesLess().
-    bool lessThanWithMargin(const Fps& other) const { return fps + kMargin < other.fps; }
-
-    bool greaterThanWithMargin(const Fps& other) const { return fps > other.fps + kMargin; }
-
-    bool lessThanOrEqualWithMargin(const Fps& other) const { return !greaterThanWithMargin(other); }
-
-    bool greaterThanOrEqualWithMargin(const Fps& other) const { return !lessThanWithMargin(other); }
-
-    bool isValid() const { return fps > 0.0f; }
-
-    int getIntValue() const { return static_cast<int>(std::round(fps)); }
-
-    // Use this comparator for sorting. Using a comparator with margins can
-    // cause std::sort to crash.
-    inline static bool comparesLess(const Fps& left, const Fps& right) {
-        return left.fps < right.fps;
+    static constexpr Fps fromValue(float frequency) {
+        return frequency > 0.f ? Fps(frequency, static_cast<nsecs_t>(1e9f / frequency)) : Fps();
     }
 
-    // Compares two FPS with margin.
-    // Transitivity is not guaranteed, i.e. a==b and b==c doesn't imply a==c.
-    // DO NOT use with hash maps. Instead use EqualsInBuckets.
-    struct EqualsWithMargin {
-        bool operator()(const Fps& left, const Fps& right) const {
-            return left.equalsWithMargin(right);
-        }
-    };
-
-    // Equals comparator which can be used with hash maps.
-    // It's guaranteed that if two elements are equal, then their hashes are equal.
-    struct EqualsInBuckets {
-        bool operator()(const Fps& left, const Fps& right) const {
-            return left.getBucket() == right.getBucket();
-        }
-    };
-
-    inline friend std::string to_string(const Fps& fps) {
-        return base::StringPrintf("%.2ffps", fps.fps);
+    static constexpr Fps fromPeriodNsecs(nsecs_t period) {
+        return period > 0 ? Fps(1e9f / period, period) : Fps();
     }
 
-    inline friend std::ostream& operator<<(std::ostream& os, const Fps& fps) {
-        return os << to_string(fps);
-    }
+    constexpr bool isValid() const { return mFrequency > 0.f; }
+
+    constexpr float getValue() const { return mFrequency; }
+    int getIntValue() const { return static_cast<int>(std::round(mFrequency)); }
+
+    constexpr nsecs_t getPeriodNsecs() const { return mPeriod; }
 
 private:
-    friend std::hash<android::Fps>;
+    constexpr Fps(float frequency, nsecs_t period) : mFrequency(frequency), mPeriod(period) {}
 
-    constexpr Fps(float fps, nsecs_t period) : fps(fps), period(period) {}
-
-    float getBucket() const { return std::round(fps / kMargin); }
-
-    static constexpr float kMargin = 0.001f;
-    float fps = 0;
-    nsecs_t period = 0;
+    float mFrequency = 0.f;
+    nsecs_t mPeriod = 0;
 };
 
 static_assert(std::is_trivially_copyable_v<Fps>);
 
-} // namespace android
+constexpr Fps operator""_Hz(unsigned long long frequency) {
+    return Fps::fromValue(static_cast<float>(frequency));
+}
 
-namespace std {
-template <>
-struct hash<android::Fps> {
-    std::size_t operator()(const android::Fps& fps) const {
-        return std::hash<float>()(fps.getBucket());
-    }
+constexpr Fps operator""_Hz(long double frequency) {
+    return Fps::fromValue(static_cast<float>(frequency));
+}
+
+inline bool isStrictlyLess(Fps lhs, Fps rhs) {
+    return lhs.getValue() < rhs.getValue();
+}
+
+// Does not satisfy equivalence relation.
+inline bool isApproxEqual(Fps lhs, Fps rhs) {
+    // TODO(b/185536303): Replace with ULP distance.
+    return std::abs(lhs.getValue() - rhs.getValue()) < 0.001f;
+}
+
+// Does not satisfy strict weak order.
+inline bool isApproxLess(Fps lhs, Fps rhs) {
+    return isStrictlyLess(lhs, rhs) && !isApproxEqual(lhs, rhs);
+}
+
+namespace fps_approx_ops {
+
+inline bool operator==(Fps lhs, Fps rhs) {
+    return isApproxEqual(lhs, rhs);
+}
+
+inline bool operator<(Fps lhs, Fps rhs) {
+    return isApproxLess(lhs, rhs);
+}
+
+inline bool operator!=(Fps lhs, Fps rhs) {
+    return !isApproxEqual(lhs, rhs);
+}
+
+inline bool operator>(Fps lhs, Fps rhs) {
+    return isApproxLess(rhs, lhs);
+}
+
+inline bool operator<=(Fps lhs, Fps rhs) {
+    return !isApproxLess(rhs, lhs);
+}
+
+inline bool operator>=(Fps lhs, Fps rhs) {
+    return !isApproxLess(lhs, rhs);
+}
+
+} // namespace fps_approx_ops
+
+struct FpsApproxEqual {
+    bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); }
 };
-} // namespace std
\ No newline at end of file
+
+inline std::string to_string(Fps fps) {
+    return base::StringPrintf("%.2f Hz", fps.getValue());
+}
+
+inline std::ostream& operator<<(std::ostream& stream, Fps fps) {
+    return stream << to_string(fps);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5707c67..68ca2f0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -221,7 +221,8 @@
  * Layer.  So, the implementation is done in BufferLayer.  When called on a
  * EffectLayer object, it's essentially a NOP.
  */
-void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
+void Layer::onLayerDisplayed(
+        std::shared_future<renderengine::RenderEngineResult> /*futureRenderEngineResult*/) {}
 
 void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
     if (mDrawingState.zOrderRelativeOf == nullptr) {
@@ -1137,7 +1138,7 @@
     if (!frameRate.rate.isValid() && frameRate.type != FrameRateCompatibility::NoVote &&
         childrenHaveFrameRate) {
         *transactionNeeded |=
-                setFrameRateForLayerTree(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote));
+                setFrameRateForLayerTree(FrameRate(Fps(), FrameRateCompatibility::NoVote));
     }
 
     // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 07b2eb5..4569f9a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -616,7 +616,8 @@
     void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
     std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
             compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
-    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+    void onLayerDisplayed(
+            std::shared_future<renderengine::RenderEngineResult> futureRenderEngineResult) override;
 
     void setWasClientComposed(const sp<Fence>& fence) override {
         mLastClientCompositionFence = fence;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 9465b19..32585dd 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -356,10 +356,13 @@
                                                renderengine::ExternalTexture::Usage::WRITEABLE);
     }
 
-    const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
-    mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
-                                 true /* regionSampling */, false /* grayscale */, captureListener);
-    ScreenCaptureResults captureResults = captureListener->waitForResults();
+    auto captureScreenResultFuture =
+            mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+                                         true /* regionSampling */, false /* grayscale */, nullptr);
+    auto& captureScreenResult = captureScreenResultFuture.get();
+    if (captureScreenResult.drawFence.ok()) {
+        sync_wait(captureScreenResult.drawFence.get(), -1);
+    }
 
     std::vector<Descriptor> activeDescriptors;
     for (const auto& descriptor : descriptors) {
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 8a45b66..314526a 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -41,7 +41,7 @@
       : mName(name),
         mOwnerUid(ownerUid),
         mDefaultVote(defaultVote),
-        mLayerVote({defaultVote, Fps(0.0f)}),
+        mLayerVote({defaultVote, Fps()}),
         mRefreshRateHistory(name) {}
 
 void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
@@ -93,10 +93,11 @@
         return false;
     }
 
+    using fps_approx_ops::operator>=;
+
     // Layer is considered frequent if the average frame rate is higher than the threshold
     const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
-    return Fps::fromPeriodNsecs(totalTime / (numFrames - 1))
-            .greaterThanOrEqualWithMargin(kMinFpsForFrequentLayer);
+    return Fps::fromPeriodNsecs(totalTime / (numFrames - 1)) >= kMinFpsForFrequentLayer;
 }
 
 bool LayerInfo::isAnimating(nsecs_t now) const {
@@ -191,17 +192,17 @@
         return std::nullopt;
     }
 
-    const auto averageFrameTime = calculateAverageFrameTime();
-    if (averageFrameTime.has_value()) {
+    if (const auto averageFrameTime = calculateAverageFrameTime()) {
         const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime);
         const bool refreshRateConsistent = mRefreshRateHistory.add(refreshRate, now);
         if (refreshRateConsistent) {
             const auto knownRefreshRate = refreshRateConfigs.findClosestKnownFrameRate(refreshRate);
-            // To avoid oscillation, use the last calculated refresh rate if it is
-            // close enough
+            using fps_approx_ops::operator!=;
+
+            // To avoid oscillation, use the last calculated refresh rate if it is close enough.
             if (std::abs(mLastRefreshRate.calculated.getValue() - refreshRate.getValue()) >
                         MARGIN &&
-                !mLastRefreshRate.reported.equalsWithMargin(knownRefreshRate)) {
+                mLastRefreshRate.reported != knownRefreshRate) {
                 mLastRefreshRate.calculated = refreshRate;
                 mLastRefreshRate.reported = knownRefreshRate;
             }
@@ -228,15 +229,15 @@
     if (isAnimating(now)) {
         ALOGV("%s is animating", mName.c_str());
         mLastRefreshRate.animatingOrInfrequent = true;
-        return {LayerHistory::LayerVoteType::Max, Fps(0.0f)};
+        return {LayerHistory::LayerVoteType::Max, Fps()};
     }
 
     if (!isFrequent(now)) {
         ALOGV("%s is infrequent", mName.c_str());
         mLastRefreshRate.animatingOrInfrequent = true;
-        // Infrequent layers vote for mininal refresh rate for
+        // Infrequent layers vote for minimal refresh rate for
         // battery saving purposes and also to prevent b/135718869.
-        return {LayerHistory::LayerVoteType::Min, Fps(0.0f)};
+        return {LayerHistory::LayerVoteType::Min, Fps()};
     }
 
     // If the layer was previously tagged as animating or infrequent, we clear
@@ -253,7 +254,7 @@
     }
 
     ALOGV("%s Max (can't resolve refresh rate)", mName.c_str());
-    return {LayerHistory::LayerVoteType::Max, Fps(0.0f)};
+    return {LayerHistory::LayerVoteType::Max, Fps()};
 }
 
 const char* LayerInfo::getTraceTag(android::scheduler::LayerHistory::LayerVoteType type) const {
@@ -300,9 +301,13 @@
 bool LayerInfo::RefreshRateHistory::isConsistent() const {
     if (mRefreshRates.empty()) return true;
 
-    const auto max = std::max_element(mRefreshRates.begin(), mRefreshRates.end());
-    const auto min = std::min_element(mRefreshRates.begin(), mRefreshRates.end());
-    const auto consistent =
+    const auto [min, max] =
+            std::minmax_element(mRefreshRates.begin(), mRefreshRates.end(),
+                                [](const auto& lhs, const auto& rhs) {
+                                    return isStrictlyLess(lhs.refreshRate, rhs.refreshRate);
+                                });
+
+    const bool consistent =
             max->refreshRate.getValue() - min->refreshRate.getValue() < MARGIN_CONSISTENT_FPS;
 
     if (CC_UNLIKELY(sTraceEnabled)) {
@@ -321,4 +326,4 @@
 } // namespace android::scheduler
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index ce9783c..92abbae 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -51,7 +51,7 @@
     // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
     // favor of a low refresh rate.
     static constexpr size_t kFrequentLayerWindowSize = 3;
-    static constexpr Fps kMinFpsForFrequentLayer{10.0f};
+    static constexpr Fps kMinFpsForFrequentLayer = 10_Hz;
     static constexpr auto kMaxPeriodForFrequentLayerNs =
             std::chrono::nanoseconds(kMinFpsForFrequentLayer.getPeriodNsecs()) + 1ms;
 
@@ -62,7 +62,7 @@
     // Holds information about the layer vote
     struct LayerVote {
         LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic;
-        Fps fps{0.0f};
+        Fps fps;
         Seamlessness seamlessness = Seamlessness::Default;
     };
 
@@ -86,19 +86,17 @@
         using Seamlessness = scheduler::Seamlessness;
 
         Fps rate;
-        FrameRateCompatibility type;
-        Seamlessness seamlessness;
+        FrameRateCompatibility type = FrameRateCompatibility::Default;
+        Seamlessness seamlessness = Seamlessness::Default;
 
-        FrameRate()
-              : rate(0),
-                type(FrameRateCompatibility::Default),
-                seamlessness(Seamlessness::Default) {}
+        FrameRate() = default;
+
         FrameRate(Fps rate, FrameRateCompatibility type,
                   Seamlessness seamlessness = Seamlessness::OnlySeamless)
               : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {}
 
         bool operator==(const FrameRate& other) const {
-            return rate.equalsWithMargin(other.rate) && type == other.type &&
+            return isApproxEqual(rate, other.rate) && type == other.type &&
                     seamlessness == other.seamlessness;
         }
 
@@ -151,7 +149,7 @@
     void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; }
 
     // Resets the layer vote to its default.
-    void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(0.0f), Seamlessness::Default}; }
+    void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(), Seamlessness::Default}; }
 
     std::string getName() const { return mName; }
 
@@ -201,9 +199,9 @@
     // Holds information about the calculated and reported refresh rate
     struct RefreshRateHeuristicData {
         // Rate calculated on the layer
-        Fps calculated{0.0f};
+        Fps calculated;
         // Last reported rate for LayerInfo::getRefreshRate()
-        Fps reported{0.0f};
+        Fps reported;
         // Whether the last reported rate for LayerInfo::getRefreshRate()
         // was due to animation or infrequent updates
         bool animatingOrInfrequent = false;
@@ -229,14 +227,8 @@
 
         // Holds the refresh rate when it was calculated
         struct RefreshRateData {
-            Fps refreshRate{0.0f};
+            Fps refreshRate;
             nsecs_t timestamp = 0;
-
-            bool operator<(const RefreshRateData& other) const {
-                // We don't need comparison with margins since we are using
-                // this to find the min and max refresh rates.
-                return refreshRate.getValue() < other.refreshRate.getValue();
-            }
         };
 
         // Holds tracing strings
@@ -268,7 +260,7 @@
 
     // Used for sanitizing the heuristic data. If two frames are less than
     // this period apart from each other they'll be considered as duplicates.
-    static constexpr nsecs_t kMinPeriodBetweenFrames = Fps(240.f).getPeriodNsecs();
+    static constexpr nsecs_t kMinPeriodBetweenFrames = (240_Hz).getPeriodNsecs();
     // Used for sanitizing the heuristic data. If two frames are more than
     // this period apart from each other, the interval between them won't be
     // taken into account when calculating average frame rate.
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index c9f00a0..aabd88a 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -42,19 +42,18 @@
 }
 
 std::vector<Fps> constructKnownFrameRates(const DisplayModes& modes) {
-    std::vector<Fps> knownFrameRates = {Fps(24.0f), Fps(30.0f), Fps(45.0f), Fps(60.0f), Fps(72.0f)};
+    std::vector<Fps> knownFrameRates = {24_Hz, 30_Hz, 45_Hz, 60_Hz, 72_Hz};
     knownFrameRates.reserve(knownFrameRates.size() + modes.size());
 
-    // Add all supported refresh rates to the set
+    // Add all supported refresh rates.
     for (const auto& mode : modes) {
-        const auto refreshRate = Fps::fromPeriodNsecs(mode->getVsyncPeriod());
-        knownFrameRates.emplace_back(refreshRate);
+        knownFrameRates.push_back(Fps::fromPeriodNsecs(mode->getVsyncPeriod()));
     }
 
-    // Sort and remove duplicates
-    std::sort(knownFrameRates.begin(), knownFrameRates.end(), Fps::comparesLess);
+    // Sort and remove duplicates.
+    std::sort(knownFrameRates.begin(), knownFrameRates.end(), isStrictlyLess);
     knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
-                                      Fps::EqualsWithMargin()),
+                                      isApproxEqual),
                           knownFrameRates.end());
     return knownFrameRates;
 }
@@ -64,6 +63,11 @@
 using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
 using RefreshRate = RefreshRateConfigs::RefreshRate;
 
+bool RefreshRate::inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const {
+    using fps_approx_ops::operator<=;
+    return minRefreshRate <= getFps() && getFps() <= maxRefreshRate;
+}
+
 std::string RefreshRate::toString() const {
     return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
                               getModeId().value(), mode->getHwcId(), getFps().getValue(),
@@ -110,14 +114,14 @@
 
 bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer,
                                        const RefreshRate& refreshRate) const {
+    using namespace fps_approx_ops;
+
     switch (layer.vote) {
         case LayerVoteType::ExplicitExactOrMultiple:
         case LayerVoteType::Heuristic:
             if (mConfig.frameRateMultipleThreshold != 0 &&
-                refreshRate.getFps().greaterThanOrEqualWithMargin(
-                        Fps(mConfig.frameRateMultipleThreshold)) &&
-                layer.desiredRefreshRate.lessThanWithMargin(
-                        Fps(mConfig.frameRateMultipleThreshold / 2))) {
+                refreshRate.getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold) &&
+                layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2)) {
                 // Don't vote high refresh rates past the threshold for layers with a low desired
                 // refresh rate. For example, desired 24 fps with 120 Hz threshold means no vote for
                 // 120 Hz, but desired 60 fps should have a vote.
@@ -247,7 +251,7 @@
 };
 
 RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
-                                                   const GlobalSignals& globalSignals,
+                                                   GlobalSignals globalSignals,
                                                    GlobalSignals* outSignalsConsidered) const {
     std::lock_guard lock(mLock);
 
@@ -269,7 +273,7 @@
 }
 
 std::optional<RefreshRate> RefreshRateConfigs::getCachedBestRefreshRate(
-        const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
+        const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals,
         GlobalSignals* outSignalsConsidered) const {
     const bool sameAsLastCall = lastBestRefreshRateInvocation &&
             lastBestRefreshRateInvocation->layerRequirements == layers &&
@@ -286,7 +290,7 @@
 }
 
 RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(
-        const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
+        const std::vector<LayerRequirement>& layers, GlobalSignals globalSignals,
         GlobalSignals* outSignalsConsidered) const {
     ATRACE_CALL();
     ALOGV("getBestRefreshRate %zu layers", layers.size());
@@ -370,7 +374,7 @@
     // move out the of range if layers explicitly request a different refresh
     // rate.
     const bool primaryRangeIsSingleRate =
-            policy->primaryRange.min.equalsWithMargin(policy->primaryRange.max);
+            isApproxEqual(policy->primaryRange.min, policy->primaryRange.max);
 
     if (!globalSignals.touch && globalSignals.idle &&
         !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
@@ -498,8 +502,11 @@
             return explicitExact == 0;
         }
     }();
+
+    using fps_approx_ops::operator<;
+
     if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
-        bestRefreshRate->getFps().lessThanWithMargin(touchRefreshRate.getFps())) {
+        bestRefreshRate->getFps() < touchRefreshRate.getFps()) {
         setTouchConsidered();
         ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
         return touchRefreshRate;
@@ -552,7 +559,8 @@
 }
 
 RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides(
-        const std::vector<LayerRequirement>& layers, Fps displayFrameRate, bool touch) const {
+        const std::vector<LayerRequirement>& layers, Fps displayFrameRate,
+        GlobalSignals globalSignals) const {
     ATRACE_CALL();
     if (!mSupportsFrameRateOverride) return {};
 
@@ -570,7 +578,7 @@
                                 return layer->vote == LayerVoteType::ExplicitExactOrMultiple;
                             });
 
-        if (touch && hasExplicitExactOrMultiple) {
+        if (globalSignals.touch && hasExplicitExactOrMultiple) {
             continue;
         }
 
@@ -798,8 +806,10 @@
         ALOGE("Default mode is not in the primary range.");
         return false;
     }
-    return policy.appRequestRange.min.lessThanOrEqualWithMargin(policy.primaryRange.min) &&
-            policy.appRequestRange.max.greaterThanOrEqualWithMargin(policy.primaryRange.max);
+
+    using namespace fps_approx_ops;
+    return policy.appRequestRange.min <= policy.primaryRange.min &&
+            policy.appRequestRange.max >= policy.primaryRange.max;
 }
 
 status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
@@ -925,19 +935,21 @@
 }
 
 Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const {
-    if (frameRate.lessThanOrEqualWithMargin(*mKnownFrameRates.begin())) {
-        return *mKnownFrameRates.begin();
+    using namespace fps_approx_ops;
+
+    if (frameRate <= mKnownFrameRates.front()) {
+        return mKnownFrameRates.front();
     }
 
-    if (frameRate.greaterThanOrEqualWithMargin(*std::prev(mKnownFrameRates.end()))) {
-        return *std::prev(mKnownFrameRates.end());
+    if (frameRate >= mKnownFrameRates.back()) {
+        return mKnownFrameRates.back();
     }
 
     auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate,
-                                       Fps::comparesLess);
+                                       isStrictlyLess);
 
-    const auto distance1 = std::abs((frameRate.getValue() - lowerBound->getValue()));
-    const auto distance2 = std::abs((frameRate.getValue() - std::prev(lowerBound)->getValue()));
+    const auto distance1 = std::abs(frameRate.getValue() - lowerBound->getValue());
+    const auto distance2 = std::abs(frameRate.getValue() - std::prev(lowerBound)->getValue());
     return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
 }
 
@@ -956,7 +968,7 @@
     }
     if (minByPolicy == maxByPolicy) {
         // when min primary range in display manager policy is below device min turn on the timer.
-        if (currentPolicy->primaryRange.min.lessThanWithMargin(deviceMin.getFps())) {
+        if (isApproxLess(currentPolicy->primaryRange.min, deviceMin.getFps())) {
             return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
         }
         return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
@@ -982,14 +994,14 @@
 }
 
 bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) {
-    if (smaller.getValue() > bigger.getValue()) {
+    if (isStrictlyLess(bigger, smaller)) {
         return isFractionalPairOrMultiple(bigger, smaller);
     }
 
     const auto multiplier = std::round(bigger.getValue() / smaller.getValue());
     constexpr float kCoef = 1000.f / 1001.f;
-    return bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier / kCoef)) ||
-            bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier * kCoef));
+    return isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier / kCoef)) ||
+            isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier * kCoef));
 }
 
 void RefreshRateConfigs::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 3abf83d..53472ef 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -76,19 +76,15 @@
 
         // Checks whether the fps of this RefreshRate struct is within a given min and max refresh
         // rate passed in. Margin of error is applied to the boundaries for approximation.
-        bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const {
-            return minRefreshRate.lessThanOrEqualWithMargin(getFps()) &&
-                    getFps().lessThanOrEqualWithMargin(maxRefreshRate);
-        }
+        bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const;
 
-        bool operator!=(const RefreshRate& other) const { return mode != other.mode; }
+        bool operator==(const RefreshRate& other) const { return mode == other.mode; }
+        bool operator!=(const RefreshRate& other) const { return !operator==(other); }
 
         bool operator<(const RefreshRate& other) const {
-            return getFps().getValue() < other.getFps().getValue();
+            return isStrictlyLess(getFps(), other.getFps());
         }
 
-        bool operator==(const RefreshRate& other) const { return !(*this != other); }
-
         std::string toString() const;
         friend std::ostream& operator<<(std::ostream& os, const RefreshRate& refreshRate) {
             return os << refreshRate.toString();
@@ -105,11 +101,11 @@
             std::unordered_map<DisplayModeId, std::unique_ptr<const RefreshRate>>;
 
     struct FpsRange {
-        Fps min{0.0f};
-        Fps max{std::numeric_limits<float>::max()};
+        Fps min = Fps::fromValue(0.f);
+        Fps max = Fps::fromValue(std::numeric_limits<float>::max());
 
         bool operator==(const FpsRange& other) const {
-            return min.equalsWithMargin(other.min) && max.equalsWithMargin(other.max);
+            return isApproxEqual(min, other.min) && isApproxEqual(max, other.max);
         }
 
         bool operator!=(const FpsRange& other) const { return !(*this == other); }
@@ -221,7 +217,7 @@
         // Layer vote type.
         LayerVoteType vote = LayerVoteType::NoVote;
         // Layer's desired refresh rate, if applicable.
-        Fps desiredRefreshRate{0.0f};
+        Fps desiredRefreshRate;
         // If a seamless mode switch is required.
         Seamlessness seamlessness = Seamlessness::Default;
         // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer
@@ -232,7 +228,7 @@
 
         bool operator==(const LayerRequirement& other) const {
             return name == other.name && vote == other.vote &&
-                    desiredRefreshRate.equalsWithMargin(other.desiredRefreshRate) &&
+                    isApproxEqual(desiredRefreshRate, other.desiredRefreshRate) &&
                     seamlessness == other.seamlessness && weight == other.weight &&
                     focused == other.focused;
         }
@@ -247,18 +243,14 @@
         // True if the system hasn't seen any buffers posted to layers recently.
         bool idle = false;
 
-        bool operator==(const GlobalSignals& other) const {
+        bool operator==(GlobalSignals other) const {
             return touch == other.touch && idle == other.idle;
         }
     };
 
-    // Returns the refresh rate that fits best to the given layers.
-    //   layers - The layer requirements to consider.
-    //   globalSignals - global state of touch and idle
-    //   outSignalsConsidered - An output param that tells the caller whether the refresh rate was
-    //                          chosen based on touch boost and/or idle timer.
-    RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>& layers,
-                                   const GlobalSignals& globalSignals,
+    // Returns the refresh rate that best fits the given layers. outSignalsConsidered returns
+    // whether the refresh rate was chosen based on touch boost and/or idle timer.
+    RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>&, GlobalSignals,
                                    GlobalSignals* outSignalsConsidered = nullptr) const
             EXCLUDES(mLock);
 
@@ -349,13 +341,10 @@
     static bool isFractionalPairOrMultiple(Fps, Fps);
 
     using UidToFrameRateOverride = std::map<uid_t, Fps>;
+
     // Returns the frame rate override for each uid.
-    //
-    // @param layers list of visible layers
-    // @param displayFrameRate the display frame rate
-    // @param touch whether touch timer is active (i.e. user touched the screen recently)
-    UidToFrameRateOverride getFrameRateOverrides(const std::vector<LayerRequirement>& layers,
-                                                 Fps displayFrameRate, bool touch) const
+    UidToFrameRateOverride getFrameRateOverrides(const std::vector<LayerRequirement>&,
+                                                 Fps displayFrameRate, GlobalSignals) const
             EXCLUDES(mLock);
 
     bool supportsKernelIdleTimer() const { return mConfig.supportKernelIdleTimer; }
@@ -396,13 +385,12 @@
             const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
             std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock);
 
-    std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>& layers,
-                                                        const GlobalSignals& globalSignals,
+    std::optional<RefreshRate> getCachedBestRefreshRate(const std::vector<LayerRequirement>&,
+                                                        GlobalSignals,
                                                         GlobalSignals* outSignalsConsidered) const
             REQUIRES(mLock);
 
-    RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>& layers,
-                                         const GlobalSignals& globalSignals,
+    RefreshRate getBestRefreshRateLocked(const std::vector<LayerRequirement>&, GlobalSignals,
                                          GlobalSignals* outSignalsConsidered) const REQUIRES(mLock);
 
     // Returns the refresh rate with the highest score in the collection specified from begin
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 208a767..80aa96f 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -16,15 +16,17 @@
 
 #pragma once
 
+#include <chrono>
 #include <numeric>
 
+#include <android-base/stringprintf.h>
+#include <ftl/small_map.h>
+#include <utils/Timers.h>
+
 #include "Fps.h"
 #include "Scheduler/SchedulerUtils.h"
 #include "TimeStats/TimeStats.h"
 
-#include "android-base/stringprintf.h"
-#include "utils/Timers.h"
-
 namespace android::scheduler {
 
 /**
@@ -40,6 +42,7 @@
     static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
 
 public:
+    // TODO(b/185535769): Inject clock to avoid sleeping in tests.
     RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate,
                      android::hardware::graphics::composer::hal::PowerMode currentPowerMode)
           : mTimeStats(timeStats),
@@ -58,7 +61,7 @@
     // Sets config mode. If the mode has changed, it records how much time was spent in the previous
     // mode.
     void setRefreshRate(Fps currRefreshRate) {
-        if (mCurrentRefreshRate.equalsWithMargin(currRefreshRate)) {
+        if (isApproxEqual(mCurrentRefreshRate, currRefreshRate)) {
             return;
         }
         mTimeStats.incrementRefreshRateSwitches();
@@ -66,25 +69,26 @@
         mCurrentRefreshRate = currRefreshRate;
     }
 
-    // Returns a map between human readable refresh rate and number of seconds the device spent in
-    // that mode.
-    std::unordered_map<std::string, int64_t> getTotalTimes() {
+    // Maps stringified refresh rate to total time spent in that mode.
+    using TotalTimes = ftl::SmallMap<std::string, std::chrono::milliseconds, 3>;
+
+    TotalTimes getTotalTimes() {
         // If the power mode is on, then we are probably switching between the config modes. If
         // it's not then the screen is probably off. Make sure to flush times before printing
         // them.
         flushTime();
 
-        std::unordered_map<std::string, int64_t> totalTime;
-        // Multiple configs may map to the same name, e.g. "60fps". Add the
-        // times for such configs together.
-        for (const auto& [configId, time] : mConfigModesTotalTime) {
-            totalTime[to_string(configId)] = 0;
+        TotalTimes totalTimes = ftl::init::map("ScreenOff", mScreenOffTime);
+        const auto zero = std::chrono::milliseconds::zero();
+
+        // Sum the times for modes that map to the same name, e.g. "60 Hz".
+        for (const auto& [fps, time] : mFpsTotalTimes) {
+            const auto string = to_string(fps);
+            const auto total = std::as_const(totalTimes).get(string).value_or(std::cref(zero));
+            totalTimes.emplace_or_replace(string, total.get() + time);
         }
-        for (const auto& [configId, time] : mConfigModesTotalTime) {
-            totalTime[to_string(configId)] += time;
-        }
-        totalTime["ScreenOff"] = mScreenOffTime;
-        return totalTime;
+
+        return totalTimes;
     }
 
     // Traverses through the map of config modes and returns how long they've been running in easy
@@ -102,28 +106,32 @@
     // Calculates the time that passed in ms between the last time we recorded time and the time
     // this method was called.
     void flushTime() {
-        nsecs_t currentTime = systemTime();
-        nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
-        int64_t timeElapsedMs = ns2ms(timeElapsed);
+        const nsecs_t currentTime = systemTime();
+        const nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
         mPreviousRecordedTime = currentTime;
 
+        const auto duration = std::chrono::milliseconds{ns2ms(timeElapsed)};
+        const auto zero = std::chrono::milliseconds::zero();
+
         uint32_t fps = 0;
+
         if (mCurrentPowerMode == android::hardware::graphics::composer::hal::PowerMode::ON) {
             // Normal power mode is counted under different config modes.
-            if (mConfigModesTotalTime.find(mCurrentRefreshRate) == mConfigModesTotalTime.end()) {
-                mConfigModesTotalTime[mCurrentRefreshRate] = 0;
-            }
-            mConfigModesTotalTime[mCurrentRefreshRate] += timeElapsedMs;
+            const auto total = std::as_const(mFpsTotalTimes)
+                                       .get(mCurrentRefreshRate)
+                                       .value_or(std::cref(zero));
+            mFpsTotalTimes.emplace_or_replace(mCurrentRefreshRate, total.get() + duration);
+
             fps = static_cast<uint32_t>(mCurrentRefreshRate.getIntValue());
         } else {
-            mScreenOffTime += timeElapsedMs;
+            mScreenOffTime += duration;
         }
         mTimeStats.recordRefreshRate(fps, timeElapsed);
     }
 
     // Formats the time in milliseconds into easy to read format.
-    static std::string getDateFormatFromMs(int64_t timeMs) {
-        auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY);
+    static std::string getDateFormatFromMs(std::chrono::milliseconds time) {
+        auto [days, dayRemainderMs] = std::div(static_cast<int64_t>(time.count()), MS_PER_DAY);
         auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR);
         auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN);
         auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S);
@@ -138,9 +146,8 @@
     Fps mCurrentRefreshRate;
     android::hardware::graphics::composer::hal::PowerMode mCurrentPowerMode;
 
-    std::unordered_map<Fps, int64_t /* duration in ms */, std::hash<Fps>, Fps::EqualsInBuckets>
-            mConfigModesTotalTime;
-    int64_t mScreenOffTime = 0;
+    ftl::SmallMap<Fps, std::chrono::milliseconds, 2, FpsApproxEqual> mFpsTotalTimes;
+    std::chrono::milliseconds mScreenOffTime = std::chrono::milliseconds::zero();
 
     nsecs_t mPreviousRecordedTime = systemTime();
 };
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c6a19de..eeea25d 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -206,14 +206,14 @@
     {
         const auto iter = mFrameRateOverridesFromBackdoor.find(uid);
         if (iter != mFrameRateOverridesFromBackdoor.end()) {
-            return std::make_optional<Fps>(iter->second);
+            return iter->second;
         }
     }
 
     {
         const auto iter = mFrameRateOverridesByContent.find(uid);
         if (iter != mFrameRateOverridesByContent.end()) {
-            return std::make_optional<Fps>(iter->second);
+            return iter->second;
         }
     }
 
@@ -324,6 +324,7 @@
         thread = mConnections[handle].thread.get();
     }
     thread->onScreenAcquired();
+    mScreenAcquired = true;
 }
 
 void Scheduler::onScreenReleased(ConnectionHandle handle) {
@@ -334,6 +335,7 @@
         thread = mConnections[handle].thread.get();
     }
     thread->onScreenReleased();
+    mScreenAcquired = false;
 }
 
 void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
@@ -697,15 +699,16 @@
         return mRefreshRateConfigs->getCurrentRefreshRate();
     }();
 
-    constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER{65.0f};
-    if (state == TimerState::Reset &&
-        refreshRate.getFps().greaterThanWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) {
+    constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
+    using namespace fps_approx_ops;
+
+    if (state == TimerState::Reset && refreshRate.getFps() > FPS_THRESHOLD_FOR_KERNEL_TIMER) {
         // If we're not in performance mode then the kernel timer shouldn't do
         // anything, as the refresh rate during DPU power collapse will be the
         // same.
         resyncToHardwareVsync(true /* makeAvailable */, refreshRate.getVsyncPeriod());
     } else if (state == TimerState::Expired &&
-               refreshRate.getFps().lessThanOrEqualWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) {
+               refreshRate.getFps() <= FPS_THRESHOLD_FOR_KERNEL_TIMER) {
         // Disable HW VSYNC if the timer expired, as we don't need it enabled if
         // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
         // need to update the VsyncController model anyway.
@@ -760,6 +763,13 @@
         }
         StringAppendF(&result, "}\n");
     }
+
+    {
+        std::lock_guard lock(mHWVsyncLock);
+        StringAppendF(&result,
+                      "mScreenAcquired=%d mPrimaryHWVsyncEnabled=%d mHWVsyncAvailable=%d\n",
+                      mScreenAcquired.load(), mPrimaryHWVsyncEnabled, mHWVsyncAvailable);
+    }
 }
 
 void Scheduler::dumpVsync(std::string& s) const {
@@ -781,13 +791,12 @@
     if (!consideredSignals.idle) {
         const auto frameRateOverrides =
                 refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements,
-                                                          displayRefreshRate,
-                                                          consideredSignals.touch);
+                                                          displayRefreshRate, consideredSignals);
         std::lock_guard lock(mFrameRateOverridesLock);
         if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(),
                         frameRateOverrides.begin(), frameRateOverrides.end(),
-                        [](const std::pair<uid_t, Fps>& a, const std::pair<uid_t, Fps>& b) {
-                            return a.first == b.first && a.second.equalsWithMargin(b.second);
+                        [](const auto& lhs, const auto& rhs) {
+                            return lhs.first == rhs.first && isApproxEqual(lhs.second, rhs.second);
                         })) {
             mFrameRateOverridesByContent = frameRateOverrides;
             return true;
@@ -912,7 +921,8 @@
 
     std::lock_guard lock(mFrameRateOverridesLock);
     if (frameRateOverride.frameRateHz != 0.f) {
-        mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz);
+        mFrameRateOverridesFromBackdoor[frameRateOverride.uid] =
+                Fps::fromValue(frameRateOverride.frameRateHz);
     } else {
         mFrameRateOverridesFromBackdoor.erase(frameRateOverride.uid);
     }
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0a33dbb..8397738 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -287,7 +287,7 @@
     InjectVSyncSource* mVSyncInjector = nullptr;
     ConnectionHandle mInjectorConnectionHandle;
 
-    std::mutex mHWVsyncLock;
+    mutable std::mutex mHWVsyncLock;
     bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false;
     bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false;
 
@@ -350,6 +350,9 @@
             GUARDED_BY(mFrameRateOverridesLock);
     scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor
             GUARDED_BY(mFrameRateOverridesLock);
+
+    // Keeps track of whether the screen is acquired for debug
+    std::atomic<bool> mScreenAcquired = false;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
index 43e0297..ff31651 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
@@ -48,14 +48,12 @@
 }
 
 PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRateLocked(Fps fps) const {
-    const auto iter = mOffsetsCache.find(fps);
-    if (iter != mOffsetsCache.end()) {
-        return iter->second;
+    if (const auto offsets = mOffsetsCache.get(fps)) {
+        return offsets->get();
     }
 
-    const auto offset = constructOffsets(fps.getPeriodNsecs());
-    mOffsetsCache[fps] = offset;
-    return offset;
+    const auto [it, _] = mOffsetsCache.try_emplace(fps, constructOffsets(fps.getPeriodNsecs()));
+    return it->second;
 }
 
 void VsyncConfiguration::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
index 3e53b3f..8447512 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
@@ -17,10 +17,10 @@
 #pragma once
 
 #include <mutex>
-#include <type_traits>
-#include <unordered_map>
-#include <vector>
+#include <optional>
+#include <string>
 
+#include <ftl/small_map.h>
 #include <utils/Timers.h>
 
 #include "Fps.h"
@@ -88,9 +88,8 @@
 
     VsyncConfigSet getConfigsForRefreshRateLocked(Fps fps) const REQUIRES(mLock);
 
-    mutable std::unordered_map<Fps, VsyncConfigSet, std::hash<Fps>, Fps::EqualsInBuckets>
-            mOffsetsCache GUARDED_BY(mLock);
-    std::atomic<Fps> mRefreshRateFps GUARDED_BY(mLock);
+    mutable ftl::SmallMap<Fps, VsyncConfigSet, 2, FpsApproxEqual> mOffsetsCache GUARDED_BY(mLock);
+    Fps mRefreshRateFps GUARDED_BY(mLock);
     mutable std::mutex mLock;
 };
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cfd051c..5f4acc9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -709,6 +709,7 @@
     ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
 
     mFlagManager = std::make_unique<android::FlagManager>();
+    mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint());
     mFrameTracer->initialize();
     mFrameTimeline->onBootFinished();
 
@@ -1039,7 +1040,7 @@
         outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue();
 
         const auto vsyncConfigSet =
-                mVsyncConfiguration->getConfigsForRefreshRate(Fps(outMode.refreshRate));
+                mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate));
         outMode.appVsyncOffset = vsyncConfigSet.late.appOffset;
         outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
         outMode.group = mode->getGroup();
@@ -1837,7 +1838,7 @@
 
         if (const auto display = getDefaultDisplayDeviceLocked();
             display && display->isPoweredOn()) {
-            getHwComposer().setVsyncEnabled(display->getPhysicalId(), mHWCVsyncPendingState);
+            setHWCVsyncEnabled(display->getPhysicalId(), mHWCVsyncPendingState);
         }
     }));
 }
@@ -2021,17 +2022,23 @@
 bool SurfaceFlinger::flushAndCommitTransactions() {
     ATRACE_CALL();
 
+    bool needsTraversal = false;
     if (clearTransactionFlags(eTransactionFlushNeeded)) {
-        flushTransactionQueues();
+        needsTraversal = flushTransactionQueues();
     }
 
-    const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || mForceTraversal;
+    const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
     if (shouldCommit) {
         commitTransactions();
     }
 
-    // Invoke OnCommit callbacks.
-    mTransactionCallbackInvoker.sendCallbacks();
+    if (!needsTraversal) {
+        // Invoke empty transaction callbacks early.
+        mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
+    } else {
+        // Invoke OnCommit callbacks.
+        mTransactionCallbackInvoker.sendCallbacks(true /* onCommitOnly */);
+    }
 
     if (transactionFlushNeeded()) {
         setTransactionFlags(eTransactionFlushNeeded);
@@ -2328,7 +2335,7 @@
     mVisibleRegionsWereDirtyThisFrame = false;
 
     mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
-    mTransactionCallbackInvoker.sendCallbacks();
+    mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
     mTransactionCallbackInvoker.clearCompletedTransactions();
 
     if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON &&
@@ -2941,7 +2948,6 @@
         processDisplayChangesLocked();
         processDisplayHotplugEventsLocked();
     }
-    mForceTraversal = false;
     mForceTransactionDisplayChange = displayTransactionNeeded;
 
     if (mSomeChildrenChanged) {
@@ -3415,11 +3421,8 @@
     return old;
 }
 
-void SurfaceFlinger::setTraversalNeeded() {
-    mForceTraversal = true;
-}
-
-void SurfaceFlinger::flushTransactionQueues() {
+bool SurfaceFlinger::flushTransactionQueues() {
+    bool needsTraversal = false;
     // to prevent onHandleDestroyed from being called while the lock is held,
     // we must keep a copy of the transactions (specifically the composer
     // states) around outside the scope of the lock
@@ -3488,19 +3491,23 @@
 
         // Now apply all transactions.
         for (const auto& transaction : transactions) {
-            applyTransactionState(transaction.frameTimelineInfo, transaction.states,
-                                  transaction.displays, transaction.flags,
-                                  transaction.inputWindowCommands, transaction.desiredPresentTime,
-                                  transaction.isAutoTimestamp, transaction.buffer,
-                                  transaction.postTime, transaction.permissions,
-                                  transaction.hasListenerCallbacks, transaction.listenerCallbacks,
-                                  transaction.originPid, transaction.originUid, transaction.id);
+            needsTraversal |=
+                    applyTransactionState(transaction.frameTimelineInfo, transaction.states,
+                                          transaction.displays, transaction.flags,
+                                          transaction.inputWindowCommands,
+                                          transaction.desiredPresentTime,
+                                          transaction.isAutoTimestamp, transaction.buffer,
+                                          transaction.postTime, transaction.permissions,
+                                          transaction.hasListenerCallbacks,
+                                          transaction.listenerCallbacks, transaction.originPid,
+                                          transaction.originUid, transaction.id);
             if (transaction.transactionCommittedSignal) {
                 mTransactionCommittedSignals.emplace_back(
                         std::move(transaction.transactionCommittedSignal));
             }
         }
-    }
+    } // unlock mStateLock
+    return needsTraversal;
 }
 
 bool SurfaceFlinger::transactionFlushNeeded() {
@@ -3706,7 +3713,7 @@
     return NO_ERROR;
 }
 
-void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
+bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
                                            const Vector<ComposerState>& states,
                                            const Vector<DisplayState>& displays, uint32_t flags,
                                            const InputWindowCommands& inputWindowCommands,
@@ -3728,12 +3735,10 @@
         mTransactionCallbackInvoker.addEmptyTransaction(listener);
     }
 
-    std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> listenerCallbacksWithSurfaces;
     uint32_t clientStateFlags = 0;
     for (const ComposerState& state : states) {
-        clientStateFlags |=
-                setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp,
-                                     postTime, permissions, listenerCallbacksWithSurfaces);
+        clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime,
+                                                 isAutoTimestamp, postTime, permissions);
         if ((flags & eAnimation) && state.state.surface) {
             if (const auto layer = fromHandle(state.state.surface).promote(); layer) {
                 mScheduler->recordLayerHistory(layer.get(),
@@ -3743,10 +3748,6 @@
         }
     }
 
-    // If the state doesn't require a traversal and there are callbacks, send them now
-    if (!(clientStateFlags & eTraversalNeeded) && hasListenerCallbacks) {
-        mTransactionCallbackInvoker.sendCallbacks();
-    }
     transactionFlags |= clientStateFlags;
 
     if (permissions & Permission::ACCESS_SURFACE_FLINGER) {
@@ -3768,6 +3769,7 @@
         transactionFlags = eTransactionNeeded;
     }
 
+    bool needsTraversal = false;
     if (transactionFlags) {
         if (mInterceptor->isEnabled()) {
             mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
@@ -3778,7 +3780,7 @@
         // so we don't have to wake up again next frame to preform an unnecessary traversal.
         if (transactionFlags & eTraversalNeeded) {
             transactionFlags = transactionFlags & (~eTraversalNeeded);
-            mForceTraversal = true;
+            needsTraversal = true;
         }
         if (transactionFlags) {
             setTransactionFlags(transactionFlags);
@@ -3788,6 +3790,8 @@
             mAnimTransactionPending = true;
         }
     }
+
+    return needsTraversal;
 }
 
 uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
@@ -3856,10 +3860,10 @@
     return true;
 }
 
-uint32_t SurfaceFlinger::setClientStateLocked(
-        const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState,
-        int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions,
-        std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& outListenerCallbacks) {
+uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTimelineInfo,
+                                              const ComposerState& composerState,
+                                              int64_t desiredPresentTime, bool isAutoTimestamp,
+                                              int64_t postTime, uint32_t permissions) {
     const layer_state_t& s = composerState.state;
     const bool privileged = permissions & Permission::ACCESS_SURFACE_FLINGER;
 
@@ -3873,13 +3877,11 @@
         ListenerCallbacks onCommitCallbacks = listener.filter(CallbackId::Type::ON_COMMIT);
         if (!onCommitCallbacks.callbackIds.empty()) {
             filteredListeners.push_back(onCommitCallbacks);
-            outListenerCallbacks.insert(onCommitCallbacks);
         }
 
         ListenerCallbacks onCompleteCallbacks = listener.filter(CallbackId::Type::ON_COMPLETE);
         if (!onCompleteCallbacks.callbackIds.empty()) {
             filteredListeners.push_back(onCompleteCallbacks);
-            outListenerCallbacks.insert(onCompleteCallbacks);
         }
     }
 
@@ -4108,7 +4110,8 @@
             const auto strategy =
                     Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy);
 
-            if (layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), compatibility, strategy))) {
+            if (layer->setFrameRate(
+                        Layer::FrameRate(Fps::fromValue(s.frameRate), compatibility, strategy))) {
                 flags |= eTraversalNeeded;
             }
         }
@@ -4502,6 +4505,12 @@
         return;
     }
 
+    const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken);
+    if (activeDisplay != display && display->isInternal() && activeDisplay &&
+        activeDisplay->isPoweredOn()) {
+        ALOGW("Trying to change power mode on non active display while the active display is ON");
+    }
+
     display->setPowerMode(mode);
 
     if (mInterceptor->isEnabled()) {
@@ -4509,7 +4518,7 @@
     }
     const auto vsyncPeriod = display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod();
     if (currentMode == hal::PowerMode::OFF) {
-        const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken);
+        // Turn on the display
         if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
             onActiveDisplayChangedLocked(display);
         }
@@ -4522,8 +4531,8 @@
             ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
         }
         getHwComposer().setPowerMode(displayId, mode);
-        if (display->isInternal() && mode != hal::PowerMode::DOZE_SUSPEND) {
-            getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState);
+        if (isDisplayActiveLocked(display) && mode != hal::PowerMode::DOZE_SUSPEND) {
+            setHWCVsyncEnabled(displayId, mHWCVsyncPendingState);
             mScheduler->onScreenAcquired(mAppConnectionHandle);
             mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
         }
@@ -4539,13 +4548,13 @@
         if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
             ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
         }
-        if (display->isInternal() && currentMode != hal::PowerMode::DOZE_SUSPEND) {
+        if (isDisplayActiveLocked(display) && currentMode != hal::PowerMode::DOZE_SUSPEND) {
             mScheduler->disableHardwareVsync(true);
             mScheduler->onScreenReleased(mAppConnectionHandle);
         }
 
         // Make sure HWVsync is disabled before turning off the display
-        getHwComposer().setVsyncEnabled(displayId, hal::Vsync::DISABLE);
+        setHWCVsyncEnabled(displayId, hal::Vsync::DISABLE);
 
         getHwComposer().setPowerMode(displayId, mode);
         mVisibleRegionsDirty = true;
@@ -4553,13 +4562,13 @@
     } else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
         // Update display while dozing
         getHwComposer().setPowerMode(displayId, mode);
-        if (display->isInternal() && currentMode == hal::PowerMode::DOZE_SUSPEND) {
+        if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) {
             mScheduler->onScreenAcquired(mAppConnectionHandle);
             mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
         }
     } else if (mode == hal::PowerMode::DOZE_SUSPEND) {
         // Leave display going to doze
-        if (display->isInternal()) {
+        if (isDisplayActiveLocked(display)) {
             mScheduler->disableHardwareVsync(true);
             mScheduler->onScreenReleased(mAppConnectionHandle);
         }
@@ -4569,7 +4578,7 @@
         getHwComposer().setPowerMode(displayId, mode);
     }
 
-    if (display->isInternal()) {
+    if (isDisplayActiveLocked(display)) {
         mTimeStats->setPowerMode(mode);
         mRefreshRateStats->setPowerMode(mode);
         mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
@@ -4748,6 +4757,8 @@
 
     mScheduler->dump(mAppConnectionHandle, result);
     mScheduler->dumpVsync(result);
+    StringAppendF(&result, "mHWCVsyncPendingState=%s mLastHWCVsyncState=%s\n",
+                  to_string(mHWCVsyncPendingState).c_str(), to_string(mLastHWCVsyncState).c_str());
 }
 
 void SurfaceFlinger::dumpPlannerInfo(const DumpArgs& args, std::string& result) const {
@@ -5932,9 +5943,10 @@
         traverseLayersInLayerStack(layerStack, args.uid, visitor);
     };
 
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, args.allowProtected, args.grayscale,
-                               captureListener);
+    auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
+                                                   reqSize, args.pixelFormat, args.allowProtected,
+                                                   args.grayscale, captureListener);
+    return captureResultFuture.get().status;
 }
 
 status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
@@ -5969,9 +5981,15 @@
         traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
     };
 
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
-                               ui::PixelFormat::RGBA_8888, false /* allowProtected */,
-                               false /* grayscale */, captureListener);
+    if (captureListener == nullptr) {
+        ALOGE("capture screen must provide a capture listener callback");
+        return BAD_VALUE;
+    }
+    auto captureResultFuture =
+            captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
+                                ui::PixelFormat::RGBA_8888, false /* allowProtected */,
+                                false /* grayscale */, captureListener);
+    return captureResultFuture.get().status;
 }
 
 status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -6098,23 +6116,28 @@
         });
     };
 
-    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, args.allowProtected, args.grayscale,
-                               captureListener);
+    if (captureListener == nullptr) {
+        ALOGE("capture screen must provide a capture listener callback");
+        return BAD_VALUE;
+    }
+
+    auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers,
+                                                   reqSize, args.pixelFormat, args.allowProtected,
+                                                   args.grayscale, captureListener);
+    return captureResultFuture.get().status;
 }
 
-status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
-                                             TraverseLayersFunction traverseLayers,
-                                             ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
-                                             bool allowProtected, bool grayscale,
-                                             const sp<IScreenCaptureListener>& captureListener) {
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
+        RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
+        ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale,
+        const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
     if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) {
         ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
               ") that exceeds render target size limit.",
               bufferSize.getWidth(), bufferSize.getHeight());
-        return BAD_VALUE;
+        return ftl::yield<renderengine::RenderEngineResult>({BAD_VALUE, base::unique_fd()}).share();
     }
 
     // Loop over all visible layers to see whether there's any protected layer. A protected layer is
@@ -6154,44 +6177,65 @@
                                false /* regionSampling */, grayscale, captureListener);
 }
 
-status_t SurfaceFlinger::captureScreenCommon(
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::captureScreenCommon(
         RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers,
         const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
         bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
-    if (captureListener == nullptr) {
-        ALOGE("capture screen must provide a capture listener callback");
-        return BAD_VALUE;
-    }
-
     bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
 
-    static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable {
+    auto scheduleResultFuture = schedule([=,
+                                          renderAreaFuture = std::move(renderAreaFuture)]() mutable
+                                         -> std::shared_future<renderengine::RenderEngineResult> {
         ScreenCaptureResults captureResults;
         std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
         if (!renderArea) {
             ALOGW("Skipping screen capture because of invalid render area.");
             captureResults.result = NO_MEMORY;
             captureListener->onScreenCaptureCompleted(captureResults);
-            return;
+            return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()})
+                    .share();
         }
 
-        status_t result = NO_ERROR;
+        std::shared_future<renderengine::RenderEngineResult> renderEngineResultFuture;
+
         renderArea->render([&] {
-            result = renderScreenImplLocked(*renderArea, traverseLayers, buffer,
-                                            canCaptureBlackoutContent, regionSampling, grayscale,
-                                            captureResults);
+            renderEngineResultFuture =
+                    renderScreenImplLocked(*renderArea, traverseLayers, buffer,
+                                           canCaptureBlackoutContent, regionSampling, grayscale,
+                                           captureResults);
         });
+        // spring up a thread to unblock SF main thread and wait for
+        // RenderEngineResult to be available
+        if (captureListener != nullptr) {
+            std::async([=]() mutable {
+                ATRACE_NAME("captureListener is nonnull!");
+                auto& [status, drawFence] = renderEngineResultFuture.get();
+                captureResults.result = status;
+                captureResults.fence = new Fence(dup(drawFence));
+                captureListener->onScreenCaptureCompleted(captureResults);
+            });
+        }
+        return renderEngineResultFuture;
+    });
 
-        captureResults.result = result;
-        captureListener->onScreenCaptureCompleted(captureResults);
-    }));
-
-    return NO_ERROR;
+    // flatten scheduleResultFuture object to single shared_future object
+    if (captureListener == nullptr) {
+        std::future<renderengine::RenderEngineResult> captureScreenResultFuture =
+                ftl::chain(std::move(scheduleResultFuture))
+                        .then([=](std::shared_future<renderengine::RenderEngineResult> futureObject)
+                                      -> renderengine::RenderEngineResult {
+                            auto& [status, drawFence] = futureObject.get();
+                            return {status, base::unique_fd(dup(drawFence))};
+                        });
+        return captureScreenResultFuture.share();
+    } else {
+        return ftl::yield<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}).share();
+    }
 }
 
-status_t SurfaceFlinger::renderScreenImplLocked(
+std::shared_future<renderengine::RenderEngineResult> SurfaceFlinger::renderScreenImplLocked(
         const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
         const std::shared_ptr<renderengine::ExternalTexture>& buffer,
         bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
@@ -6210,7 +6254,8 @@
     // the impetus on WindowManager to not persist them.
     if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
         ALOGW("FB is protected: PERMISSION_DENIED");
-        return PERMISSION_DENIED;
+        return ftl::yield<renderengine::RenderEngineResult>({PERMISSION_DENIED, base::unique_fd()})
+                .share();
     }
 
     captureResults.buffer = buffer->getBuffer();
@@ -6292,11 +6337,12 @@
 
     });
 
-    std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers(
-            clientCompositionLayers.size());
+    std::vector<renderengine::LayerSettings> clientRenderEngineLayers;
+    clientRenderEngineLayers.reserve(clientCompositionLayers.size());
     std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(),
-                   clientCompositionLayerPointers.begin(),
-                   std::pointer_traits<renderengine::LayerSettings*>::pointer_to);
+                   std::back_inserter(clientRenderEngineLayers),
+                   [](compositionengine::LayerFE::LayerSettings& settings)
+                           -> renderengine::LayerSettings { return settings; });
 
     // Use an empty fence for the buffer fence, since we just created the buffer so
     // there is no need for synchronization with the GPU.
@@ -6304,24 +6350,22 @@
     getRenderEngine().useProtectedContext(useProtected);
 
     const constexpr bool kUseFramebufferCache = false;
-    auto [status, drawFence] =
-            getRenderEngine()
-                    .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
-                                kUseFramebufferCache, std::move(bufferFence))
-                    .get();
+    std::future<renderengine::RenderEngineResult> drawLayersResult =
+            getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer,
+                                         kUseFramebufferCache, std::move(bufferFence));
 
-    if (drawFence >= 0) {
-        sp<Fence> releaseFence = new Fence(dup(drawFence));
-        for (auto* layer : renderedLayers) {
-            layer->onLayerDisplayed(releaseFence);
-        }
+    std::shared_future<renderengine::RenderEngineResult> drawLayersResultFuture =
+            drawLayersResult.share(); // drawLayersResult will be moved to shared one
+
+    for (auto* layer : renderedLayers) {
+        // make a copy of shared_future object for each layer
+        layer->onLayerDisplayed(drawLayersResultFuture);
     }
 
-    captureResults.fence = new Fence(drawFence.release());
     // Always switch back to unprotected context.
     getRenderEngine().useProtectedContext(false);
 
-    return status;
+    return drawLayersResultFuture;
 }
 
 void SurfaceFlinger::windowInfosReported() {
@@ -6449,8 +6493,10 @@
             using Policy = scheduler::RefreshRateConfigs::Policy;
             const Policy policy{DisplayModeId(defaultMode),
                                 allowGroupSwitching,
-                                {Fps(primaryRefreshRateMin), Fps(primaryRefreshRateMax)},
-                                {Fps(appRequestRefreshRateMin), Fps(appRequestRefreshRateMax)}};
+                                {Fps::fromValue(primaryRefreshRateMin),
+                                 Fps::fromValue(primaryRefreshRateMax)},
+                                {Fps::fromValue(appRequestRefreshRateMin),
+                                 Fps::fromValue(appRequestRefreshRateMax)}};
             constexpr bool kOverridePolicy = false;
 
             return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy);
@@ -6582,7 +6628,7 @@
             const auto strategy =
                     Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy);
             if (layer->setFrameRate(
-                        Layer::FrameRate(Fps{frameRate},
+                        Layer::FrameRate(Fps::fromValue(frameRate),
                                          Layer::FrameRate::convertCompatibility(compatibility),
                                          strategy))) {
                 setTransactionFlags(eTraversalNeeded);
@@ -6716,7 +6762,7 @@
 }
 
 status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
-    Fps maxRefreshRate(60.f);
+    Fps maxRefreshRate = 60_Hz;
 
     if (!getHwComposer().isHeadless()) {
         if (const auto display = getDefaultDisplayDevice()) {
@@ -6729,7 +6775,7 @@
 }
 
 uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const {
-    Fps refreshRate(60.f);
+    Fps refreshRate = 60_Hz;
 
     if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) {
         refreshRate = *frameRateOverride;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5fa509e..feee5df 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -712,7 +712,7 @@
     /*
      * Transactions
      */
-    void applyTransactionState(const FrameTimelineInfo& info, const Vector<ComposerState>& state,
+    bool applyTransactionState(const FrameTimelineInfo& info, const Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
                                const int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -722,15 +722,13 @@
                                int originPid, int originUid, uint64_t transactionId)
             REQUIRES(mStateLock);
     // flush pending transaction that was presented after desiredPresentTime.
-    void flushTransactionQueues();
+    bool flushTransactionQueues();
     // Returns true if there is at least one transaction that needs to be flushed
     bool transactionFlushNeeded();
 
     uint32_t setClientStateLocked(const FrameTimelineInfo&, const ComposerState&,
                                   int64_t desiredPresentTime, bool isAutoTimestamp,
-                                  int64_t postTime, uint32_t permissions,
-                                  std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>&)
-            REQUIRES(mStateLock);
+                                  int64_t postTime, uint32_t permissions) REQUIRES(mStateLock);
 
     uint32_t getTransactionFlags() const;
 
@@ -808,17 +806,17 @@
     // Boot animation, on/off animations and screen capture
     void startBootAnim();
 
-    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
-                                 ui::PixelFormat, bool allowProtected, bool grayscale,
-                                 const sp<IScreenCaptureListener>&);
-    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction,
-                                 const std::shared_ptr<renderengine::ExternalTexture>&,
-                                 bool regionSampling, bool grayscale,
-                                 const sp<IScreenCaptureListener>&);
-    status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
-                                    const std::shared_ptr<renderengine::ExternalTexture>&,
-                                    bool canCaptureBlackoutContent, bool regionSampling,
-                                    bool grayscale, ScreenCaptureResults&);
+    std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
+            RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat,
+            bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>&);
+    std::shared_future<renderengine::RenderEngineResult> captureScreenCommon(
+            RenderAreaFuture, TraverseLayersFunction,
+            const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
+            bool grayscale, const sp<IScreenCaptureListener>&);
+    std::shared_future<renderengine::RenderEngineResult> renderScreenImplLocked(
+            const RenderArea&, TraverseLayersFunction,
+            const std::shared_ptr<renderengine::ExternalTexture>&, bool canCaptureBlackoutContent,
+            bool regionSampling, bool grayscale, ScreenCaptureResults&);
 
     // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a
     // matching ownerUid
@@ -951,6 +949,11 @@
      */
     nsecs_t getVsyncPeriodFromHWC() const REQUIRES(mStateLock);
 
+    void setHWCVsyncEnabled(PhysicalDisplayId id, hal::Vsync enabled) {
+        mLastHWCVsyncState = enabled;
+        getHwComposer().setVsyncEnabled(id, enabled);
+    }
+
     // Sets the refresh rate by switching active configs, if they are available for
     // the desired refresh rate.
     void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock);
@@ -1110,7 +1113,6 @@
     std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
     bool mAnimTransactionPending = false;
     SortedVector<sp<Layer>> mLayersPendingRemoval;
-    bool mForceTraversal = false;
 
     // global color transform states
     Daltonizer mDaltonizer;
@@ -1304,6 +1306,7 @@
     std::atomic<nsecs_t> mExpectedPresentTime = 0;
     nsecs_t mScheduledPresentTime = 0;
     hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
+    hal::Vsync mLastHWCVsyncState = hal::Vsync::DISABLE;
 
     // below flags are set by main thread only
     bool mSetActiveModePending = false;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 9e70684..bdeaeb8 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -129,13 +129,15 @@
         nsecs_t displayPresentJitter = 0;
         nsecs_t appDeadlineDelta = 0;
 
+        static bool isOptApproxEqual(std::optional<Fps> lhs, std::optional<Fps> rhs) {
+            return (!lhs && !rhs) || (lhs && rhs && isApproxEqual(*lhs, *rhs));
+        }
+
         bool operator==(const JankyFramesInfo& o) const {
-            return Fps::EqualsInBuckets{}(refreshRate, o.refreshRate) &&
-                    ((renderRate == std::nullopt && o.renderRate == std::nullopt) ||
-                     (renderRate != std::nullopt && o.renderRate != std::nullopt &&
-                      Fps::EqualsInBuckets{}(*renderRate, *o.renderRate))) &&
-                    uid == o.uid && layerName == o.layerName && gameMode == o.gameMode &&
-                    reasons == o.reasons && displayDeadlineDelta == o.displayDeadlineDelta &&
+            return isApproxEqual(refreshRate, o.refreshRate) &&
+                    isOptApproxEqual(renderRate, o.renderRate) && uid == o.uid &&
+                    layerName == o.layerName && gameMode == o.gameMode && reasons == o.reasons &&
+                    displayDeadlineDelta == o.displayDeadlineDelta &&
                     displayPresentJitter == o.displayPresentJitter &&
                     appDeadlineDelta == o.appDeadlineDelta;
         }
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index c1eb896..f3d46ea 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -121,7 +121,7 @@
     return addCallbackHandle(handle, std::vector<JankData>());
 }
 
-status_t TransactionCallbackInvoker::findTransactionStats(
+status_t TransactionCallbackInvoker::findOrCreateTransactionStats(
         const sp<IBinder>& listener, const std::vector<CallbackId>& callbackIds,
         TransactionStats** outTransactionStats) {
     auto& transactionStatsDeque = mCompletedTransactions[listener];
@@ -143,7 +143,8 @@
     // If we can't find the transaction stats something has gone wrong. The client should call
     // startRegistration before trying to add a callback handle.
     TransactionStats* transactionStats;
-    status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
+    status_t err =
+            findOrCreateTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
     if (err != NO_ERROR) {
         return err;
     }
@@ -154,6 +155,38 @@
     // destroyed the client side is dead and there won't be anyone to send the callback to.
     sp<IBinder> surfaceControl = handle->surfaceControl.promote();
     if (surfaceControl) {
+        sp<Fence> prevFence = nullptr;
+
+        for (const auto& futureStruct : handle->previousReleaseFences) {
+            sp<Fence> currentFence = sp<Fence>::make(dup(futureStruct.get().drawFence));
+            if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) {
+                prevFence = currentFence;
+                handle->previousReleaseFence = prevFence;
+            } else if (prevFence != nullptr) {
+                // If both fences are signaled or both are unsignaled, we need to merge
+                // them to get an accurate timestamp.
+                if (prevFence->getStatus() != Fence::Status::Invalid &&
+                    prevFence->getStatus() == currentFence->getStatus()) {
+                    char fenceName[32] = {};
+                    snprintf(fenceName, 32, "%.28s", handle->name.c_str());
+                    sp<Fence> mergedFence = Fence::merge(fenceName, prevFence, currentFence);
+                    if (mergedFence->isValid()) {
+                        handle->previousReleaseFence = mergedFence;
+                        prevFence = handle->previousReleaseFence;
+                    }
+                } else if (currentFence->getStatus() == Fence::Status::Unsignaled) {
+                    // If one fence has signaled and the other hasn't, the unsignaled
+                    // fence will approximately correspond with the correct timestamp.
+                    // There's a small race if both fences signal at about the same time
+                    // and their statuses are retrieved with unfortunate timing. However,
+                    // by this point, they will have both signaled and only the timestamp
+                    // will be slightly off; any dependencies after this point will
+                    // already have been met.
+                    handle->previousReleaseFence = currentFence;
+                }
+            }
+        }
+        handle->previousReleaseFences = {};
         FrameEventHistoryStats eventStats(handle->frameNumber,
                                           handle->gpuCompositionDoneFence->getSnapshot().fence,
                                           handle->compositorTiming, handle->refreshStartTime,
@@ -172,7 +205,7 @@
     mPresentFence = presentFence;
 }
 
-void TransactionCallbackInvoker::sendCallbacks() {
+void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) {
     // For each listener
     auto completedTransactionsItr = mCompletedTransactions.begin();
     while (completedTransactionsItr != mCompletedTransactions.end()) {
@@ -184,6 +217,10 @@
         auto transactionStatsItr = transactionStatsDeque.begin();
         while (transactionStatsItr != transactionStatsDeque.end()) {
             auto& transactionStats = *transactionStatsItr;
+            if (onCommitOnly && !containsOnCommitCallbacks(transactionStats.callbackIds)) {
+                transactionStatsItr++;
+                continue;
+            }
 
             // If the transaction has been latched
             if (transactionStats.latchTime >= 0 &&
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 7e879e1..e203d41 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -18,8 +18,9 @@
 
 #include <condition_variable>
 #include <deque>
-#include <queue>
+#include <future>
 #include <mutex>
+#include <queue>
 #include <thread>
 #include <unordered_map>
 #include <unordered_set>
@@ -28,6 +29,7 @@
 
 #include <binder/IBinder.h>
 #include <gui/ITransactionCompletedListener.h>
+#include <renderengine/RenderEngine.h>
 #include <ui/Fence.h>
 
 namespace android {
@@ -42,7 +44,9 @@
     wp<IBinder> surfaceControl;
 
     bool releasePreviousBuffer = false;
+    std::string name;
     sp<Fence> previousReleaseFence;
+    std::vector<std::shared_future<renderengine::RenderEngineResult>> previousReleaseFences;
     nsecs_t acquireTime = -1;
     nsecs_t latchTime = -1;
     uint32_t transformHint = 0;
@@ -72,7 +76,7 @@
 
     void addPresentFence(const sp<Fence>& presentFence);
 
-    void sendCallbacks();
+    void sendCallbacks(bool onCommitOnly);
     void clearCompletedTransactions() {
         mCompletedTransactions.clear();
     }
@@ -82,11 +86,9 @@
 
 
 private:
-    status_t findTransactionStats(const sp<IBinder>& listener,
-                                  const std::vector<CallbackId>& callbackIds,
-                                  TransactionStats** outTransactionStats);
-
-
+    status_t findOrCreateTransactionStats(const sp<IBinder>& listener,
+                                          const std::vector<CallbackId>& callbackIds,
+                                          TransactionStats** outTransactionStats);
 
     std::unordered_map<sp<IBinder>, std::deque<TransactionStats>, IListenerHash>
         mCompletedTransactions;
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 9ddbed2..91a5b52 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -1029,4 +1029,60 @@
     EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
 }
 
+// b202394221
+TEST_F(LayerCallbackTest, EmptyBufferStateChanges) {
+    sp<SurfaceControl> bufferLayer, emptyBufferLayer;
+    ASSERT_NO_FATAL_FAILURE(bufferLayer = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(emptyBufferLayer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    for (size_t i = 0; i < 10; i++) {
+        int err = fillTransaction(transaction, &callback, bufferLayer);
+        if (err) {
+            GTEST_SUCCEED() << "test not supported";
+            return;
+        }
+
+        ui::Size bufferSize = getBufferSize();
+
+        TransactionUtils::setFrame(transaction, bufferLayer,
+                                   Rect(0, 0, bufferSize.width, bufferSize.height),
+                                   Rect(0, 0, 32, 32));
+        transaction.setPosition(emptyBufferLayer, 1 + i, 2 + i);
+        transaction.apply();
+
+        ExpectedResult expected;
+        expected.addSurface(ExpectedResult::Transaction::PRESENTED, bufferLayer,
+                            ExpectedResult::Buffer::ACQUIRED,
+                            (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+                                     : ExpectedResult::PreviousBuffer::RELEASED);
+        expected.addSurface(ExpectedResult::Transaction::PRESENTED, emptyBufferLayer,
+                            ExpectedResult::Buffer::NOT_ACQUIRED,
+                            ExpectedResult::PreviousBuffer::NOT_RELEASED);
+
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+// b202394221
+TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED));
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    transaction.setPosition(layer, 1, 2);
+    transaction.apply();
+
+    ExpectedResult expected;
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index da019a3..e15b081 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -124,7 +124,7 @@
         "android.hardware.power@1.1",
         "android.hardware.power@1.2",
         "android.hardware.power@1.3",
-        "android.hardware.power-V1-cpp",
+        "android.hardware.power-V2-cpp",
         "libcompositionengine_mocks",
         "libcompositionengine",
         "libframetimeline",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index a081291..40ef6e7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -245,10 +245,16 @@
                                                              "screenshot"),
                                            *mRenderEngine, true);
 
-    status_t result =
-            mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer,
-                                            forSystem, regionSampling);
-    EXPECT_EQ(NO_ERROR, result);
+    auto result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer,
+                                                  forSystem, regionSampling);
+    EXPECT_TRUE(result.valid());
+
+    auto& [status, drawFence] = result.get();
+
+    EXPECT_EQ(NO_ERROR, status);
+    if (drawFence.ok()) {
+        sync_wait(drawFence.get(), -1);
+    }
 
     LayerCase::cleanup(this);
 }
@@ -344,9 +350,9 @@
     static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
-                                    const std::vector<const renderengine::LayerSettings*>&,
+                                    const std::vector<renderengine::LayerSettings>&,
                                     const std::shared_ptr<renderengine::ExternalTexture>&,
-                                    const bool, base::unique_fd &&)
+                                    const bool, base::unique_fd&&)
                                         -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -395,9 +401,9 @@
                                 Return(0)));
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
-                                    const std::vector<const renderengine::LayerSettings*>&,
+                                    const std::vector<renderengine::LayerSettings>&,
                                     const std::shared_ptr<renderengine::ExternalTexture>&,
-                                    const bool, base::unique_fd &&)
+                                    const bool, base::unique_fd&&)
                                         -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -631,9 +637,9 @@
     static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
-                              const std::vector<const renderengine::LayerSettings*>& layerSettings,
+                              const std::vector<renderengine::LayerSettings>& layerSettings,
                               const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                              base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                              base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
@@ -650,16 +656,16 @@
                                          "verification lambda";
                         return resultFuture;
                     }
-                    const renderengine::LayerSettings* layer = layerSettings.back();
-                    EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull()));
-                    EXPECT_THAT(layer->source.buffer.fence, Not(IsNull()));
-                    EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName);
-                    EXPECT_EQ(false, layer->source.buffer.isY410BT2020);
-                    EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha);
-                    EXPECT_EQ(false, layer->source.buffer.isOpaque);
-                    EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
-                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
-                    EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
+                    const renderengine::LayerSettings layer = layerSettings.back();
+                    EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
+                    EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
+                    EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
+                    EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
+                    EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
+                    EXPECT_EQ(false, layer.source.buffer.isOpaque);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+                    EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
                     return resultFuture;
                 });
     }
@@ -683,9 +689,9 @@
     static void setupREColorCompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
-                              const std::vector<const renderengine::LayerSettings*>& layerSettings,
+                              const std::vector<renderengine::LayerSettings>& layerSettings,
                               const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                              base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                              base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
@@ -702,14 +708,14 @@
                                    "setupREColorCompositionCallExpectations verification lambda";
                         return resultFuture;
                     }
-                    const renderengine::LayerSettings* layer = layerSettings.back();
-                    EXPECT_THAT(layer->source.buffer.buffer, IsNull());
+                    const renderengine::LayerSettings layer = layerSettings.back();
+                    EXPECT_THAT(layer.source.buffer.buffer, IsNull());
                     EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
                                     LayerProperties::COLOR[2]),
-                              layer->source.solidColor);
-                    EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
-                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
-                    EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
+                              layer.source.solidColor);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+                    EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
                     return resultFuture;
                 });
     }
@@ -763,9 +769,9 @@
     static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
-                              const std::vector<const renderengine::LayerSettings*>& layerSettings,
+                              const std::vector<renderengine::LayerSettings>& layerSettings,
                               const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
-                              base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+                              base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
                     EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
                               displaySettings.physicalDisplay);
@@ -782,12 +788,12 @@
                                          "verification lambda";
                         return resultFuture;
                     }
-                    const renderengine::LayerSettings* layer = layerSettings.back();
-                    EXPECT_THAT(layer->source.buffer.buffer, IsNull());
-                    EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor);
-                    EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
-                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
-                    EXPECT_EQ(1.0f, layer->alpha);
+                    const renderengine::LayerSettings layer = layerSettings.back();
+                    EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+                    EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
+                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
+                    EXPECT_EQ(1.0f, layer.alpha);
                     return resultFuture;
                 });
     }
diff --git a/services/surfaceflinger/tests/unittests/FpsOps.h b/services/surfaceflinger/tests/unittests/FpsOps.h
new file mode 100644
index 0000000..23c2841
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FpsOps.h
@@ -0,0 +1,49 @@
+/*
+ * 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 "Fps.h"
+
+namespace android {
+
+// Pull Fps operators into its namespace to enable ADL for EXPECT_EQ, EXPECT_LT, etc.
+
+inline bool operator==(Fps lhs, Fps rhs) {
+    return fps_approx_ops::operator==(lhs, rhs);
+}
+
+inline bool operator<(Fps lhs, Fps rhs) {
+    return fps_approx_ops::operator<(lhs, rhs);
+}
+
+inline bool operator!=(Fps lhs, Fps rhs) {
+    return fps_approx_ops::operator!=(lhs, rhs);
+}
+
+inline bool operator>(Fps lhs, Fps rhs) {
+    return fps_approx_ops::operator>(lhs, rhs);
+}
+
+inline bool operator<=(Fps lhs, Fps rhs) {
+    return fps_approx_ops::operator<=(lhs, rhs);
+}
+
+inline bool operator>=(Fps lhs, Fps rhs) {
+    return fps_approx_ops::operator>=(lhs, rhs);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FpsTest.cpp b/services/surfaceflinger/tests/unittests/FpsTest.cpp
index db732cf..b44dd89 100644
--- a/services/surfaceflinger/tests/unittests/FpsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsTest.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "Fps.h"
+#include "FpsOps.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -22,77 +23,48 @@
 namespace android {
 
 TEST(FpsTest, construct) {
-    Fps fpsDefault;
-    EXPECT_FALSE(fpsDefault.isValid());
+    EXPECT_FALSE(Fps().isValid());
 
-    Fps fps1(60.0f);
-    EXPECT_TRUE(fps1.isValid());
-    Fps fps2 = Fps::fromPeriodNsecs(static_cast<nsecs_t>(1e9f / 60.0f));
-    EXPECT_TRUE(fps2.isValid());
-    EXPECT_TRUE(fps1.equalsWithMargin(fps2));
+    EXPECT_FALSE((0_Hz).isValid());
+    EXPECT_TRUE((120_Hz).isValid());
+    EXPECT_TRUE((0.5_Hz).isValid());
+
+    EXPECT_FALSE(Fps::fromPeriodNsecs(0).isValid());
+
+    const Fps fps = Fps::fromPeriodNsecs(16'666'667);
+    EXPECT_TRUE(fps.isValid());
+    EXPECT_EQ(fps, 60_Hz);
 }
 
 TEST(FpsTest, compare) {
-    constexpr float kEpsilon = 1e-4f;
-    const Fps::EqualsInBuckets equalsInBuckets;
-    const Fps::EqualsWithMargin equalsWithMargin;
+    EXPECT_EQ(60_Hz, 60_Hz);
+    EXPECT_EQ(60_Hz, 59.9999_Hz);
+    EXPECT_EQ(60_Hz, 60.0001_Hz);
 
-    EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f)));
-    EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f - kEpsilon)));
-    EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f + kEpsilon)));
+    EXPECT_LE(60_Hz, 60_Hz);
+    EXPECT_LE(60_Hz, 59.9999_Hz);
+    EXPECT_LE(60_Hz, 60.0001_Hz);
 
-    EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f)));
-    EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f - kEpsilon)));
-    EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f + kEpsilon)));
+    EXPECT_GE(60_Hz, 60_Hz);
+    EXPECT_GE(60_Hz, 59.9999_Hz);
+    EXPECT_GE(60_Hz, 60.0001_Hz);
 
-    EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f)));
-    EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f - kEpsilon)));
-    EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f + kEpsilon)));
-
-    EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f + kEpsilon)));
-    EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f)));
-    EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f - kEpsilon)));
-
-    EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f + kEpsilon)));
-    EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f)));
-    EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f - kEpsilon)));
-
-    // Fps with difference of 1 should be different
-    EXPECT_FALSE(Fps(60.0f).equalsWithMargin(Fps(61.f)));
-    EXPECT_TRUE(Fps(60.0f).lessThanWithMargin(Fps(61.f)));
-    EXPECT_TRUE(Fps(60.0f).greaterThanWithMargin(Fps(59.f)));
+    // Fps with difference of 1 should be different.
+    EXPECT_NE(60_Hz, 61_Hz);
+    EXPECT_LT(60_Hz, 61_Hz);
+    EXPECT_GT(60_Hz, 59_Hz);
 
     // These are common refresh rates which should be different.
-    EXPECT_FALSE(Fps(60.0f).equalsWithMargin(Fps(59.94f)));
-    EXPECT_TRUE(Fps(60.0f).greaterThanWithMargin(Fps(59.94f)));
-    EXPECT_FALSE(equalsInBuckets(Fps(60.0f), Fps(59.94f)));
-    EXPECT_FALSE(equalsWithMargin(Fps(60.0f), Fps(59.94f)));
-    EXPECT_NE(std::hash<Fps>()(Fps(60.0f)), std::hash<Fps>()(Fps(59.94f)));
-
-    EXPECT_FALSE(Fps(30.0f).equalsWithMargin(Fps(29.97f)));
-    EXPECT_TRUE(Fps(30.0f).greaterThanWithMargin(Fps(29.97f)));
-    EXPECT_FALSE(equalsInBuckets(Fps(30.0f), Fps(29.97f)));
-    EXPECT_FALSE(equalsWithMargin(Fps(30.0f), Fps(29.97f)));
-    EXPECT_NE(std::hash<Fps>()(Fps(30.0f)), std::hash<Fps>()(Fps(29.97f)));
+    EXPECT_NE(60_Hz, 59.94_Hz);
+    EXPECT_GT(60_Hz, 59.94_Hz);
+    EXPECT_NE(30_Hz, 29.97_Hz);
+    EXPECT_GT(30_Hz, 29.97_Hz);
 }
 
 TEST(FpsTest, getIntValue) {
-    EXPECT_EQ(30, Fps(30.1f).getIntValue());
-    EXPECT_EQ(31, Fps(30.9f).getIntValue());
-    EXPECT_EQ(31, Fps(30.5f).getIntValue());
-}
-
-TEST(FpsTest, equalsInBucketsImpliesEqualHashes) {
-    constexpr float kStep = 1e-4f;
-    const Fps::EqualsInBuckets equals;
-    for (float fps = 30.0f; fps < 31.0f; fps += kStep) {
-        const Fps left(fps);
-        const Fps right(fps + kStep);
-        if (equals(left, right)) {
-            ASSERT_EQ(std::hash<Fps>()(left), std::hash<Fps>()(right))
-                    << "left= " << left << " right=" << right;
-        }
-    }
+    EXPECT_EQ(30, (30.1_Hz).getIntValue());
+    EXPECT_EQ(31, (30.9_Hz).getIntValue());
+    EXPECT_EQ(31, (30.5_Hz).getIntValue());
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 97b60e0..9fbaece 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -559,7 +559,7 @@
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
-    Fps refreshRate = Fps(11.0);
+    Fps refreshRate = 11_Hz;
     EXPECT_CALL(*mTimeStats,
                 incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                                                                 sLayerNameOne, sGameMode,
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index bb21ad6..e8795fe 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -26,6 +26,7 @@
 #include <gtest/gtest.h>
 #include <log/log.h>
 
+#include "FpsOps.h"
 #include "Scheduler/LayerHistory.h"
 #include "Scheduler/LayerInfo.h"
 #include "TestableScheduler.h"
@@ -50,10 +51,10 @@
     static constexpr auto REFRESH_RATE_AVERAGE_HISTORY_DURATION =
             LayerInfo::RefreshRateHistory::HISTORY_DURATION;
 
-    static constexpr Fps LO_FPS{30.f};
+    static constexpr Fps LO_FPS = 30_Hz;
     static constexpr auto LO_FPS_PERIOD = LO_FPS.getPeriodNsecs();
 
-    static constexpr Fps HI_FPS{90.f};
+    static constexpr Fps HI_FPS = 90_Hz;
     static constexpr auto HI_FPS_PERIOD = HI_FPS.getPeriodNsecs();
 
     LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
@@ -111,8 +112,7 @@
 
         ASSERT_EQ(1, summary.size());
         ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
-        ASSERT_TRUE(desiredRefreshRate.equalsWithMargin(summary[0].desiredRefreshRate))
-                << "Frame rate is " << frameRate;
+        ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate);
     }
 
     std::shared_ptr<RefreshRateConfigs> mConfigs = std::make_shared<
@@ -149,7 +149,7 @@
     EXPECT_EQ(1, layerCount());
     EXPECT_EQ(0, activeLayerCount());
 
-    const nsecs_t time = systemTime();
+    nsecs_t time = systemTime();
 
     // No layers returned if no layers are active.
     EXPECT_TRUE(summarizeLayerHistory(time).empty());
@@ -161,6 +161,7 @@
         ASSERT_EQ(1, summarizeLayerHistory(time).size());
         EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
         EXPECT_EQ(1, activeLayerCount());
+        time += LO_FPS_PERIOD;
     }
 
     // Max is returned since we have enough history but there is no timestamp votes.
@@ -169,6 +170,7 @@
         ASSERT_EQ(1, summarizeLayerHistory(time).size());
         EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
         EXPECT_EQ(1, activeLayerCount());
+        time += LO_FPS_PERIOD;
     }
 }
 
@@ -213,7 +215,7 @@
 
     ASSERT_EQ(1, summarizeLayerHistory(time).size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
-    EXPECT_TRUE(LO_FPS.equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+    EXPECT_EQ(LO_FPS, summarizeLayerHistory(time)[0].desiredRefreshRate);
     EXPECT_EQ(1, activeLayerCount());
     EXPECT_EQ(1, frequentLayerCount(time));
 }
@@ -306,7 +308,7 @@
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
     EXPECT_CALL(*layer, getFrameRateForLayerTree())
             .WillRepeatedly(
-                    Return(Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::Default)));
+                    Return(Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::Default)));
 
     EXPECT_EQ(1, layerCount());
     EXPECT_EQ(0, activeLayerCount());
@@ -319,7 +321,7 @@
 
     ASSERT_EQ(1, summarizeLayerHistory(time).size());
     EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
-    EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+    EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
     EXPECT_EQ(1, activeLayerCount());
     EXPECT_EQ(1, frequentLayerCount(time));
 
@@ -328,7 +330,7 @@
     time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
     ASSERT_EQ(1, summarizeLayerHistory(time).size());
     EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
-    EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+    EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
     EXPECT_EQ(1, activeLayerCount());
     EXPECT_EQ(0, frequentLayerCount(time));
 }
@@ -338,7 +340,7 @@
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
     EXPECT_CALL(*layer, getFrameRateForLayerTree())
             .WillRepeatedly(Return(
-                    Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::ExactOrMultiple)));
+                    Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
 
     EXPECT_EQ(1, layerCount());
     EXPECT_EQ(0, activeLayerCount());
@@ -352,7 +354,7 @@
     ASSERT_EQ(1, summarizeLayerHistory(time).size());
     EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
               summarizeLayerHistory(time)[0].vote);
-    EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+    EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
     EXPECT_EQ(1, activeLayerCount());
     EXPECT_EQ(1, frequentLayerCount(time));
 
@@ -362,7 +364,7 @@
     ASSERT_EQ(1, summarizeLayerHistory(time).size());
     EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
               summarizeLayerHistory(time)[0].vote);
-    EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+    EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
     EXPECT_EQ(1, activeLayerCount());
     EXPECT_EQ(0, frequentLayerCount(time));
 }
@@ -414,7 +416,7 @@
     ASSERT_EQ(2, summary.size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
     ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
-    EXPECT_TRUE(HI_FPS.equalsWithMargin(summarizeLayerHistory(time)[1].desiredRefreshRate));
+    EXPECT_EQ(HI_FPS, summarizeLayerHistory(time)[1].desiredRefreshRate);
 
     EXPECT_EQ(2, activeLayerCount());
     EXPECT_EQ(1, frequentLayerCount(time));
@@ -429,7 +431,7 @@
 
     ASSERT_EQ(1, summary.size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
-    EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+    EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
     EXPECT_EQ(1, activeLayerCount());
     EXPECT_EQ(1, frequentLayerCount(time));
 
@@ -448,7 +450,7 @@
 
     ASSERT_EQ(2, summary.size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
-    EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+    EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
     EXPECT_EQ(LayerHistory::LayerVoteType::Max, summary[1].vote);
     EXPECT_EQ(2, activeLayerCount());
     EXPECT_EQ(2, frequentLayerCount(time));
@@ -458,9 +460,9 @@
     summary = summarizeLayerHistory(time);
     ASSERT_EQ(2, summary.size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
-    EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+    EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
-    EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate));
+    EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate);
     EXPECT_EQ(2, activeLayerCount());
     EXPECT_EQ(2, frequentLayerCount(time));
 
@@ -470,9 +472,9 @@
     ASSERT_EQ(2, summary.size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
-    EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+    EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
-    EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate));
+    EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate);
     EXPECT_EQ(2, layerCount());
     EXPECT_EQ(2, activeLayerCount());
     EXPECT_EQ(2, frequentLayerCount(time));
@@ -487,7 +489,7 @@
 
     ASSERT_EQ(1, summary.size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
-    EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+    EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
     EXPECT_EQ(1, activeLayerCount());
     EXPECT_EQ(1, frequentLayerCount(time));
 
@@ -508,7 +510,7 @@
 
     ASSERT_EQ(1, summary.size());
     EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
-    EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
+    EXPECT_EQ(HI_FPS, summary[0].desiredRefreshRate);
     EXPECT_EQ(1, layerCount());
     EXPECT_EQ(1, activeLayerCount());
     EXPECT_EQ(1, frequentLayerCount(time));
@@ -585,12 +587,12 @@
     EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true));
     EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree())
             .WillRepeatedly(Return(
-                    Layer::FrameRate(Fps(60.0f), Layer::FrameRateCompatibility::ExactOrMultiple)));
+                    Layer::FrameRate(60_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
 
     EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false));
     EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree())
             .WillRepeatedly(Return(
-                    Layer::FrameRate(Fps(90.0f), Layer::FrameRateCompatibility::ExactOrMultiple)));
+                    Layer::FrameRate(90_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
 
     nsecs_t time = systemTime();
 
@@ -603,7 +605,7 @@
     ASSERT_EQ(1, summarizeLayerHistory(time).size());
     EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
               summarizeLayerHistory(time)[0].vote);
-    EXPECT_TRUE(Fps(60.0f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
+    EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
     EXPECT_EQ(2, activeLayerCount());
     EXPECT_EQ(2, frequentLayerCount(time));
 }
@@ -661,7 +663,7 @@
 
     nsecs_t time = systemTime();
     for (float fps = 54.0f; fps < 65.0f; fps += 0.1f) {
-        recordFramesAndExpect(layer, time, Fps(fps), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
+        recordFramesAndExpect(layer, time, Fps::fromValue(fps), 60_Hz, PRESENT_TIME_HISTORY_SIZE);
     }
 }
 
@@ -671,13 +673,13 @@
     EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
 
     nsecs_t time = systemTime();
-    recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
 
-    recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
-    recordFramesAndExpect(layer, time, Fps(30.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
-    recordFramesAndExpect(layer, time, Fps(30.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
-    recordFramesAndExpect(layer, time, Fps(60.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
-    recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 30_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 30_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 60_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
 }
 
 TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) {
@@ -687,11 +689,11 @@
 
     nsecs_t time = systemTime();
 
-    recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
-    recordFramesAndExpect(layer, time, Fps(26.90f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
-    recordFramesAndExpect(layer, time, Fps(26.00f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE);
-    recordFramesAndExpect(layer, time, Fps(26.90f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE);
-    recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
 }
 
 class LayerHistoryTestParameterized : public LayerHistoryTest,
@@ -742,7 +744,7 @@
 
             bool max = false;
             bool min = false;
-            Fps heuristic{0.0};
+            Fps heuristic;
             for (const auto& layer : summarizeLayerHistory(time)) {
                 if (layer.vote == LayerHistory::LayerVoteType::Heuristic) {
                     heuristic = layer.desiredRefreshRate;
@@ -754,7 +756,7 @@
             }
 
             if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) {
-                EXPECT_TRUE(Fps(24.0f).equalsWithMargin(heuristic));
+                EXPECT_EQ(24_Hz, heuristic);
                 EXPECT_FALSE(max);
                 if (summarizeLayerHistory(time).size() == 2) {
                     EXPECT_TRUE(min);
@@ -772,4 +774,4 @@
 } // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
index d6ce5e2..f25994e 100644
--- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -20,6 +20,7 @@
 #include <gtest/gtest.h>
 
 #include "Fps.h"
+#include "FpsOps.h"
 #include "Scheduler/LayerHistory.h"
 #include "Scheduler/LayerInfo.h"
 
@@ -47,7 +48,7 @@
 
 TEST_F(LayerInfoTest, prefersPresentTime) {
     std::deque<FrameTimeData> frameTimes;
-    constexpr auto kExpectedFps = Fps(50.0f);
+    constexpr auto kExpectedFps = 50_Hz;
     constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
     constexpr int kNumFrames = 10;
     for (int i = 1; i <= kNumFrames; i++) {
@@ -58,14 +59,12 @@
     setFrameTimes(frameTimes);
     const auto averageFrameTime = calculateAverageFrameTime();
     ASSERT_TRUE(averageFrameTime.has_value());
-    const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
-    ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
-            << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+    ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
 }
 
 TEST_F(LayerInfoTest, fallbacksToQueueTimeIfNoPresentTime) {
     std::deque<FrameTimeData> frameTimes;
-    constexpr auto kExpectedFps = Fps(50.0f);
+    constexpr auto kExpectedFps = 50_Hz;
     constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
     constexpr int kNumFrames = 10;
     for (int i = 1; i <= kNumFrames; i++) {
@@ -74,17 +73,15 @@
                                            .pendingModeChange = false});
     }
     setFrameTimes(frameTimes);
-    setLastRefreshRate(Fps(20.0f)); // Set to some valid value
+    setLastRefreshRate(20_Hz); // Set to some valid value.
     const auto averageFrameTime = calculateAverageFrameTime();
     ASSERT_TRUE(averageFrameTime.has_value());
-    const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
-    ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
-            << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+    ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
 }
 
 TEST_F(LayerInfoTest, returnsNulloptIfThereWasConfigChange) {
     std::deque<FrameTimeData> frameTimesWithoutConfigChange;
-    const auto period = Fps(50.0f).getPeriodNsecs();
+    const auto period = (50_Hz).getPeriodNsecs();
     constexpr int kNumFrames = 10;
     for (int i = 1; i <= kNumFrames; i++) {
         frameTimesWithoutConfigChange.push_back(FrameTimeData{.presentTime = period * i,
@@ -124,9 +121,9 @@
 // Make sure that this doesn't influence the calculated average FPS.
 TEST_F(LayerInfoTest, ignoresSmallPeriods) {
     std::deque<FrameTimeData> frameTimes;
-    constexpr auto kExpectedFps = Fps(50.0f);
+    constexpr auto kExpectedFps = 50_Hz;
     constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
-    constexpr auto kSmallPeriod = Fps(250.0f).getPeriodNsecs();
+    constexpr auto kSmallPeriod = (250_Hz).getPeriodNsecs();
     constexpr int kNumIterations = 10;
     for (int i = 1; i <= kNumIterations; i++) {
         frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i,
@@ -141,18 +138,16 @@
     setFrameTimes(frameTimes);
     const auto averageFrameTime = calculateAverageFrameTime();
     ASSERT_TRUE(averageFrameTime.has_value());
-    const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
-    ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
-            << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+    ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
 }
 
 // There may be a big period of time between two frames. Make sure that
 // this doesn't influence the calculated average FPS.
 TEST_F(LayerInfoTest, ignoresLargePeriods) {
     std::deque<FrameTimeData> frameTimes;
-    constexpr auto kExpectedFps = Fps(50.0f);
+    constexpr auto kExpectedFps = 50_Hz;
     constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
-    constexpr auto kLargePeriod = Fps(9.0f).getPeriodNsecs();
+    constexpr auto kLargePeriod = (9_Hz).getPeriodNsecs();
 
     auto record = [&](nsecs_t time) {
         frameTimes.push_back(
@@ -172,9 +167,7 @@
     setFrameTimes(frameTimes);
     const auto averageFrameTime = calculateAverageFrameTime();
     ASSERT_TRUE(averageFrameTime.has_value());
-    const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
-    ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
-            << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+    ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime));
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index a8e3e5e..fc84d48 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -27,15 +27,13 @@
 
 #include <ui/Size.h>
 
-#include "../../Scheduler/RefreshRateConfigs.h"
 #include "DisplayHardware/HWC2.h"
+#include "FpsOps.h"
 #include "Scheduler/RefreshRateConfigs.h"
 
 using namespace std::chrono_literals;
 
-namespace android {
-
-namespace scheduler {
+namespace android::scheduler {
 
 namespace hal = android::hardware::graphics::composer::hal;
 
@@ -104,33 +102,32 @@
     static inline const DisplayModeId HWC_CONFIG_ID_60_FRAC = DisplayModeId(10);
 
     // Test configs
-    DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
+    DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, (60_Hz).getPeriodNsecs());
     DisplayModePtr mConfig60Frac =
-            createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, Fps(59.94f).getPeriodNsecs());
-    DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, (59.94_Hz).getPeriodNsecs());
+    DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, (90_Hz).getPeriodNsecs());
     DisplayModePtr mConfig90DifferentGroup =
-            createDisplayMode(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_90, 1, (90_Hz).getPeriodNsecs());
     DisplayModePtr mConfig90DifferentResolution =
-            createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs(), ui::Size(111, 222));
-    DisplayModePtr mConfig72 = createDisplayMode(HWC_CONFIG_ID_72, 0, Fps(72.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_90, 0, (90_Hz).getPeriodNsecs(), ui::Size(111, 222));
+    DisplayModePtr mConfig72 = createDisplayMode(HWC_CONFIG_ID_72, 0, (72_Hz).getPeriodNsecs());
     DisplayModePtr mConfig72DifferentGroup =
-            createDisplayMode(HWC_CONFIG_ID_72, 1, Fps(72.0f).getPeriodNsecs());
-    DisplayModePtr mConfig120 =
-            createDisplayMode(HWC_CONFIG_ID_120, 0, Fps(120.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_72, 1, (72_Hz).getPeriodNsecs());
+    DisplayModePtr mConfig120 = createDisplayMode(HWC_CONFIG_ID_120, 0, (120_Hz).getPeriodNsecs());
     DisplayModePtr mConfig120DifferentGroup =
-            createDisplayMode(HWC_CONFIG_ID_120, 1, Fps(120.0f).getPeriodNsecs());
-    DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_120, 1, (120_Hz).getPeriodNsecs());
+    DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, (30_Hz).getPeriodNsecs());
     DisplayModePtr mConfig30DifferentGroup =
-            createDisplayMode(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_30, 1, (30_Hz).getPeriodNsecs());
     DisplayModePtr mConfig30Frac =
-            createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, Fps(29.97f).getPeriodNsecs());
-    DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, Fps(25.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, (29.97_Hz).getPeriodNsecs());
+    DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, (25_Hz).getPeriodNsecs());
     DisplayModePtr mConfig25DifferentGroup =
-            createDisplayMode(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
-    DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
-    DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, Fps(24.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_25, 1, (25_Hz).getPeriodNsecs());
+    DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, (50_Hz).getPeriodNsecs());
+    DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, (24_Hz).getPeriodNsecs());
     DisplayModePtr mConfig24Frac =
-            createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, Fps(23.976f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, (23.976_Hz).getPeriodNsecs());
 
     // Test device configurations
     // The positions of the configs in the arrays below MUST match their IDs. For example,
@@ -206,9 +203,7 @@
 }
 
 namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
 TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingSupported) {
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
@@ -219,10 +214,8 @@
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
-    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(10), {Fps(60), Fps(60)}}),
-              0);
-    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(20), Fps(40)}}),
-              0);
+    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(10), {60_Hz, 60_Hz}}), 0);
+    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20_Hz, 40_Hz}}), 0);
 }
 
 TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
@@ -256,8 +249,7 @@
     ASSERT_EQ(mExpected60Config, minRate60);
     ASSERT_EQ(mExpected60Config, performanceRate60);
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60_Hz, 90_Hz}}), 0);
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
 
     const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs);
@@ -282,8 +274,7 @@
     ASSERT_EQ(mExpected60Config, minRate60);
     ASSERT_EQ(mExpected60Config, performanceRate60);
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60_Hz, 90_Hz}}), 0);
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
 
     const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs);
@@ -305,8 +296,7 @@
     ASSERT_EQ(mExpected60Config, minRate);
     ASSERT_EQ(mExpected90Config, performanceRate);
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0);
 
     auto minRate60 = getMinRefreshRateByPolicy(*refreshRateConfigs);
     auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -329,8 +319,7 @@
         EXPECT_EQ(current.getModeId(), HWC_CONFIG_ID_90);
     }
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90_Hz, 90_Hz}}), 0);
     {
         auto current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.getModeId(), HWC_CONFIG_ID_90);
@@ -344,23 +333,19 @@
 
     // If there are no layers we select the default frame rate, which is the max of the primary
     // range.
-    auto layers = std::vector<LayerRequirement>{};
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate({}, {}));
 
-    ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
+    ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}),
               NO_ERROR);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate({}, {}));
 
     // We select max even when this will cause a non-seamless switch.
     refreshRateConfigs = std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
                                                               /*currentConfigId=*/HWC_CONFIG_ID_60);
     ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {Fps(0), Fps(90)}}),
+                      {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {0_Hz, 90_Hz}}),
               NO_ERROR);
-    EXPECT_EQ(mExpected90DifferentGroupConfig,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90DifferentGroupConfig, refreshRateConfigs->getBestRefreshRate({}, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) {
@@ -368,142 +353,109 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::Min;
     lr.name = "Min";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Max;
     lr.name = "Max";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(90.0f);
+    lr.desiredRefreshRate = 90_Hz;
     lr.vote = LayerVoteType::Heuristic;
     lr.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(60.0f);
+    lr.desiredRefreshRate = 60_Hz;
     lr.name = "60Hz Heuristic";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(45.0f);
+    lr.desiredRefreshRate = 45_Hz;
     lr.name = "45Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(30.0f);
+    lr.desiredRefreshRate = 30_Hz;
     lr.name = "30Hz Heuristic";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(24.0f);
+    lr.desiredRefreshRate = 24_Hz;
     lr.name = "24Hz Heuristic";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.name = "";
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0);
 
     lr.vote = LayerVoteType::Min;
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Max;
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(90.0f);
+    lr.desiredRefreshRate = 90_Hz;
     lr.vote = LayerVoteType::Heuristic;
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(60.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(45.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 45_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(30.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 30_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(24.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 24_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_90, {Fps(90.0f), Fps(90.0f)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90_Hz, 90_Hz}}), 0);
 
     lr.vote = LayerVoteType::Min;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Max;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(90.0f);
+    lr.desiredRefreshRate = 90_Hz;
     lr.vote = LayerVoteType::Heuristic;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(60.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(45.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 45_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(30.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 30_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(24.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 24_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_60, {Fps(0.0f), Fps(120.0f)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0_Hz, 120_Hz}}), 0);
     lr.vote = LayerVoteType::Min;
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Max;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(90.0f);
+    lr.desiredRefreshRate = 90_Hz;
     lr.vote = LayerVoteType::Heuristic;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(60.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(45.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 45_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(30.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 30_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(24.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 24_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_multipleThreshold_60_90) {
@@ -512,44 +464,37 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60, config);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::Min;
     lr.name = "Min";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Max;
     lr.name = "Max";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(90.0f);
+    lr.desiredRefreshRate = 90_Hz;
     lr.vote = LayerVoteType::Heuristic;
     lr.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(60.0f);
+    lr.desiredRefreshRate = 60_Hz;
     lr.name = "60Hz Heuristic";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(45.0f);
+    lr.desiredRefreshRate = 45_Hz;
     lr.name = "45Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(30.0f);
+    lr.desiredRefreshRate = 30_Hz;
     lr.name = "30Hz Heuristic";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(24.0f);
+    lr.desiredRefreshRate = 24_Hz;
     lr.name = "24Hz Heuristic";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) {
@@ -557,37 +502,30 @@
             std::make_unique<RefreshRateConfigs>(m60_72_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::Min;
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Max;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(90.0f);
+    lr.desiredRefreshRate = 90_Hz;
     lr.vote = LayerVoteType::Heuristic;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(60.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(45.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 45_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(30.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 30_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(24.0f);
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 24_Hz;
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) {
@@ -595,31 +533,27 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.vote = LayerVoteType::Heuristic;
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(48.0f);
+    lr2.desiredRefreshRate = 48_Hz;
     lr2.vote = LayerVoteType::Heuristic;
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(48.0f);
+    lr2.desiredRefreshRate = 48_Hz;
     lr2.vote = LayerVoteType::Heuristic;
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) {
@@ -627,91 +561,81 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.name = "24Hz ExplicitDefault";
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "60Hz Heuristic";
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "60Hz Heuristic";
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "60Hz ExplicitDefault";
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.name = "24Hz ExplicitDefault";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::Heuristic;
     lr1.name = "24Hz Heuristic";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz ExplicitDefault";
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz ExplicitDefault";
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.name = "24Hz ExplicitDefault";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.name = "90Hz ExplicitExactOrMultiple";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_multipleThreshold) {
@@ -720,91 +644,81 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60, config);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.name = "24Hz ExplicitDefault";
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "60Hz Heuristic";
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "60Hz Heuristic";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "60Hz ExplicitDefault";
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.name = "24Hz ExplicitDefault";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::Heuristic;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::Heuristic;
     lr1.name = "24Hz Heuristic";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz ExplicitDefault";
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr1.name = "24Hz ExplicitExactOrMultiple";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitDefault;
     lr2.name = "90Hz ExplicitDefault";
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr1.desiredRefreshRate = Fps(24.0f);
+    lr1.desiredRefreshRate = 24_Hz;
     lr1.vote = LayerVoteType::ExplicitDefault;
     lr1.name = "24Hz ExplicitDefault";
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr2.name = "90Hz ExplicitExactOrMultiple";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
@@ -812,37 +726,30 @@
             std::make_unique<RefreshRateConfigs>(m30_60Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::Min;
-    EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Max;
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(90.0f);
+    lr.desiredRefreshRate = 90_Hz;
     lr.vote = LayerVoteType::Heuristic;
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(60.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(45.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 45_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(30.0f);
-    EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 30_Hz;
+    EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(24.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr.desiredRefreshRate = 24_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) {
@@ -850,60 +757,47 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::Min;
     lr.name = "Min";
-    EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Max;
     lr.name = "Max";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(90.0f);
+    lr.desiredRefreshRate = 90_Hz;
     lr.vote = LayerVoteType::Heuristic;
     lr.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    lr.desiredRefreshRate = Fps(60.0f);
+    lr.desiredRefreshRate = 60_Hz;
     lr.name = "60Hz Heuristic";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 
-    lr.desiredRefreshRate = Fps(45.0f);
+    lr.desiredRefreshRate = 45_Hz;
     lr.name = "45Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 
-    lr.desiredRefreshRate = Fps(30.0f);
+    lr.desiredRefreshRate = 30_Hz;
     lr.name = "30Hz Heuristic";
-    EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 
-    lr.desiredRefreshRate = Fps(24.0f);
+    lr.desiredRefreshRate = 24_Hz;
     lr.name = "24Hz Heuristic";
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 
-    lr.desiredRefreshRate = Fps(24.0f);
+    lr.desiredRefreshRate = 24_Hz;
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr.name = "24Hz ExplicitExactOrMultiple";
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) {
@@ -911,53 +805,45 @@
             std::make_unique<RefreshRateConfigs>(m30_60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
 
     lr1.vote = LayerVoteType::Min;
     lr2.vote = LayerVoteType::Max;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::Min;
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(24.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr2.desiredRefreshRate = 24_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::Min;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr2.desiredRefreshRate = Fps(24.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr2.desiredRefreshRate = 24_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::Max;
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(60.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr2.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::Max;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr2.desiredRefreshRate = Fps(60.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr2.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::Heuristic;
-    lr1.desiredRefreshRate = Fps(15.0f);
+    lr1.desiredRefreshRate = 15_Hz;
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(45.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr2.desiredRefreshRate = 45_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::Heuristic;
-    lr1.desiredRefreshRate = Fps(30.0f);
+    lr1.desiredRefreshRate = 30_Hz;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr2.desiredRefreshRate = Fps(45.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr2.desiredRefreshRate = 45_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) {
@@ -965,15 +851,15 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
     for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
-        lr.desiredRefreshRate = Fps(fps);
-        const auto& refreshRate =
-                refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
-        EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+        lr.desiredRefreshRate = Fps::fromValue(fps);
+        const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+        EXPECT_EQ(mExpected60Config, refreshRate)
+                << lr.desiredRefreshRate << " chooses " << refreshRate.getName();
     }
 }
 
@@ -983,15 +869,15 @@
             std::make_unique<RefreshRateConfigs>(m60_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60, config);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
     for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
-        lr.desiredRefreshRate = Fps(fps);
-        const auto& refreshRate =
-                refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
-        EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+        lr.desiredRefreshRate = Fps::fromValue(fps);
+        const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+        EXPECT_EQ(mExpected60Config, refreshRate)
+                << lr.desiredRefreshRate << " chooses " << refreshRate.getName();
     }
 }
 
@@ -1000,39 +886,35 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
 
     lr1.vote = LayerVoteType::Heuristic;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr2.desiredRefreshRate = Fps(90.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr2.desiredRefreshRate = 90_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::ExplicitDefault;
-    lr1.desiredRefreshRate = Fps(90.0f);
+    lr1.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr2.desiredRefreshRate = Fps(60.0f);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr2.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::Heuristic;
-    lr1.desiredRefreshRate = Fps(90.0f);
+    lr1.desiredRefreshRate = 90_Hz;
     lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr2.desiredRefreshRate = Fps(60.0f);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    lr2.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, testInPolicy) {
-    ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(Fps(60.000004f), Fps(60.000004f)));
-    ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(Fps(59.0f), Fps(60.1f)));
-    ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(75.0f), Fps(90.0f)));
-    ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(60.0011f), Fps(90.0f)));
-    ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(50.0f), Fps(59.998f)));
+    ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(60.000004_Hz, 60.000004_Hz));
+    ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(59_Hz, 60.1_Hz));
+    ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(75_Hz, 90_Hz));
+    ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(60.0011_Hz, 90_Hz));
+    ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(50_Hz, 59.998_Hz));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
@@ -1040,15 +922,15 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
     for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
-        lr.desiredRefreshRate = Fps(fps);
-        const auto& refreshRate =
-                refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
-        EXPECT_EQ(mExpected90Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+        lr.desiredRefreshRate = Fps::fromValue(fps);
+        const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+        EXPECT_EQ(mExpected90Config, refreshRate)
+                << lr.desiredRefreshRate << " chooses " << refreshRate.getName();
     }
 }
 
@@ -1057,53 +939,47 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::ExplicitDefault;
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.name = "90Hz ExplicitDefault";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(30.0f);
+    lr1.desiredRefreshRate = 30_Hz;
     lr1.name = "30Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(30.0f);
+    lr1.desiredRefreshRate = 30_Hz;
     lr1.name = "30Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
@@ -1111,52 +987,46 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::NoVote;
     lr2.name = "NoVote";
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::NoVote;
     lr2.name = "NoVote";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Max;
     lr2.name = "Max";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     // The other layer starts to provide buffers
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(90.0f);
+    lr2.desiredRefreshRate = 90_Hz;
     lr2.name = "90Hz Heuristic";
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, touchConsidered) {
@@ -1165,55 +1035,50 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false}, &consideredSignals);
+    refreshRateConfigs->getBestRefreshRate({}, {}, &consideredSignals);
     EXPECT_EQ(false, consideredSignals.touch);
 
-    refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = false}, &consideredSignals);
+    refreshRateConfigs->getBestRefreshRate({}, {.touch = true}, &consideredSignals);
     EXPECT_EQ(true, consideredSignals.touch);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
     auto& lr1 = layers[0];
     auto& lr2 = layers[1];
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.name = "60Hz Heuristic";
-    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
-                                           &consideredSignals);
+    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals);
     EXPECT_EQ(true, consideredSignals.touch);
 
     lr1.vote = LayerVoteType::ExplicitDefault;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.name = "60Hz Heuristic";
-    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
-                                           &consideredSignals);
+    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals);
     EXPECT_EQ(false, consideredSignals.touch);
 
     lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.name = "60Hz Heuristic";
-    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
-                                           &consideredSignals);
+    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals);
     EXPECT_EQ(true, consideredSignals.touch);
 
     lr1.vote = LayerVoteType::ExplicitDefault;
-    lr1.desiredRefreshRate = Fps(60.0f);
+    lr1.desiredRefreshRate = 60_Hz;
     lr1.name = "60Hz ExplicitExactOrMultiple";
     lr2.vote = LayerVoteType::Heuristic;
-    lr2.desiredRefreshRate = Fps(60.0f);
+    lr2.desiredRefreshRate = 60_Hz;
     lr2.name = "60Hz Heuristic";
-    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
-                                           &consideredSignals);
+    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals);
     EXPECT_EQ(false, consideredSignals.touch);
 }
 
@@ -1222,47 +1087,44 @@
             std::make_unique<RefreshRateConfigs>(m60_90_72_120Device, /*currentConfigId=*/
                                                  HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     // Prepare a table with the vote and the expected refresh rate
-    const std::vector<std::pair<float, float>> testCases = {
-            {130, 120}, {120, 120}, {119, 120}, {110, 120},
+    const std::initializer_list<std::pair<Fps, Fps>> testCases = {
+            {130_Hz, 120_Hz}, {120_Hz, 120_Hz}, {119_Hz, 120_Hz}, {110_Hz, 120_Hz},
 
-            {100, 90},  {90, 90},   {89, 90},
+            {100_Hz, 90_Hz},  {90_Hz, 90_Hz},   {89_Hz, 90_Hz},
 
-            {80, 72},   {73, 72},   {72, 72},   {71, 72},   {70, 72},
+            {80_Hz, 72_Hz},   {73_Hz, 72_Hz},   {72_Hz, 72_Hz},   {71_Hz, 72_Hz},   {70_Hz, 72_Hz},
 
-            {65, 60},   {60, 60},   {59, 60},   {58, 60},
+            {65_Hz, 60_Hz},   {60_Hz, 60_Hz},   {59_Hz, 60_Hz},   {58_Hz, 60_Hz},
 
-            {55, 90},   {50, 90},   {45, 90},
+            {55_Hz, 90_Hz},   {50_Hz, 90_Hz},   {45_Hz, 90_Hz},
 
-            {42, 120},  {40, 120},  {39, 120},
+            {42_Hz, 120_Hz},  {40_Hz, 120_Hz},  {39_Hz, 120_Hz},
 
-            {37, 72},   {36, 72},   {35, 72},
+            {37_Hz, 72_Hz},   {36_Hz, 72_Hz},   {35_Hz, 72_Hz},
 
-            {30, 60},
+            {30_Hz, 60_Hz},
     };
 
-    for (const auto& test : testCases) {
+    for (auto [desired, expected] : testCases) {
         lr.vote = LayerVoteType::ExplicitDefault;
-        lr.desiredRefreshRate = Fps(test.first);
+        lr.desiredRefreshRate = desired;
 
         std::stringstream ss;
-        ss << "ExplicitDefault " << test.first << " fps";
+        ss << "ExplicitDefault " << desired;
         lr.name = ss.str();
 
-        const auto& refreshRate =
-                refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
-        EXPECT_TRUE(refreshRate.getFps().equalsWithMargin(Fps(test.second)))
-                << "Expecting " << test.first << "fps => " << test.second << "Hz"
-                << " but it was " << refreshRate.getFps();
+        const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+        EXPECT_EQ(refreshRate.getFps(), expected);
     }
 }
 
 TEST_F(RefreshRateConfigsTest,
        getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) {
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     // Test that 23.976 will choose 24 if 23.976 is not supported
@@ -1273,11 +1135,9 @@
                 std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
 
         lr.vote = LayerVoteType::ExplicitExactOrMultiple;
-        lr.desiredRefreshRate = Fps(23.976f);
-        lr.name = "ExplicitExactOrMultiple 23.976 fps";
-        EXPECT_EQ(HWC_CONFIG_ID_24,
-                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                          .getModeId());
+        lr.desiredRefreshRate = 23.976_Hz;
+        lr.name = "ExplicitExactOrMultiple 23.976 Hz";
+        EXPECT_EQ(HWC_CONFIG_ID_24, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
     }
 
     // Test that 24 will choose 23.976 if 24 is not supported
@@ -1286,11 +1146,10 @@
                                        mConfig30Frac, mConfig60, mConfig60Frac};
         auto refreshRateConfigs =
                 std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
-        lr.desiredRefreshRate = Fps(24.f);
-        lr.name = "ExplicitExactOrMultiple 24 fps";
+        lr.desiredRefreshRate = 24_Hz;
+        lr.name = "ExplicitExactOrMultiple 24 Hz";
         EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
-                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                          .getModeId());
+                  refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
     }
 
     // Test that 29.97 will prefer 59.94 over 60 and 30
@@ -1299,16 +1158,15 @@
                                        mConfig30, mConfig60,     mConfig60Frac};
         auto refreshRateConfigs =
                 std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
-        lr.desiredRefreshRate = Fps(29.97f);
-        lr.name = "ExplicitExactOrMultiple 29.97f fps";
+        lr.desiredRefreshRate = 29.97_Hz;
+        lr.name = "ExplicitExactOrMultiple 29.97 Hz";
         EXPECT_EQ(HWC_CONFIG_ID_60_FRAC,
-                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                          .getModeId());
+                  refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
     }
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) {
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     // Test that voting for supported refresh rate will select this refresh rate
@@ -1317,19 +1175,15 @@
                 std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
                                                      /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-        for (auto desiredRefreshRate : {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f}) {
+        for (auto desired : {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz}) {
             lr.vote = LayerVoteType::ExplicitExact;
-            lr.desiredRefreshRate = Fps(desiredRefreshRate);
+            lr.desiredRefreshRate = desired;
             std::stringstream ss;
-            ss << "ExplicitExact " << desiredRefreshRate << " fps";
+            ss << "ExplicitExact " << desired;
             lr.name = ss.str();
 
-            auto selecteRefreshRate =
-                    refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
-
-            EXPECT_TRUE(selecteRefreshRate.getFps().equalsWithMargin(lr.desiredRefreshRate))
-                    << "Expecting " << lr.desiredRefreshRate << " but it was "
-                    << selecteRefreshRate.getFps();
+            auto selectedRefreshRate = refreshRateConfigs->getBestRefreshRate(layers, {});
+            EXPECT_EQ(selectedRefreshRate.getFps(), lr.desiredRefreshRate);
         }
     }
 
@@ -1340,11 +1194,9 @@
         auto refreshRateConfigs =
                 std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
         lr.vote = LayerVoteType::ExplicitExact;
-        lr.desiredRefreshRate = Fps(23.976f);
-        lr.name = "ExplicitExact 23.976 fps";
-        EXPECT_EQ(HWC_CONFIG_ID_24,
-                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                          .getModeId());
+        lr.desiredRefreshRate = 23.976_Hz;
+        lr.name = "ExplicitExact 23.976 Hz";
+        EXPECT_EQ(HWC_CONFIG_ID_24, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
     }
 
     // Test that 24 will choose 23.976 if 24 is not supported
@@ -1353,11 +1205,10 @@
                                        mConfig30Frac, mConfig60, mConfig60Frac};
         auto refreshRateConfigs =
                 std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
-        lr.desiredRefreshRate = Fps(24.f);
-        lr.name = "ExplicitExact 24 fps";
+        lr.desiredRefreshRate = 24_Hz;
+        lr.name = "ExplicitExact 24 Hz";
         EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
-                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                          .getModeId());
+                  refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
     }
 }
 
@@ -1368,15 +1219,15 @@
                                                  /*currentConfigId=*/HWC_CONFIG_ID_90);
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_90, {Fps(90.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}),
+                      {HWC_CONFIG_ID_90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}),
               0);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     RefreshRateConfigs::GlobalSignals consideredSignals;
     lr.vote = LayerVoteType::ExplicitDefault;
-    lr.desiredRefreshRate = Fps(60.0f);
+    lr.desiredRefreshRate = 60_Hz;
     lr.name = "60Hz ExplicitDefault";
     lr.focused = true;
     EXPECT_EQ(mExpected60Config,
@@ -1392,18 +1243,17 @@
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_60, {Fps(60.f), Fps(60.f)}, {Fps(60.f), Fps(90.f)}}),
+                      {HWC_CONFIG_ID_60, {60_Hz, 60_Hz}, {60_Hz, 90_Hz}}),
               0);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::ExplicitDefault;
-    lr.desiredRefreshRate = Fps(90.0f);
+    lr.desiredRefreshRate = 90_Hz;
     lr.name = "90Hz ExplicitDefault";
     lr.focused = true;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = true}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.idle = true}));
 }
 
 TEST_F(RefreshRateConfigsTest,
@@ -1413,72 +1263,61 @@
                                                  /*currentConfigId=*/HWC_CONFIG_ID_90);
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_90, {Fps(90.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}),
+                      {HWC_CONFIG_ID_90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}),
               0);
 
     RefreshRateConfigs::GlobalSignals consideredSignals;
     EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false},
-                                                     &consideredSignals));
+              refreshRateConfigs->getBestRefreshRate({}, {}, &consideredSignals));
     EXPECT_EQ(false, consideredSignals.touch);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
 
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
-    lr.desiredRefreshRate = Fps(60.0f);
+    lr.desiredRefreshRate = 60_Hz;
     lr.name = "60Hz ExplicitExactOrMultiple";
     lr.focused = false;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.focused = true;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::ExplicitDefault;
-    lr.desiredRefreshRate = Fps(60.0f);
+    lr.desiredRefreshRate = 60_Hz;
     lr.name = "60Hz ExplicitDefault";
     lr.focused = false;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.focused = true;
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Heuristic;
-    lr.desiredRefreshRate = Fps(60.0f);
+    lr.desiredRefreshRate = 60_Hz;
     lr.name = "60Hz Heuristic";
     lr.focused = false;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.focused = true;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Max;
-    lr.desiredRefreshRate = Fps(60.0f);
+    lr.desiredRefreshRate = 60_Hz;
     lr.name = "60Hz Max";
     lr.focused = false;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.focused = true;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.vote = LayerVoteType::Min;
-    lr.desiredRefreshRate = Fps(60.0f);
+    lr.desiredRefreshRate = 60_Hz;
     lr.name = "60Hz Min";
     lr.focused = false;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
     lr.focused = true;
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, groupSwitchingNotAllowed) {
@@ -1488,17 +1327,15 @@
 
     // The default policy doesn't allow group switching. Verify that no
     // group switches are performed.
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& layer = layers[0];
     layer.vote = LayerVoteType::ExplicitDefault;
-    layer.desiredRefreshRate = Fps(90.0f);
+    layer.desiredRefreshRate = 90_Hz;
     layer.seamlessness = Seamlessness::SeamedAndSeamless;
     layer.name = "90Hz ExplicitDefault";
     layer.focused = true;
 
-    ASSERT_EQ(HWC_CONFIG_ID_60,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) {
@@ -1510,16 +1347,14 @@
     policy.allowGroupSwitching = true;
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& layer = layers[0];
     layer.vote = LayerVoteType::ExplicitDefault;
-    layer.desiredRefreshRate = Fps(90.0f);
+    layer.desiredRefreshRate = 90_Hz;
     layer.seamlessness = Seamlessness::SeamedAndSeamless;
     layer.name = "90Hz ExplicitDefault";
     layer.focused = true;
-    ASSERT_EQ(HWC_CONFIG_ID_90,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) {
@@ -1532,16 +1367,14 @@
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
 
     // Verify that we won't change the group if seamless switch is required.
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& layer = layers[0];
     layer.vote = LayerVoteType::ExplicitDefault;
-    layer.desiredRefreshRate = Fps(90.0f);
+    layer.desiredRefreshRate = 90_Hz;
     layer.seamlessness = Seamlessness::OnlySeamless;
     layer.name = "90Hz ExplicitDefault";
     layer.focused = true;
-    ASSERT_EQ(HWC_CONFIG_ID_60,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) {
@@ -1556,16 +1389,14 @@
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
 
     // Verify that we won't do a seamless switch if we request the same mode as the default
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& layer = layers[0];
     layer.vote = LayerVoteType::ExplicitDefault;
-    layer.desiredRefreshRate = Fps(60.0f);
+    layer.desiredRefreshRate = 60_Hz;
     layer.seamlessness = Seamlessness::OnlySeamless;
     layer.name = "60Hz ExplicitDefault";
     layer.focused = true;
-    ASSERT_EQ(HWC_CONFIG_ID_90,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) {
@@ -1582,17 +1413,15 @@
     // Verify that if the current config is in another group and there are no layers with
     // seamlessness=SeamedAndSeamless we'll go back to the default group.
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& layer = layers[0];
     layer.vote = LayerVoteType::ExplicitDefault;
-    layer.desiredRefreshRate = Fps(60.0f);
+    layer.desiredRefreshRate = 60_Hz;
     layer.seamlessness = Seamlessness::Default;
     layer.name = "60Hz ExplicitDefault";
     layer.focused = true;
 
-    ASSERT_EQ(HWC_CONFIG_ID_60,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) {
@@ -1608,9 +1437,9 @@
 
     // If there's a layer with seamlessness=SeamedAndSeamless, another layer with
     // seamlessness=OnlySeamless can't change the mode group.
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     layers[0].vote = LayerVoteType::ExplicitDefault;
-    layers[0].desiredRefreshRate = Fps(60.0f);
+    layers[0].desiredRefreshRate = 60_Hz;
     layers[0].seamlessness = Seamlessness::OnlySeamless;
     layers[0].name = "60Hz ExplicitDefault";
     layers[0].focused = true;
@@ -1618,13 +1447,11 @@
     layers.push_back(LayerRequirement{.weight = 0.5f});
     layers[1].vote = LayerVoteType::ExplicitDefault;
     layers[1].seamlessness = Seamlessness::SeamedAndSeamless;
-    layers[1].desiredRefreshRate = Fps(90.0f);
+    layers[1].desiredRefreshRate = 90_Hz;
     layers[1].name = "90Hz ExplicitDefault";
     layers[1].focused = false;
 
-    ASSERT_EQ(HWC_CONFIG_ID_90,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) {
@@ -1644,23 +1471,21 @@
     // For example, this may happen when a video playback requests and gets a seamed switch,
     // but another layer (with default seamlessness) starts animating. The animating layer
     // should not cause a seamed switch.
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     layers[0].seamlessness = Seamlessness::Default;
-    layers[0].desiredRefreshRate = Fps(60.0f);
+    layers[0].desiredRefreshRate = 60_Hz;
     layers[0].focused = true;
     layers[0].vote = LayerVoteType::ExplicitDefault;
     layers[0].name = "60Hz ExplicitDefault";
 
     layers.push_back(LayerRequirement{.weight = 0.1f});
     layers[1].seamlessness = Seamlessness::SeamedAndSeamless;
-    layers[1].desiredRefreshRate = Fps(90.0f);
+    layers[1].desiredRefreshRate = 90_Hz;
     layers[1].focused = true;
     layers[1].vote = LayerVoteType::ExplicitDefault;
     layers[1].name = "90Hz ExplicitDefault";
 
-    ASSERT_EQ(HWC_CONFIG_ID_90,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) {
@@ -1677,23 +1502,21 @@
     // Layer with seamlessness=Default can change the mode group if there's a not
     // focused layer with seamlessness=SeamedAndSeamless. This happens for example,
     // when in split screen mode the user switches between the two visible applications.
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     layers[0].seamlessness = Seamlessness::Default;
-    layers[0].desiredRefreshRate = Fps(60.0f);
+    layers[0].desiredRefreshRate = 60_Hz;
     layers[0].focused = true;
     layers[0].vote = LayerVoteType::ExplicitDefault;
     layers[0].name = "60Hz ExplicitDefault";
 
     layers.push_back(LayerRequirement{.weight = 0.7f});
     layers[1].seamlessness = Seamlessness::SeamedAndSeamless;
-    layers[1].desiredRefreshRate = Fps(90.0f);
+    layers[1].desiredRefreshRate = 90_Hz;
     layers[1].focused = false;
     layers[1].vote = LayerVoteType::ExplicitDefault;
     layers[1].name = "90Hz ExplicitDefault";
 
-    ASSERT_EQ(HWC_CONFIG_ID_60,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) {
@@ -1707,22 +1530,18 @@
     policy.allowGroupSwitching = true;
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& layer = layers[0];
     layer.vote = LayerVoteType::ExplicitExactOrMultiple;
-    layer.desiredRefreshRate = Fps(60.0f);
+    layer.desiredRefreshRate = 60_Hz;
     layer.seamlessness = Seamlessness::SeamedAndSeamless;
     layer.name = "60Hz ExplicitExactOrMultiple";
     layer.focused = true;
 
-    ASSERT_EQ(HWC_CONFIG_ID_60,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_120);
-    ASSERT_EQ(HWC_CONFIG_ID_120,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_120, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) {
@@ -1736,31 +1555,27 @@
     policy.allowGroupSwitching = true;
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
 
-    auto layers = std::vector<
-            LayerRequirement>{LayerRequirement{.name = "60Hz ExplicitDefault",
-                                               .vote = LayerVoteType::ExplicitDefault,
-                                               .desiredRefreshRate = Fps(60.0f),
-                                               .seamlessness = Seamlessness::SeamedAndSeamless,
-                                               .weight = 0.5f,
-                                               .focused = false},
-                              LayerRequirement{.name = "25Hz ExplicitExactOrMultiple",
-                                               .vote = LayerVoteType::ExplicitExactOrMultiple,
-                                               .desiredRefreshRate = Fps(25.0f),
-                                               .seamlessness = Seamlessness::OnlySeamless,
-                                               .weight = 1.0f,
-                                               .focused = true}};
+    std::vector<LayerRequirement> layers = {{.name = "60Hz ExplicitDefault",
+                                             .vote = LayerVoteType::ExplicitDefault,
+                                             .desiredRefreshRate = 60_Hz,
+                                             .seamlessness = Seamlessness::SeamedAndSeamless,
+                                             .weight = 0.5f,
+                                             .focused = false},
+                                            {.name = "25Hz ExplicitExactOrMultiple",
+                                             .vote = LayerVoteType::ExplicitExactOrMultiple,
+                                             .desiredRefreshRate = 25_Hz,
+                                             .seamlessness = Seamlessness::OnlySeamless,
+                                             .weight = 1.f,
+                                             .focused = true}};
 
-    ASSERT_EQ(HWC_CONFIG_ID_50,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_50, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 
     auto& seamedLayer = layers[0];
-    seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = Fps(30.0f);
+    seamedLayer.desiredRefreshRate = 30_Hz;
+    seamedLayer.name = "30Hz ExplicitDefault";
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_30);
 
-    ASSERT_EQ(HWC_CONFIG_ID_25,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_25, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, minLayersDontTrigerSeamedSwitch) {
@@ -1774,14 +1589,10 @@
     policy.allowGroupSwitching = true;
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.name = "Min",
-                                                                 .vote = LayerVoteType::Min,
-                                                                 .weight = 1.f,
-                                                                 .focused = true}};
+    std::vector<LayerRequirement> layers = {
+            {.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}};
 
-    ASSERT_EQ(HWC_CONFIG_ID_90,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getModeId());
+    ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
@@ -1789,59 +1600,58 @@
             std::make_unique<RefreshRateConfigs>(m30_60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     layers[0].name = "Test layer";
 
+    struct Args {
+        bool touch = false;
+        bool focused = true;
+    };
+
     // Return the config ID from calling getBestRefreshRate() for a single layer with the
     // given voteType and fps.
-    auto getFrameRate = [&](LayerVoteType voteType, Fps fps, bool touchActive = false,
-                            bool focused = true) -> DisplayModeId {
+    auto getFrameRate = [&](LayerVoteType voteType, Fps fps, Args args = {}) -> DisplayModeId {
         layers[0].vote = voteType;
         layers[0].desiredRefreshRate = fps;
-        layers[0].focused = focused;
-        return refreshRateConfigs->getBestRefreshRate(layers, {.touch = touchActive, .idle = false})
-                .getModeId();
+        layers[0].focused = args.focused;
+        return refreshRateConfigs->getBestRefreshRate(layers, {.touch = args.touch}).getModeId();
     };
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_60, {Fps(30.f), Fps(60.f)}, {Fps(30.f), Fps(90.f)}}),
+                      {HWC_CONFIG_ID_60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}}),
               0);
-    EXPECT_EQ(HWC_CONFIG_ID_60,
-              refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false})
-                      .getModeId());
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f)));
+    EXPECT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate({}, {}).getModeId());
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz));
 
-    // Layers not focused are not allowed to override primary config
+    // Unfocused layers are not allowed to override primary config.
     EXPECT_EQ(HWC_CONFIG_ID_60,
-              getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f), /*touch=*/false,
-                           /*focused=*/false));
+              getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.focused = false}));
     EXPECT_EQ(HWC_CONFIG_ID_60,
-              getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f), /*touch=*/false,
-                           /*focused=*/false));
+              getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.focused = false}));
 
     // Touch boost should be restricted to the primary range.
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f), /*touch=*/true));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90_Hz, {.touch = true}));
     // When we're higher than the primary range max due to a layer frame rate setting, touch boost
     // shouldn't drag us back down to the primary range max.
     EXPECT_EQ(HWC_CONFIG_ID_90,
-              getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f), /*touch=*/true));
+              getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.touch = true}));
     EXPECT_EQ(HWC_CONFIG_ID_60,
-              getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f), /*touch=*/true));
+              getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.touch = true}));
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_60, {Fps(60.f), Fps(60.f)}, {Fps(60.f), Fps(60.f)}}),
+                      {HWC_CONFIG_ID_60, {60_Hz, 60_Hz}, {60_Hz, 60_Hz}}),
               0);
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f)));
-    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f)));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz));
 }
 
 TEST_F(RefreshRateConfigsTest, idle) {
@@ -1849,12 +1659,12 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     layers[0].name = "Test layer";
 
     const auto getIdleFrameRate = [&](LayerVoteType voteType, bool touchActive) -> DisplayModeId {
         layers[0].vote = voteType;
-        layers[0].desiredRefreshRate = Fps(90.f);
+        layers[0].desiredRefreshRate = 90_Hz;
         RefreshRateConfigs::GlobalSignals consideredSignals;
         const auto configId =
                 refreshRateConfigs
@@ -1867,7 +1677,7 @@
     };
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_60, {Fps(60.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}),
+                      {HWC_CONFIG_ID_60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}),
               0);
 
     // Idle should be lower priority than touch boost.
@@ -1898,8 +1708,7 @@
 
     // Idle should be applied rather than the current config when there are no layers.
     EXPECT_EQ(HWC_CONFIG_ID_60,
-              refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = true})
-                      .getModeId());
+              refreshRateConfigs->getBestRefreshRate({}, {.idle = true}).getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) {
@@ -1908,23 +1717,23 @@
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
     for (float fps = 1.0f; fps <= 120.0f; fps += 0.1f) {
-        const auto knownFrameRate = findClosestKnownFrameRate(*refreshRateConfigs, Fps(fps));
+        const auto knownFrameRate =
+                findClosestKnownFrameRate(*refreshRateConfigs, Fps::fromValue(fps));
         Fps expectedFrameRate;
         if (fps < 26.91f) {
-            expectedFrameRate = Fps(24.0f);
+            expectedFrameRate = 24_Hz;
         } else if (fps < 37.51f) {
-            expectedFrameRate = Fps(30.0f);
+            expectedFrameRate = 30_Hz;
         } else if (fps < 52.51f) {
-            expectedFrameRate = Fps(45.0f);
+            expectedFrameRate = 45_Hz;
         } else if (fps < 66.01f) {
-            expectedFrameRate = Fps(60.0f);
+            expectedFrameRate = 60_Hz;
         } else if (fps < 81.01f) {
-            expectedFrameRate = Fps(72.0f);
+            expectedFrameRate = 72_Hz;
         } else {
-            expectedFrameRate = Fps(90.0f);
+            expectedFrameRate = 90_Hz;
         }
-        EXPECT_TRUE(expectedFrameRate.equalsWithMargin(knownFrameRate))
-                << "findClosestKnownFrameRate(" << fps << ") = " << knownFrameRate;
+        EXPECT_EQ(expectedFrameRate, knownFrameRate);
     }
 }
 
@@ -1933,38 +1742,32 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    struct ExpectedRate {
-        Fps rate;
-        const RefreshRate& expected;
+    struct Expectation {
+        Fps fps;
+        const RefreshRate& refreshRate;
     };
 
-    /* clang-format off */
-    std::vector<ExpectedRate> knownFrameRatesExpectations = {
-        {Fps(24.0f), mExpected60Config},
-        {Fps(30.0f), mExpected60Config},
-        {Fps(45.0f), mExpected90Config},
-        {Fps(60.0f), mExpected60Config},
-        {Fps(72.0f), mExpected90Config},
-        {Fps(90.0f), mExpected90Config},
+    const std::initializer_list<Expectation> knownFrameRatesExpectations = {
+            {24_Hz, mExpected60Config}, {30_Hz, mExpected60Config}, {45_Hz, mExpected90Config},
+            {60_Hz, mExpected60Config}, {72_Hz, mExpected90Config}, {90_Hz, mExpected90Config},
     };
-    /* clang-format on */
 
     // Make sure the test tests all the known frame rate
     const auto knownFrameRateList = getKnownFrameRate(*refreshRateConfigs);
-    const auto equal =
-            std::equal(knownFrameRateList.begin(), knownFrameRateList.end(),
-                       knownFrameRatesExpectations.begin(),
-                       [](Fps a, const ExpectedRate& b) { return a.equalsWithMargin(b.rate); });
+    const bool equal = std::equal(knownFrameRateList.begin(), knownFrameRateList.end(),
+                                  knownFrameRatesExpectations.begin(),
+                                  [](Fps fps, const Expectation& expected) {
+                                      return isApproxEqual(fps, expected.fps);
+                                  });
     EXPECT_TRUE(equal);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& layer = layers[0];
     layer.vote = LayerVoteType::Heuristic;
-    for (const auto& expectedRate : knownFrameRatesExpectations) {
-        layer.desiredRefreshRate = expectedRate.rate;
-        const auto& refreshRate =
-                refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
-        EXPECT_EQ(expectedRate.expected, refreshRate);
+
+    for (const auto& [fps, refreshRate] : knownFrameRatesExpectations) {
+        layer.desiredRefreshRate = fps;
+        EXPECT_EQ(refreshRate, refreshRateConfigs->getBestRefreshRate(layers, {}));
     }
 }
 
@@ -1973,40 +1776,33 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 0.5f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
     auto& explicitExactLayer = layers[0];
     auto& explicitExactOrMultipleLayer = layers[1];
 
     explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
     explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
-    explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+    explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz;
 
     explicitExactLayer.vote = LayerVoteType::ExplicitExact;
     explicitExactLayer.name = "ExplicitExact";
-    explicitExactLayer.desiredRefreshRate = Fps(30);
+    explicitExactLayer.desiredRefreshRate = 30_Hz;
 
-    EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
-    EXPECT_EQ(mExpected30Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+    EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 
-    explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120);
-    explicitExactLayer.desiredRefreshRate = Fps(60);
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz;
+    explicitExactLayer.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    explicitExactLayer.desiredRefreshRate = Fps(72);
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    explicitExactLayer.desiredRefreshRate = 72_Hz;
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    explicitExactLayer.desiredRefreshRate = Fps(90);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    explicitExactLayer.desiredRefreshRate = 90_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    explicitExactLayer.desiredRefreshRate = Fps(120);
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    explicitExactLayer.desiredRefreshRate = 120_Hz;
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) {
@@ -2015,40 +1811,33 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60, config);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 0.5f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
     auto& explicitExactLayer = layers[0];
     auto& explicitExactOrMultipleLayer = layers[1];
 
     explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
     explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
-    explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+    explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz;
 
     explicitExactLayer.vote = LayerVoteType::ExplicitExact;
     explicitExactLayer.name = "ExplicitExact";
-    explicitExactLayer.desiredRefreshRate = Fps(30);
+    explicitExactLayer.desiredRefreshRate = 30_Hz;
 
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 
-    explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120);
-    explicitExactLayer.desiredRefreshRate = Fps(60);
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz;
+    explicitExactLayer.desiredRefreshRate = 60_Hz;
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    explicitExactLayer.desiredRefreshRate = Fps(72);
-    EXPECT_EQ(mExpected72Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    explicitExactLayer.desiredRefreshRate = 72_Hz;
+    EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    explicitExactLayer.desiredRefreshRate = Fps(90);
-    EXPECT_EQ(mExpected90Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    explicitExactLayer.desiredRefreshRate = 90_Hz;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 
-    explicitExactLayer.desiredRefreshRate = Fps(120);
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    explicitExactLayer.desiredRefreshRate = 120_Hz;
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCached) {
@@ -2059,26 +1848,20 @@
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
     setLastBestRefreshRateInvocation(*refreshRateConfigs,
-                                     GetBestRefreshRateInvocation{.layerRequirements = std::vector<
-                                                                          LayerRequirement>(),
-                                                                  .globalSignals = {.touch = true,
+                                     GetBestRefreshRateInvocation{.globalSignals = {.touch = true,
                                                                                     .idle = true},
                                                                   .outSignalsConsidered =
-                                                                          {.touch = true,
-                                                                           .idle = false},
+                                                                          {.touch = true},
                                                                   .resultingBestRefreshRate =
                                                                           createRefreshRate(
                                                                                   mConfig90)});
 
     EXPECT_EQ(createRefreshRate(mConfig90),
-              refreshRateConfigs->getBestRefreshRate(std::vector<LayerRequirement>(),
-                                                     {.touch = true, .idle = true}));
+              refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = true}));
 
-    const GlobalSignals cachedSignalsConsidered{.touch = true, .idle = false};
+    const GlobalSignals cachedSignalsConsidered{.touch = true};
     setLastBestRefreshRateInvocation(*refreshRateConfigs,
-                                     GetBestRefreshRateInvocation{.layerRequirements = std::vector<
-                                                                          LayerRequirement>(),
-                                                                  .globalSignals = {.touch = true,
+                                     GetBestRefreshRateInvocation{.globalSignals = {.touch = true,
                                                                                     .idle = true},
                                                                   .outSignalsConsidered =
                                                                           cachedSignalsConsidered,
@@ -2088,8 +1871,7 @@
 
     GlobalSignals signalsConsidered;
     EXPECT_EQ(createRefreshRate(mConfig30),
-              refreshRateConfigs->getBestRefreshRate(std::vector<LayerRequirement>(),
-                                                     {.touch = true, .idle = true},
+              refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = true},
                                                      &signalsConsidered));
 
     EXPECT_EQ(cachedSignalsConsidered, signalsConsidered);
@@ -2104,8 +1886,7 @@
     ASSERT_FALSE(getLastBestRefreshRateInvocation(*refreshRateConfigs).has_value());
 
     GlobalSignals globalSignals{.touch = true, .idle = true};
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 0.5f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
     const auto lastResult =
             refreshRateConfigs->getBestRefreshRate(layers, globalSignals,
                                                    /* outSignalsConsidered */ nullptr);
@@ -2129,30 +1910,25 @@
             std::make_unique<RefreshRateConfigs>(m60_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60, config);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
-                                                LayerRequirement{.weight = 0.5f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 0.5f}};
     auto& explicitExactLayer = layers[0];
     auto& explicitExactOrMultipleLayer = layers[1];
 
     explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
     explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
-    explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+    explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz;
 
     explicitExactLayer.vote = LayerVoteType::ExplicitExact;
     explicitExactLayer.name = "ExplicitExact";
-    explicitExactLayer.desiredRefreshRate = Fps(30);
+    explicitExactLayer.desiredRefreshRate = 30_Hz;
 
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
-    EXPECT_EQ(mExpected120Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+    EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 
     explicitExactOrMultipleLayer.vote = LayerVoteType::NoVote;
 
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}));
 }
 
 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) {
@@ -2161,21 +1937,19 @@
             std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60, config);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 0.5f},
-                                                LayerRequirement{.weight = 0.5f}};
+    std::vector<LayerRequirement> layers = {{.weight = 0.5f}, {.weight = 0.5f}};
     auto& explicitDefaultLayer = layers[0];
     auto& explicitExactOrMultipleLayer = layers[1];
 
     explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
     explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
-    explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+    explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz;
 
     explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault;
     explicitDefaultLayer.name = "ExplicitDefault";
-    explicitDefaultLayer.desiredRefreshRate = Fps(59.94f);
+    explicitDefaultLayer.desiredRefreshRate = 59.94_Hz;
 
-    EXPECT_EQ(mExpected60Config,
-              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {}));
 }
 
 // b/190578904
@@ -2186,29 +1960,26 @@
     DisplayModes displayModes;
     for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
         constexpr int32_t kGroup = 0;
-        const auto refreshRate = Fps(static_cast<float>(fps));
+        const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
         displayModes.push_back(
                 createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs()));
     }
 
-    const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(displayModes,
                                                  /*currentConfigId=*/displayModes[0]->getId());
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
         layers[0].desiredRefreshRate = fps;
         layers[0].vote = vote;
         EXPECT_EQ(fps.getIntValue(),
-                  refreshRateConfigs->getBestRefreshRate(layers, globalSignals)
-                          .getFps()
-                          .getIntValue())
+                  refreshRateConfigs->getBestRefreshRate(layers, {}).getFps().getIntValue())
                 << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote);
     };
 
     for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
-        const auto refreshRate = Fps(static_cast<float>(fps));
+        const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
         testRefreshRate(refreshRate, LayerVoteType::Heuristic);
         testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault);
         testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple);
@@ -2232,18 +2003,15 @@
     EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
 
     // SetPolicy(60, 90), current 60Hz => TurnOn.
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(90)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 90_Hz}}), 0);
     EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
 
     // SetPolicy(60, 60), current 60Hz => TurnOff
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0);
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
 
     // SetPolicy(90, 90), current 90Hz => TurnOff.
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90_Hz, 90_Hz}}), 0);
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
 }
 
@@ -2255,23 +2023,19 @@
             std::make_unique<RefreshRateConfigs>(m60_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_120);
     // SetPolicy(0, 60), current 60Hz => TurnOn.
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(0), Fps(60)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0_Hz, 60_Hz}}), 0);
     EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
 
     // SetPolicy(60, 60), current 60Hz => TurnOff.
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0);
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
 
     // SetPolicy(60, 120), current 60Hz => TurnOn.
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(120)}}),
-              0);
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 120_Hz}}), 0);
     EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
 
     // SetPolicy(120, 120), current 120Hz => TurnOff.
-    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
-                      {HWC_CONFIG_ID_120, {Fps(120), Fps(120)}}),
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_120, {120_Hz, 120_Hz}}),
               0);
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
 }
@@ -2281,7 +2045,7 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_30);
 
-    const auto frameRate = Fps(30.f);
+    const auto frameRate = 30_Hz;
     Fps displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
     EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
 
@@ -2303,39 +2067,38 @@
 
     refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
     displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps();
-    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, Fps(22.5f)));
+    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, 22.5_Hz));
 
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(25.f)));
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(23.976f)));
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(30.f), Fps(29.97f)));
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(60.f), Fps(59.94f)));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 25_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 23.976_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(30_Hz, 29.97_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(60_Hz, 59.94_Hz));
 }
 
 TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) {
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.976f), Fps(24.f)));
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(23.976f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(23.976_Hz, 24_Hz));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(24_Hz, 23.976_Hz));
 
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(30.f)));
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(29.97f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 30_Hz));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(30_Hz, 29.97_Hz));
 
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(60.f)));
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(59.94f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(59.94_Hz, 60_Hz));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(60_Hz, 59.94_Hz));
 
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(60.f)));
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(29.97f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 60_Hz));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(60_Hz, 29.97_Hz));
 
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(30.f)));
-    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(59.94f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(59.94_Hz, 30_Hz));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(30_Hz, 59.94_Hz));
 
-    const std::vector<float> refreshRates = {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f};
+    const auto refreshRates = {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz};
     for (auto refreshRate : refreshRates) {
-        EXPECT_FALSE(
-                RefreshRateConfigs::isFractionalPairOrMultiple(Fps(refreshRate), Fps(refreshRate)));
+        EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(refreshRate, refreshRate));
     }
 
-    EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(25.f)));
-    EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.978f), Fps(25.f)));
-    EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(59.94f)));
+    EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(24_Hz, 25_Hz));
+    EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(23.978_Hz, 25_Hz));
+    EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 59.94_Hz));
 }
 
 TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) {
@@ -2343,9 +2106,7 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
                                                  HWC_CONFIG_ID_120);
 
-    auto layers = std::vector<LayerRequirement>{};
-    ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false)
-                        .empty());
+    ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides({}, 120_Hz, {}).empty());
 }
 
 TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_60on120) {
@@ -2354,42 +2115,36 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
                                                  HWC_CONFIG_ID_120, config);
 
-    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     layers[0].name = "Test layer";
     layers[0].ownerUid = 1234;
-    layers[0].desiredRefreshRate = Fps(60.0f);
+    layers[0].desiredRefreshRate = 60_Hz;
     layers[0].vote = LayerVoteType::ExplicitDefault;
-    auto frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_EQ(1, frameRateOverrides.size());
     ASSERT_EQ(1, frameRateOverrides.count(1234));
-    ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+    ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
 
     layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_EQ(1, frameRateOverrides.size());
     ASSERT_EQ(1, frameRateOverrides.count(1234));
-    ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+    ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
 
     layers[0].vote = LayerVoteType::NoVote;
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_TRUE(frameRateOverrides.empty());
 
     layers[0].vote = LayerVoteType::Min;
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_TRUE(frameRateOverrides.empty());
 
     layers[0].vote = LayerVoteType::Max;
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_TRUE(frameRateOverrides.empty());
 
     layers[0].vote = LayerVoteType::Heuristic;
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_TRUE(frameRateOverrides.empty());
 }
 
@@ -2399,37 +2154,32 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
                                                  HWC_CONFIG_ID_120, config);
 
-    auto layers = std::vector<LayerRequirement>{
-            LayerRequirement{.ownerUid = 1234, .weight = 1.0f},
-            LayerRequirement{.ownerUid = 5678, .weight = 1.0f},
-    };
+    std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f},
+                                            {.ownerUid = 5678, .weight = 1.f}};
 
     layers[0].name = "Test layer 1234";
-    layers[0].desiredRefreshRate = Fps(60.0f);
+    layers[0].desiredRefreshRate = 60_Hz;
     layers[0].vote = LayerVoteType::ExplicitDefault;
 
     layers[1].name = "Test layer 5678";
-    layers[1].desiredRefreshRate = Fps(30.0f);
+    layers[1].desiredRefreshRate = 30_Hz;
     layers[1].vote = LayerVoteType::ExplicitDefault;
-    auto frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
 
     ASSERT_EQ(2, frameRateOverrides.size());
     ASSERT_EQ(1, frameRateOverrides.count(1234));
-    ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+    ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
     ASSERT_EQ(1, frameRateOverrides.count(5678));
-    ASSERT_EQ(30.0f, frameRateOverrides.at(5678).getValue());
+    ASSERT_EQ(30_Hz, frameRateOverrides.at(5678));
 
     layers[1].vote = LayerVoteType::Heuristic;
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_EQ(1, frameRateOverrides.size());
     ASSERT_EQ(1, frameRateOverrides.count(1234));
-    ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+    ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
 
     layers[1].ownerUid = 1234;
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_TRUE(frameRateOverrides.empty());
 }
 
@@ -2439,54 +2189,44 @@
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
                                                  HWC_CONFIG_ID_120, config);
 
-    auto layers = std::vector<LayerRequirement>{
-            LayerRequirement{.ownerUid = 1234, .weight = 1.0f},
-    };
-
+    std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f}};
     layers[0].name = "Test layer";
-    layers[0].desiredRefreshRate = Fps(60.0f);
+    layers[0].desiredRefreshRate = 60_Hz;
     layers[0].vote = LayerVoteType::ExplicitDefault;
 
-    auto frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_EQ(1, frameRateOverrides.size());
     ASSERT_EQ(1, frameRateOverrides.count(1234));
-    ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+    ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
 
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {.touch = true});
     ASSERT_EQ(1, frameRateOverrides.size());
     ASSERT_EQ(1, frameRateOverrides.count(1234));
-    ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+    ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
 
     layers[0].vote = LayerVoteType::ExplicitExact;
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_EQ(1, frameRateOverrides.size());
     ASSERT_EQ(1, frameRateOverrides.count(1234));
-    ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+    ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
 
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {.touch = true});
     ASSERT_EQ(1, frameRateOverrides.size());
     ASSERT_EQ(1, frameRateOverrides.count(1234));
-    ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+    ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
 
     layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {});
     ASSERT_EQ(1, frameRateOverrides.size());
     ASSERT_EQ(1, frameRateOverrides.count(1234));
-    ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+    ASSERT_EQ(60_Hz, frameRateOverrides.at(1234));
 
-    frameRateOverrides =
-            refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true);
+    frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {.touch = true});
     ASSERT_TRUE(frameRateOverrides.empty());
 }
 
 } // namespace
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 0a8759d..df4a9c4 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wextra"
-
 #undef LOG_TAG
 #define LOG_TAG "SchedulerUnittests"
 
@@ -35,8 +31,7 @@
 using testing::_;
 using testing::AtLeast;
 
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
 
 class RefreshRateStatsTest : public testing::Test {
 protected:
@@ -88,54 +83,53 @@
 }
 
 namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
 TEST_F(RefreshRateStatsTest, oneConfigTest) {
     init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)});
 
     EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
     EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
 
-    std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
-    ASSERT_EQ(1, times.size());
-    EXPECT_NE(0u, times.count("ScreenOff"));
-    // Setting up tests on mobile harness can be flaky with time passing, so testing for
-    // exact time changes can result in flaxy numbers. To avoid that remember old
-    // numbers to make sure the correct values are increasing in the next test.
-    auto screenOff = times["ScreenOff"];
+    auto times = mRefreshRateStats->getTotalTimes();
+    ASSERT_TRUE(times.contains("ScreenOff"));
+    EXPECT_EQ(1u, times.size());
 
     // Screen is off by default.
+    std::chrono::milliseconds screenOff = times.get("ScreenOff")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_LT(screenOff, times["ScreenOff"]);
-    EXPECT_EQ(0u, times.count("90.00fps"));
+
+    EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+    EXPECT_FALSE(times.contains("90.00 Hz"));
 
     const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
     mRefreshRateStats->setRefreshRate(config0Fps);
     mRefreshRateStats->setPowerMode(PowerMode::ON);
-    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+    screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_EQ(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(1u, times.count("90.00fps"));
-    EXPECT_LT(0, times["90.00fps"]);
+
+    EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+    ASSERT_TRUE(times.contains("90.00 Hz"));
+    EXPECT_LT(0ms, times.get("90.00 Hz")->get());
 
     mRefreshRateStats->setPowerMode(PowerMode::DOZE);
-    auto ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
+    const auto ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_LT(screenOff, times["ScreenOff"]);
-    EXPECT_EQ(ninety, times["90.00fps"]);
+
+    EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+    EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
 
     mRefreshRateStats->setRefreshRate(config0Fps);
-    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+    screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
+
     // Because the power mode is not PowerMode::ON, switching the config
     // does not update refresh rates that come from the config.
-    EXPECT_LT(screenOff, times["ScreenOff"]);
-    EXPECT_EQ(ninety, times["90.00fps"]);
+    EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+    EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
 }
 
 TEST_F(RefreshRateStatsTest, twoConfigsTest) {
@@ -146,78 +140,81 @@
     EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
     EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
 
-    std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
-    ASSERT_EQ(1, times.size());
-    EXPECT_NE(0u, times.count("ScreenOff"));
-    // Setting up tests on mobile harness can be flaky with time passing, so testing for
-    // exact time changes can result in flaxy numbers. To avoid that remember old
-    // numbers to make sure the correct values are increasing in the next test.
-    auto screenOff = times["ScreenOff"];
+    auto times = mRefreshRateStats->getTotalTimes();
+    ASSERT_TRUE(times.contains("ScreenOff"));
+    EXPECT_EQ(1u, times.size());
 
     // Screen is off by default.
+    std::chrono::milliseconds screenOff = times.get("ScreenOff")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_LT(screenOff, times["ScreenOff"]);
+
+    EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+    EXPECT_FALSE(times.contains("60.00 Hz"));
+    EXPECT_FALSE(times.contains("90.00 Hz"));
 
     const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
     const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_1).getFps();
     mRefreshRateStats->setRefreshRate(config0Fps);
     mRefreshRateStats->setPowerMode(PowerMode::ON);
-    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+    screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_EQ(screenOff, times["ScreenOff"]);
-    ASSERT_EQ(1u, times.count("90.00fps"));
-    EXPECT_LT(0, times["90.00fps"]);
+
+    EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+    ASSERT_TRUE(times.contains("90.00 Hz"));
+    EXPECT_LT(0ms, times.get("90.00 Hz")->get());
 
     // When power mode is normal, time for configs updates.
     mRefreshRateStats->setRefreshRate(config1Fps);
-    auto ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
+    auto ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_EQ(screenOff, times["ScreenOff"]);
-    EXPECT_EQ(ninety, times["90.00fps"]);
-    ASSERT_EQ(1u, times.count("60.00fps"));
-    EXPECT_LT(0, times["60.00fps"]);
+
+    EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+    EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
+    ASSERT_TRUE(times.contains("60.00 Hz"));
+    EXPECT_LT(0ms, times.get("60.00 Hz")->get());
 
     mRefreshRateStats->setRefreshRate(config0Fps);
-    auto sixty = mRefreshRateStats->getTotalTimes()["60.00fps"];
+    auto sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_EQ(screenOff, times["ScreenOff"]);
-    EXPECT_LT(ninety, times["90.00fps"]);
-    EXPECT_EQ(sixty, times["60.00fps"]);
+
+    EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+    EXPECT_LT(ninety, times.get("90.00 Hz")->get());
+    EXPECT_EQ(sixty, times.get("60.00 Hz")->get());
 
     mRefreshRateStats->setRefreshRate(config1Fps);
-    ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
+    ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_EQ(screenOff, times["ScreenOff"]);
-    EXPECT_EQ(ninety, times["90.00fps"]);
-    EXPECT_LT(sixty, times["60.00fps"]);
+
+    EXPECT_EQ(screenOff, times.get("ScreenOff")->get());
+    EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
+    EXPECT_LT(sixty, times.get("60.00 Hz")->get());
 
     // Because the power mode is not PowerMode::ON, switching the config
     // does not update refresh rates that come from the config.
     mRefreshRateStats->setPowerMode(PowerMode::DOZE);
     mRefreshRateStats->setRefreshRate(config0Fps);
-    sixty = mRefreshRateStats->getTotalTimes()["60.00fps"];
+    sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_LT(screenOff, times["ScreenOff"]);
-    EXPECT_EQ(ninety, times["90.00fps"]);
-    EXPECT_EQ(sixty, times["60.00fps"]);
+
+    EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+    EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
+    EXPECT_EQ(sixty, times.get("60.00 Hz")->get());
 
     mRefreshRateStats->setRefreshRate(config1Fps);
-    screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+    screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get();
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    EXPECT_LT(screenOff, times["ScreenOff"]);
-    EXPECT_EQ(ninety, times["90.00fps"]);
-    EXPECT_EQ(sixty, times["60.00fps"]);
-}
-} // namespace
-} // namespace scheduler
-} // namespace android
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
+    EXPECT_LT(screenOff, times.get("ScreenOff")->get());
+    EXPECT_EQ(ninety, times.get("90.00 Hz")->get());
+    EXPECT_EQ(sixty, times.get("60.00 Hz")->get());
+}
+
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index e2b3993..599b235 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -54,13 +54,13 @@
     const DisplayModePtr mode60 = DisplayMode::Builder(0)
                                           .setId(DisplayModeId(0))
                                           .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
-                                          .setVsyncPeriod(Fps(60.f).getPeriodNsecs())
+                                          .setVsyncPeriod((60_Hz).getPeriodNsecs())
                                           .setGroup(0)
                                           .build();
     const DisplayModePtr mode120 = DisplayMode::Builder(1)
                                            .setId(DisplayModeId(1))
                                            .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
-                                           .setVsyncPeriod(Fps(120.f).getPeriodNsecs())
+                                           .setVsyncPeriod((120_Hz).getPeriodNsecs())
                                            .setGroup(0)
                                            .build();
 
@@ -217,17 +217,17 @@
 }
 
 TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
-    EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 30ms));
-    EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(90), 30ms));
-    EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(Fps(120), 30ms));
+    EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 30ms));
+    EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(90_Hz, 30ms));
+    EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(120_Hz, 30ms));
 
-    EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 40ms));
+    EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 40ms));
 
-    EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 10ms));
+    EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms));
 }
 
 MATCHER(Is120Hz, "") {
-    return arg.getFps().equalsWithMargin(Fps(120.f));
+    return isApproxEqual(arg.getFps(), 120_Hz);
 }
 
 TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) {
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 6c3b2fd..3b40965 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -29,6 +29,7 @@
 #include "Layer.h"
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic pop // ignored "-Wconversion"
+#include "FpsOps.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/MockEventThread.h"
@@ -96,12 +97,11 @@
  */
 class SetFrameRateTest : public ::testing::TestWithParam<std::shared_ptr<LayerFactory>> {
 protected:
-    const FrameRate FRAME_RATE_VOTE1 = FrameRate(Fps(67.f), FrameRateCompatibility::Default);
-    const FrameRate FRAME_RATE_VOTE2 =
-            FrameRate(Fps(14.f), FrameRateCompatibility::ExactOrMultiple);
-    const FrameRate FRAME_RATE_VOTE3 = FrameRate(Fps(99.f), FrameRateCompatibility::NoVote);
-    const FrameRate FRAME_RATE_TREE = FrameRate(Fps(0.f), FrameRateCompatibility::NoVote);
-    const FrameRate FRAME_RATE_NO_VOTE = FrameRate(Fps(0.f), FrameRateCompatibility::Default);
+    const FrameRate FRAME_RATE_VOTE1 = FrameRate(67_Hz, FrameRateCompatibility::Default);
+    const FrameRate FRAME_RATE_VOTE2 = FrameRate(14_Hz, FrameRateCompatibility::ExactOrMultiple);
+    const FrameRate FRAME_RATE_VOTE3 = FrameRate(99_Hz, FrameRateCompatibility::NoVote);
+    const FrameRate FRAME_RATE_TREE = FrameRate(Fps(), FrameRateCompatibility::NoVote);
+    const FrameRate FRAME_RATE_NO_VOTE = FrameRate(Fps(), FrameRateCompatibility::Default);
 
     SetFrameRateTest();
 
@@ -172,9 +172,7 @@
 }
 
 namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
 TEST_P(SetFrameRateTest, SetAndGet) {
     EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
 
@@ -470,8 +468,8 @@
                     .mutableLayerHistory()
                     ->summarize(*mFlinger.mutableScheduler().refreshRateConfigs(), 0);
     ASSERT_EQ(2u, layerHistorySummary.size());
-    EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[0].desiredRefreshRate));
-    EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate));
+    EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[0].desiredRefreshRate);
+    EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[1].desiredRefreshRate);
 }
 
 TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index e55721d..6edebd4 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -260,6 +260,11 @@
         auto display = Display::makeFakeExistingDisplayInjector(test);
         display.inject();
         display.mutableDisplayDevice()->setPowerMode(mode);
+        if (display.mutableDisplayDevice()->isInternal()) {
+            test->mFlinger.mutableActiveDisplayToken() =
+                    display.mutableDisplayDevice()->getDisplayToken();
+        }
+
         return display;
     }
 
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b89da60..dd20d0d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -446,6 +446,7 @@
     auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
     auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; }
     auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
+    auto& mutableActiveDisplayToken() { return mFlinger->mActiveDisplayToken; }
 
     auto fromHandle(const sp<IBinder>& handle) {
         return mFlinger->fromHandle(handle);
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 317cdf1..1487a96 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -64,16 +64,14 @@
 #define LAYER_ID_0            0
 #define LAYER_ID_1            1
 #define UID_0                 123
-#define REFRESH_RATE_0        61
-#define RENDER_RATE_0         31
 #define REFRESH_RATE_BUCKET_0 60
 #define RENDER_RATE_BUCKET_0  30
 #define LAYER_ID_INVALID      -1
 #define NUM_LAYERS            1
 #define NUM_LAYERS_INVALID    "INVALID"
 
-const constexpr Fps kRefreshRate0 = Fps(static_cast<float>(REFRESH_RATE_0));
-const constexpr Fps kRenderRate0 = Fps(static_cast<float>(RENDER_RATE_0));
+const constexpr Fps kRefreshRate0 = 61_Hz;
+const constexpr Fps kRenderRate0 = 31_Hz;
 static constexpr int32_t kGameMode = TimeStatsHelper::GameModeUnsupported;
 
 enum InputCommand : int32_t {
@@ -1498,14 +1496,14 @@
         EXPECT_THAT(result, HasSubstr(expectedResult)) << "failed for " << fps;
     };
 
-    verifyRefreshRateBucket(Fps(91.f), 90);
-    verifyRefreshRateBucket(Fps(89.f), 90);
+    verifyRefreshRateBucket(91_Hz, 90);
+    verifyRefreshRateBucket(89_Hz, 90);
 
-    verifyRefreshRateBucket(Fps(61.f), 60);
-    verifyRefreshRateBucket(Fps(59.f), 60);
+    verifyRefreshRateBucket(61_Hz, 60);
+    verifyRefreshRateBucket(59_Hz, 60);
 
-    verifyRefreshRateBucket(Fps(31.f), 30);
-    verifyRefreshRateBucket(Fps(29.f), 30);
+    verifyRefreshRateBucket(31_Hz, 30);
+    verifyRefreshRateBucket(29_Hz, 30);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 2b5b7b5..bf69704 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -344,7 +344,7 @@
         // Both the droppedSurfaceFrame and presentedSurfaceFrame should be in
         // pendingJankClassifications.
         EXPECT_EQ(2u, layer->mPendingJankClassifications.size());
-        presentedSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+        presentedSurfaceFrame->onPresent(20, JankType::None, 90_Hz,
                                          /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0);
         layer->releasePendingBuffer(25);
 
@@ -462,10 +462,10 @@
         // BufferlessSurfaceFrames are immediately set to presented and added to the DisplayFrame.
         // Since we don't have access to DisplayFrame here, trigger an onPresent directly.
         for (auto& surfaceFrame : bufferlessSurfaceFrames) {
-            surfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+            surfaceFrame->onPresent(20, JankType::None, 90_Hz,
                                     /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0);
         }
-        presentedBufferSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11),
+        presentedBufferSurfaceFrame->onPresent(20, JankType::None, 90_Hz,
                                                /*displayDeadlineDelta*/ 0,
                                                /*displayPresentDelta*/ 0);
 
diff --git a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
index 41a4d30..21ee071 100644
--- a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
@@ -44,7 +44,7 @@
 class WorkDurationTest : public testing::Test {
 protected:
     WorkDurationTest()
-          : mWorkDuration(Fps(60.0f), 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
+          : mWorkDuration(60_Hz, 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
                           21'000'000, 1234) {}
 
     ~WorkDurationTest() = default;
@@ -56,9 +56,9 @@
  * Test cases
  */
 TEST_F(WorkDurationTest, getConfigsForRefreshRate_60Hz) {
-    mWorkDuration.setRefreshRateFps(Fps(60.0f));
+    mWorkDuration.setRefreshRateFps(60_Hz);
     auto currentOffsets = mWorkDuration.getCurrentConfigs();
-    auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(60.0f));
+    auto offsets = mWorkDuration.getConfigsForRefreshRate(60_Hz);
 
     EXPECT_EQ(currentOffsets, offsets);
     EXPECT_EQ(offsets.late.sfOffset, 6'166'667);
@@ -81,9 +81,9 @@
 }
 
 TEST_F(WorkDurationTest, getConfigsForRefreshRate_90Hz) {
-    mWorkDuration.setRefreshRateFps(Fps(90.0f));
+    mWorkDuration.setRefreshRateFps(90_Hz);
     auto currentOffsets = mWorkDuration.getCurrentConfigs();
-    auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(90.0f));
+    auto offsets = mWorkDuration.getConfigsForRefreshRate(90_Hz);
 
     EXPECT_EQ(currentOffsets, offsets);
     EXPECT_EQ(offsets.late.sfOffset, 611'111);
@@ -106,7 +106,7 @@
 }
 
 TEST_F(WorkDurationTest, getConfigsForRefreshRate_DefaultOffsets) {
-    TestableWorkDuration phaseOffsetsWithDefaultValues(Fps(60.0f), -1, -1, -1, -1, -1, -1, 0);
+    TestableWorkDuration phaseOffsetsWithDefaultValues(60_Hz, -1, -1, -1, -1, -1, -1, 0);
 
     auto validateOffsets = [](const auto& offsets, std::chrono::nanoseconds vsyncPeriod) {
         EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
@@ -138,12 +138,12 @@
         validateOffsets(offsets, std::chrono::nanoseconds(refreshRate.getPeriodNsecs()));
     };
 
-    testForRefreshRate(Fps(90.0f));
-    testForRefreshRate(Fps(60.0f));
+    testForRefreshRate(90_Hz);
+    testForRefreshRate(60_Hz);
 }
 
 TEST_F(WorkDurationTest, getConfigsForRefreshRate_unknownRefreshRate) {
-    auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(14.7f));
+    auto offsets = mWorkDuration.getConfigsForRefreshRate(14.7_Hz);
 
     EXPECT_EQ(offsets.late.sfOffset, 57'527'208);
     EXPECT_EQ(offsets.late.appOffset, 37'027'208);
@@ -181,13 +181,12 @@
                          std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
                          std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,
                          nsecs_t thresholdForNextVsync, nsecs_t hwcMinWorkDuration)
-          : impl::PhaseOffsets(Fps(60.0f), vsyncPhaseOffsetNs, sfVSyncPhaseOffsetNs,
-                               earlySfOffsetNs, earlyGpuSfOffsetNs, earlyAppOffsetNs,
-                               earlyGpuAppOffsetNs, highFpsVsyncPhaseOffsetNs,
-                               highFpsSfVSyncPhaseOffsetNs, highFpsEarlySfOffsetNs,
-                               highFpsEarlyGpuSfOffsetNs, highFpsEarlyAppOffsetNs,
-                               highFpsEarlyGpuAppOffsetNs, thresholdForNextVsync,
-                               hwcMinWorkDuration) {}
+          : impl::PhaseOffsets(60_Hz, vsyncPhaseOffsetNs, sfVSyncPhaseOffsetNs, earlySfOffsetNs,
+                               earlyGpuSfOffsetNs, earlyAppOffsetNs, earlyGpuAppOffsetNs,
+                               highFpsVsyncPhaseOffsetNs, highFpsSfVSyncPhaseOffsetNs,
+                               highFpsEarlySfOffsetNs, highFpsEarlyGpuSfOffsetNs,
+                               highFpsEarlyAppOffsetNs, highFpsEarlyGpuAppOffsetNs,
+                               thresholdForNextVsync, hwcMinWorkDuration) {}
 };
 
 class PhaseOffsetsTest : public testing::Test {
@@ -201,7 +200,7 @@
 };
 
 TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_unknownRefreshRate) {
-    auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(14.7f));
+    auto offsets = mPhaseOffsets.getConfigsForRefreshRate(14.7_Hz);
 
     EXPECT_EQ(offsets.late.sfOffset, 6'000'000);
     EXPECT_EQ(offsets.late.appOffset, 2'000'000);
@@ -223,7 +222,7 @@
 }
 
 TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_60Hz) {
-    auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(60.0f));
+    auto offsets = mPhaseOffsets.getConfigsForRefreshRate(60_Hz);
 
     EXPECT_EQ(offsets.late.sfOffset, 6'000'000);
     EXPECT_EQ(offsets.late.appOffset, 2'000'000);
@@ -245,7 +244,7 @@
 }
 
 TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_90Hz) {
-    auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(90.0f));
+    auto offsets = mPhaseOffsets.getConfigsForRefreshRate(90_Hz);
 
     EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
     EXPECT_EQ(offsets.late.appOffset, 2'000'000);
@@ -269,7 +268,7 @@
 TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_60Hz) {
     TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {},         2'000'000,
                                       1'000'000, {},        {}, {}, {}, 10'000'000, 1234};
-    auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(60.0f));
+    auto offsets = phaseOffsets.getConfigsForRefreshRate(60_Hz);
 
     EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
     EXPECT_EQ(offsets.late.appOffset, 1'000'000);
@@ -293,7 +292,7 @@
 TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_90Hz) {
     TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {},         2'000'000,
                                       1'000'000, {},        {}, {}, {}, 10'000'000, 1234};
-    auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(90.0f));
+    auto offsets = phaseOffsets.getConfigsForRefreshRate(90_Hz);
 
     EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
     EXPECT_EQ(offsets.late.appOffset, 2'000'000);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 159bdf1..23b849a 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -27,11 +27,21 @@
     PowerAdvisor();
     ~PowerAdvisor() override;
 
-    MOCK_METHOD0(init, void());
-    MOCK_METHOD0(onBootFinished, void());
-    MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
-    MOCK_METHOD0(isUsingExpensiveRendering, bool());
-    MOCK_METHOD0(notifyDisplayUpdateImminent, void());
+    MOCK_METHOD(void, init, (), (override));
+    MOCK_METHOD(void, onBootFinished, (), (override));
+    MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected),
+                (override));
+    MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override));
+    MOCK_METHOD(void, notifyDisplayUpdateImminent, (), (override));
+    MOCK_METHOD(bool, usePowerHintSession, (), (override));
+    MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
+    MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
+    MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
+    MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
+                (override));
+    MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
+                (override));
+    MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
 };
 
 } // namespace android::Hwc2::mock
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index a375808..63ecaec 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -402,12 +402,21 @@
         auto primitiveIdx = static_cast<size_t>(primitive);
         if (primitiveIdx >= durations.size()) {
             // Safety check, should not happen if enum_range is correct.
+            ALOGE("Supported primitive %zu is outside range [0,%zu), skipping load duration",
+                  primitiveIdx, durations.size());
             continue;
         }
         int32_t duration = 0;
-        auto status = getHal()->getPrimitiveDuration(primitive, &duration);
-        if (!status.isOk()) {
-            return HalResult<std::vector<milliseconds>>::failed(status.toString8().c_str());
+        auto result = getHal()->getPrimitiveDuration(primitive, &duration);
+        auto halResult = HalResult<int32_t>::fromStatus(result, duration);
+        if (halResult.isUnsupported()) {
+            // Should not happen, supported primitives should always support requesting duration.
+            ALOGE("Supported primitive %zu returned unsupported for getPrimitiveDuration",
+                  primitiveIdx);
+        }
+        if (halResult.isFailed()) {
+            // Fail entire request if one request has failed.
+            return HalResult<std::vector<milliseconds>>::failed(result.toString8().c_str());
         }
         durations[primitiveIdx] = milliseconds(duration);
     }
diff --git a/services/vibratorservice/VibratorManagerHalController.cpp b/services/vibratorservice/VibratorManagerHalController.cpp
index 6bf6581..0df0bfa 100644
--- a/services/vibratorservice/VibratorManagerHalController.cpp
+++ b/services/vibratorservice/VibratorManagerHalController.cpp
@@ -45,7 +45,7 @@
 template <typename T>
 HalResult<T> ManagerHalController::processHalResult(HalResult<T> result, const char* functionName) {
     if (result.isFailed()) {
-        ALOGE("%s failed: %s", functionName, result.errorMessage());
+        ALOGE("VibratorManager HAL %s failed: %s", functionName, result.errorMessage());
         std::lock_guard<std::mutex> lock(mConnectedHalMutex);
         mConnectedHal->tryReconnect();
     }
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index 6c31e2b..6b73d17 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -103,7 +103,7 @@
 
         for (int i = 0; i < MAX_RETRIES; i++) {
             T result = halFn(hal.get());
-            if (result.checkAndLogFailure(functionName)) {
+            if (result.isFailedLogged(functionName)) {
                 tryReconnect();
             } else {
                 return result;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 68d6647..d2cc9ad 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -69,9 +69,9 @@
     bool isFailed() const { return !mUnsupported && !mValue.has_value(); }
     bool isUnsupported() const { return mUnsupported; }
     const char* errorMessage() const { return mErrorMessage.c_str(); }
-    bool checkAndLogFailure(const char* functionName) const {
+    bool isFailedLogged(const char* functionNameForLogging) const {
         if (isFailed()) {
-            ALOGE("%s failed: %s", functionName, errorMessage());
+            ALOGE("Vibrator HAL %s failed: %s", functionNameForLogging, errorMessage());
             return true;
         }
         return false;
@@ -107,9 +107,9 @@
     bool isFailed() const { return !mUnsupported && mFailed; }
     bool isUnsupported() const { return mUnsupported; }
     const char* errorMessage() const { return mErrorMessage.c_str(); }
-    bool checkAndLogFailure(const char* functionName) const {
+    bool isFailedLogged(const char* functionNameForLogging) const {
         if (isFailed()) {
-            ALOGE("%s failed: %s", functionName, errorMessage());
+            ALOGE("Vibrator HAL %s failed: %s", functionNameForLogging, errorMessage());
             return true;
         }
         return false;
@@ -192,21 +192,21 @@
     const HalResult<float> qFactor;
     const HalResult<std::vector<float>> maxAmplitudes;
 
-    bool checkAndLogFailure(const char*) const {
-        return capabilities.checkAndLogFailure("getCapabilities") ||
-                supportedEffects.checkAndLogFailure("getSupportedEffects") ||
-                supportedBraking.checkAndLogFailure("getSupportedBraking") ||
-                supportedPrimitives.checkAndLogFailure("getSupportedPrimitives") ||
-                primitiveDurations.checkAndLogFailure("getPrimitiveDuration") ||
-                primitiveDelayMax.checkAndLogFailure("getPrimitiveDelayMax") ||
-                pwlePrimitiveDurationMax.checkAndLogFailure("getPwlePrimitiveDurationMax") ||
-                compositionSizeMax.checkAndLogFailure("getCompositionSizeMax") ||
-                pwleSizeMax.checkAndLogFailure("getPwleSizeMax") ||
-                minFrequency.checkAndLogFailure("getMinFrequency") ||
-                resonantFrequency.checkAndLogFailure("getResonantFrequency") ||
-                frequencyResolution.checkAndLogFailure("getFrequencyResolution") ||
-                qFactor.checkAndLogFailure("getQFactor") ||
-                maxAmplitudes.checkAndLogFailure("getMaxAmplitudes");
+    bool isFailedLogged(const char*) const {
+        return capabilities.isFailedLogged("getCapabilities") ||
+                supportedEffects.isFailedLogged("getSupportedEffects") ||
+                supportedBraking.isFailedLogged("getSupportedBraking") ||
+                supportedPrimitives.isFailedLogged("getSupportedPrimitives") ||
+                primitiveDurations.isFailedLogged("getPrimitiveDuration") ||
+                primitiveDelayMax.isFailedLogged("getPrimitiveDelayMax") ||
+                pwlePrimitiveDurationMax.isFailedLogged("getPwlePrimitiveDurationMax") ||
+                compositionSizeMax.isFailedLogged("getCompositionSizeMax") ||
+                pwleSizeMax.isFailedLogged("getPwleSizeMax") ||
+                minFrequency.isFailedLogged("getMinFrequency") ||
+                resonantFrequency.isFailedLogged("getResonantFrequency") ||
+                frequencyResolution.isFailedLogged("getFrequencyResolution") ||
+                qFactor.isFailedLogged("getQFactor") ||
+                maxAmplitudes.isFailedLogged("getMaxAmplitudes");
     }
 };
 
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3ed3eba..e89a49b 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -736,7 +736,8 @@
     // We must support R8G8B8A8
     std::vector<VkSurfaceFormatKHR> all_formats = {
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
+        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT}};
 
     if (wide_color_support) {
         all_formats.emplace_back(VkSurfaceFormatKHR{