Merge "Look up source using & instead of equality"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4dd4f79..f054596 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,6 +1,6 @@
 [Builtin Hooks]
-clang_format = true
 bpfmt = true
+clang_format = true
 
 [Builtin Hooks Options]
 # Only turn on clang-format check for the following subfolders.
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 01c4723..34ccb21 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -282,6 +282,21 @@
     chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu23/trace
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu23/trace
 
+# Setup synthetic events
+    chmod 0666 /sys/kernel/tracing/synthetic_events
+    chmod 0666 /sys/kernel/debug/tracing/synthetic_events
+
+    # rss_stat_throttled
+    write /sys/kernel/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
+    write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
+
+# Set up histogram triggers
+    # rss_stat_throttled (bucket size == 512KB)
+    chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
+    write /sys/kernel/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+    write /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+
 # Only create the tracing instance if persist.mm_events.enabled
 # Attempting to remove the tracing instance after it has been created
 # will likely fail with EBUSY as it would be in use by traced_probes.
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 39ef0b5..8d23efc 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1455,7 +1455,7 @@
 }
 
 binder::Status InstalldNativeService::freeCache(const std::optional<std::string>& uuid,
-        int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags) {
+        int64_t targetFreeBytes, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     std::lock_guard<std::recursive_mutex> lock(mLock);
@@ -1558,12 +1558,6 @@
                 break;
             }
 
-            // Only keep clearing when we haven't pushed into reserved area
-            if (cacheReservedBytes > 0 && cleared >= (cacheTotal - cacheReservedBytes)) {
-                LOG(DEBUG) << "Refusing to clear cached data in reserved space";
-                break;
-            }
-
             // Find the best tracker to work with; this might involve swapping
             // if the active tracker is no longer the most over quota
             bool nextBetter = active && !queue.empty()
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 8cfda01..3fdb01a 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -145,7 +145,7 @@
 
     binder::Status rmPackageDir(const std::string& packageDir);
     binder::Status freeCache(const std::optional<std::string>& uuid, int64_t targetFreeBytes,
-            int64_t cacheReservedBytes, int32_t flags);
+            int32_t flags);
     binder::Status linkNativeLibraryDirectory(const std::optional<std::string>& uuid,
             const std::string& packageName, const std::string& nativeLibPath32, int32_t userId);
     binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 637a9f2..9c51ff7 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -86,8 +86,7 @@
     void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String profileName);
 
     void rmPackageDir(@utf8InCpp String packageDir);
-    void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes,
-            long cacheReservedBytes, int flags);
+    void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes, int flags);
     void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
             @utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId);
     void createOatDir(@utf8InCpp String oatDir, @utf8InCpp String instructionSet);
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 863cdfe..9a1e17e 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -145,7 +145,7 @@
     EXPECT_EQ(0, exists("com.example/cache/foo/one"));
     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
 
-    service->freeCache(testUuid, kTbInBytes, 0,
+    service->freeCache(testUuid, kTbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
     EXPECT_EQ(0, exists("com.example/normal"));
@@ -153,6 +153,33 @@
     EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
 }
 
+TEST_F(CacheTest, FreeCache_NonAggressive) {
+    LOG(INFO) << "FreeCache_NonAggressive";
+
+    mkdir("com.example");
+    touch("com.example/normal", 1 * kMbInBytes, 60);
+    mkdir("com.example/cache");
+    mkdir("com.example/cache/foo");
+    touch("com.example/cache/foo/one", 65 * kMbInBytes, 60);
+    touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
+
+    EXPECT_EQ(0, exists("com.example/normal"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+    service->freeCache(testUuid, kTbInBytes, FLAG_FREE_CACHE_V2);
+
+    EXPECT_EQ(0, exists("com.example/normal"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+    service->freeCache(testUuid, kTbInBytes, FLAG_FREE_CACHE_V2);
+
+    EXPECT_EQ(0, exists("com.example/normal"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+}
+
 TEST_F(CacheTest, FreeCache_Age) {
     LOG(INFO) << "FreeCache_Age";
 
@@ -162,13 +189,13 @@
     touch("com.example/cache/foo/one", kMbInBytes, 60);
     touch("com.example/cache/foo/two", kMbInBytes, 120);
 
-    service->freeCache(testUuid, free() + kKbInBytes, 0,
+    service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
     EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
 
-    service->freeCache(testUuid, free() + kKbInBytes, 0,
+    service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
     EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
@@ -196,7 +223,7 @@
     EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1"));
     EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2"));
 
-    service->freeCache(testUuid, kTbInBytes, 0,
+    service->freeCache(testUuid, kTbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
     EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
@@ -218,7 +245,7 @@
 
     setxattr("com.example/cache/foo", "user.cache_group");
 
-    service->freeCache(testUuid, free() + kKbInBytes, 0,
+    service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
     EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
@@ -263,7 +290,7 @@
     setxattr("com.example/cache/tomb", "user.cache_tombstone");
     setxattr("com.example/cache/tomb/group", "user.cache_group");
 
-    service->freeCache(testUuid, free() + kKbInBytes, 0,
+    service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
     EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file1"));
@@ -284,7 +311,7 @@
     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
 
-    service->freeCache(testUuid, free() + kKbInBytes, 0,
+    service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
     EXPECT_EQ(-1, size("com.example/cache/group/file1"));
@@ -305,7 +332,7 @@
     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
 
-    service->freeCache(testUuid, kTbInBytes, 0,
+    service->freeCache(testUuid, kTbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
     EXPECT_EQ(-1, size("com.example/cache/group/file1"));
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 5fe4ea1..931c5e3 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -89,6 +89,12 @@
 }
 
 prebuilt_etc {
+    name: "android.hardware.fingerprint.prebuilt.xml",
+    src: "android.hardware.fingerprint.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
     name: "android.hardware.location.gps.prebuilt.xml",
     src: "android.hardware.location.gps.xml",
     defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/include/input/Input.h b/include/input/Input.h
index 263ade4..1e06257 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -844,15 +844,12 @@
 
     inline bool getHasFocus() const { return mHasFocus; }
 
-    inline bool getInTouchMode() const { return mInTouchMode; }
-
-    void initialize(int32_t id, bool hasFocus, bool inTouchMode);
+    void initialize(int32_t id, bool hasFocus);
 
     void initialize(const FocusEvent& from);
 
 protected:
     bool mHasFocus;
-    bool mInTouchMode;
 };
 
 /*
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index d655b28..edcb615 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -178,10 +178,9 @@
 
         struct Focus {
             int32_t eventId;
-            // The following 3 fields take up 4 bytes total
+            // The following 2 fields take up 4 bytes total
             bool hasFocus;
-            bool inTouchMode;
-            uint8_t empty[2];
+            uint8_t empty[3];
 
             inline size_t size() const { return sizeof(Focus); }
         } focus;
@@ -381,7 +380,7 @@
      * Returns DEAD_OBJECT if the channel's peer has been closed.
      * Other errors probably indicate that the channel is broken.
      */
-    status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode);
+    status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus);
 
     /* Publishes a capture event to the input channel.
      *
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
index 03e1f2a..a2b59a8 100644
--- a/libs/battery/MultiStateCounter.h
+++ b/libs/battery/MultiStateCounter.h
@@ -195,10 +195,18 @@
                         << ", which is lower than the previous value " << valueToString(lastValue)
                         << "\n";
                     ALOGE("%s", str.str().c_str());
+
+                    for (int i = 0; i < stateCount; i++) {
+                        states[i].timeInStateSinceUpdate = 0;
+                    }
                 }
             } else if (timestamp < lastUpdateTimestamp) {
                 ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
                       (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
+
+                for (int i = 0; i < stateCount; i++) {
+                    states[i].timeInStateSinceUpdate = 0;
+                }
             }
         }
     }
diff --git a/libs/battery/MultiStateCounterTest.cpp b/libs/battery/MultiStateCounterTest.cpp
index 848fd10..876bf74 100644
--- a/libs/battery/MultiStateCounterTest.cpp
+++ b/libs/battery/MultiStateCounterTest.cpp
@@ -176,7 +176,7 @@
     testCounter.setState(0, 0);
     testCounter.updateValue(6.0, 2000);
 
-    // Time moves back. The negative delta from 2000 to 1000 is ignored
+    // Time moves back. The delta over the negative interval from 2000 to 1000 is ignored
     testCounter.updateValue(8.0, 1000);
     double delta = testCounter.updateValue(11.0, 3000);
 
@@ -189,6 +189,27 @@
     EXPECT_DOUBLE_EQ(3.0, delta);
 }
 
+TEST_F(MultiStateCounterTest, updateValue_nonmonotonic) {
+    DoubleMultiStateCounter testCounter(2, 0);
+    testCounter.updateValue(0, 0);
+    testCounter.setState(0, 0);
+    testCounter.updateValue(6.0, 2000);
+
+    // Value goes down. The negative delta from 6.0 to 4.0 is ignored
+    testCounter.updateValue(4.0, 3000);
+
+    // Value goes up again. The positive delta from 4.0 to 7.0 is accumulated.
+    double delta = testCounter.updateValue(7.0, 4000);
+
+    // The total accumulated count is:
+    //  6.0          // For the period 0-2000
+    //  +(7.0-4.0)   // For the period 3000-4000
+    EXPECT_DOUBLE_EQ(9.0, testCounter.getCount(0));
+
+    //  7.0-4.0
+    EXPECT_DOUBLE_EQ(3.0, delta);
+}
+
 TEST_F(MultiStateCounterTest, addValue) {
     DoubleMultiStateCounter testCounter(1, 0);
     testCounter.updateValue(0, 0);
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 34f1cbf..5baa4d7 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -32,9 +32,11 @@
 bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
                           void* param);
 
-// Starts an RPC server on a given port and a given root IBinder object.
-// This function sets up the server, calls readyCallback with a given param, and
-// then joins before returning.
+// Starts an RPC server on a given port and a given root IBinder factory.
+// RunRpcServerWithFactory acts like RunRpcServerCallback, but instead of
+// assigning single root IBinder object to all connections, factory is called
+// whenever a client connects, making it possible to assign unique IBinder
+// object to each client.
 bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
                           void* factoryContext, unsigned int port);
 
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index d63a8d0..197c0a1 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -119,11 +119,11 @@
     AIBinder_setRequestingSid; # apex
     AParcel_markSensitive; # systemapi llndk
     AServiceManager_forEachDeclaredInstance; # apex llndk
-    AServiceManager_forceLazyServicesPersist; # llndk
+    AServiceManager_forceLazyServicesPersist; # apex llndk
     AServiceManager_isDeclared; # apex llndk
     AServiceManager_isUpdatableViaApex; # apex
     AServiceManager_reRegister; # llndk
-    AServiceManager_registerLazyService; # llndk
+    AServiceManager_registerLazyService; # apex llndk
     AServiceManager_setActiveServicesCallback; # llndk
     AServiceManager_tryUnregister; # llndk
     AServiceManager_waitForService; # apex llndk
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index d323022..4561d6e 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -20,6 +20,7 @@
         "libdowncast_rs",
     ],
     host_supported: true,
+    vendor_available: true,
     target: {
         darwin: {
             enabled: false,
@@ -64,6 +65,7 @@
         "libbinder_ndk",
     ],
     host_supported: true,
+    vendor_available: true,
     target: {
         darwin: {
             enabled: false,
@@ -105,6 +107,7 @@
         "libbinder_ndk",
     ],
     host_supported: true,
+    vendor_available: true,
 
     // Currently necessary for host builds
     // TODO(b/31559095): bionic on host should define this
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 4e048d7..d09ac83 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,7 +17,7 @@
 //! Trait definitions for binder objects
 
 use crate::error::{status_t, Result, StatusCode};
-use crate::parcel::{OwnedParcel, Parcel};
+use crate::parcel::{Parcel, BorrowedParcel};
 use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
 use crate::sys;
 
@@ -129,7 +129,7 @@
     /// Handle and reply to a request to invoke a transaction on this object.
     ///
     /// `reply` may be [`None`] if the sender does not expect a reply.
-    fn on_transact(&self, code: TransactionCode, data: &Parcel, reply: &mut Parcel) -> Result<()>;
+    fn on_transact(&self, code: TransactionCode, data: &BorrowedParcel<'_>, reply: &mut BorrowedParcel<'_>) -> Result<()>;
 
     /// Handle a request to invoke the dump transaction on this
     /// object.
@@ -167,6 +167,7 @@
     fn ping_binder(&mut self) -> Result<()>;
 
     /// Indicate that the service intends to receive caller security contexts.
+    #[cfg(not(android_vndk))]
     fn set_requesting_sid(&mut self, enable: bool);
 
     /// Dump this object to the given file handle
@@ -177,25 +178,25 @@
     fn get_extension(&mut self) -> Result<Option<SpIBinder>>;
 
     /// Create a Parcel that can be used with `submit_transact`.
-    fn prepare_transact(&self) -> Result<OwnedParcel>;
+    fn prepare_transact(&self) -> Result<Parcel>;
 
     /// Perform a generic operation with the object.
     ///
-    /// The provided [`OwnedParcel`] must have been created by a call to
+    /// The provided [`Parcel`] must have been created by a call to
     /// `prepare_transact` on the same binder.
     ///
     /// # Arguments
     ///
     /// * `code` - Transaction code for the operation.
-    /// * `data` - [`OwnedParcel`] with input data.
+    /// * `data` - [`Parcel`] with input data.
     /// * `flags` - Transaction flags, e.g. marking the transaction as
     ///   asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY)).
     fn submit_transact(
         &self,
         code: TransactionCode,
-        data: OwnedParcel,
+        data: Parcel,
         flags: TransactionFlags,
-    ) -> Result<OwnedParcel>;
+    ) -> Result<Parcel>;
 
     /// Perform a generic operation with the object. This is a convenience
     /// method that internally calls `prepare_transact` followed by
@@ -206,15 +207,15 @@
     /// * `flags` - Transaction flags, e.g. marking the transaction as
     ///   asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY))
     /// * `input_callback` A callback for building the `Parcel`.
-    fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
+    fn transact<F: FnOnce(BorrowedParcel<'_>) -> Result<()>>(
         &self,
         code: TransactionCode,
         flags: TransactionFlags,
         input_callback: F,
     ) -> Result<Parcel> {
         let mut parcel = self.prepare_transact()?;
-        input_callback(&mut parcel.borrowed())?;
-        self.submit_transact(code, parcel, flags).map(OwnedParcel::into_parcel)
+        input_callback(parcel.borrowed())?;
+        self.submit_transact(code, parcel, flags)
     }
 }
 
@@ -475,8 +476,8 @@
 ///     fn on_transact(
 ///         &self,
 ///         code: TransactionCode,
-///         data: &Parcel,
-///         reply: &mut Parcel,
+///         data: &BorrowedParcel,
+///         reply: &mut BorrowedParcel,
 ///     ) -> Result<()> {
 ///         // ...
 ///     }
@@ -635,6 +636,7 @@
 pub struct BinderFeatures {
     /// Indicates that the service intends to receive caller security contexts. This must be true
     /// for `ThreadState::with_calling_sid` to work.
+    #[cfg(not(android_vndk))]
     pub set_requesting_sid: bool,
     // Ensure that clients include a ..BinderFeatures::default() to preserve backwards compatibility
     // when new fields are added. #[non_exhaustive] doesn't work because it prevents struct
@@ -655,13 +657,13 @@
 /// have the following type:
 ///
 /// ```
-/// # use binder::{Interface, TransactionCode, Parcel};
+/// # use binder::{Interface, TransactionCode, BorrowedParcel};
 /// # trait Placeholder {
 /// fn on_transact(
 ///     service: &dyn Interface,
 ///     code: TransactionCode,
-///     data: &Parcel,
-///     reply: &mut Parcel,
+///     data: &BorrowedParcel,
+///     reply: &mut BorrowedParcel,
 /// ) -> binder::Result<()>;
 /// # }
 /// ```
@@ -676,7 +678,7 @@
 /// using the provided function, `on_transact`.
 ///
 /// ```
-/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, Parcel};
+/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, BorrowedParcel};
 ///
 /// pub trait IServiceManager: Interface {
 ///     // remote methods...
@@ -692,8 +694,8 @@
 /// fn on_transact(
 ///     service: &dyn IServiceManager,
 ///     code: TransactionCode,
-///     data: &Parcel,
-///     reply: &mut Parcel,
+///     data: &BorrowedParcel,
+///     reply: &mut BorrowedParcel,
 /// ) -> binder::Result<()> {
 ///     // ...
 ///     Ok(())
@@ -837,6 +839,7 @@
             /// Create a new binder service.
             pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> {
                 let mut binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
+                #[cfg(not(android_vndk))]
                 $crate::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
                 $crate::Strong::new(Box::new(binder))
             }
@@ -847,7 +850,7 @@
                 $descriptor
             }
 
-            fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::Parcel, reply: &mut $crate::Parcel) -> $crate::Result<()> {
+            fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::BorrowedParcel<'_>, reply: &mut $crate::BorrowedParcel<'_>) -> $crate::Result<()> {
                 match $on_transact(&*self.0, code, data, reply) {
                     // The C++ backend converts UNEXPECTED_NULL into an exception
                     Err($crate::StatusCode::UNEXPECTED_NULL) => {
@@ -922,14 +925,14 @@
         where
             dyn $interface: $crate::Interface
         {
-            fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 let binder = $crate::Interface::as_binder(self);
                 parcel.write(&binder)
             }
         }
 
         impl $crate::parcel::SerializeOption for dyn $interface + '_ {
-            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 parcel.write(&this.map($crate::Interface::as_binder))
             }
         }
@@ -988,14 +991,14 @@
         }
 
         impl<P: $crate::BinderAsyncPool> $crate::parcel::Serialize for dyn $async_interface<P> + '_ {
-            fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 let binder = $crate::Interface::as_binder(self);
                 parcel.write(&binder)
             }
         }
 
         impl<P: $crate::BinderAsyncPool> $crate::parcel::SerializeOption for dyn $async_interface<P> + '_ {
-            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 parcel.write(&this.map($crate::Interface::as_binder))
             }
         }
@@ -1040,26 +1043,26 @@
         }
 
         impl $crate::parcel::Serialize for $enum {
-            fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 parcel.write(&self.0)
             }
         }
 
         impl $crate::parcel::SerializeArray for $enum {
-            fn serialize_array(slice: &[Self], parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize_array(slice: &[Self], parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 let v: Vec<$backing> = slice.iter().map(|x| x.0).collect();
                 <$backing as binder::parcel::SerializeArray>::serialize_array(&v[..], parcel)
             }
         }
 
         impl $crate::parcel::Deserialize for $enum {
-            fn deserialize(parcel: &$crate::parcel::Parcel) -> $crate::Result<Self> {
+            fn deserialize(parcel: &$crate::parcel::BorrowedParcel<'_>) -> $crate::Result<Self> {
                 parcel.read().map(Self)
             }
         }
 
         impl $crate::parcel::DeserializeArray for $enum {
-            fn deserialize_array(parcel: &$crate::parcel::Parcel) -> $crate::Result<Option<Vec<Self>>> {
+            fn deserialize_array(parcel: &$crate::parcel::BorrowedParcel<'_>) -> $crate::Result<Option<Vec<Self>>> {
                 let v: Option<Vec<$backing>> =
                     <$backing as binder::parcel::DeserializeArray>::deserialize_array(parcel)?;
                 Ok(v.map(|v| v.into_iter().map(Self).collect()))
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 2ac2d2f..cce55c0 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -50,8 +50,8 @@
 //! fn on_transact(
 //!     service: &dyn ITest,
 //!     code: TransactionCode,
-//!     _data: &Parcel,
-//!     reply: &mut Parcel,
+//!     _data: &BorrowedParcel,
+//!     reply: &mut BorrowedParcel,
 //! ) -> binder::Result<()> {
 //!     match code {
 //!         SpIBinder::FIRST_CALL_TRANSACTION => {
@@ -115,7 +115,7 @@
 pub use crate::binder_async::{BoxFuture, BinderAsyncPool};
 pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
 pub use native::{add_service, force_lazy_services_persist, register_lazy_service, Binder};
-pub use parcel::{OwnedParcel, Parcel};
+pub use parcel::{BorrowedParcel, Parcel};
 pub use proxy::{get_interface, get_service, wait_for_interface, wait_for_service};
 pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
 pub use state::{ProcessState, ThreadState};
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index a91092e..e183ea3 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -18,7 +18,7 @@
     AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode,
 };
 use crate::error::{status_result, status_t, Result, StatusCode};
-use crate::parcel::{Parcel, Serialize};
+use crate::parcel::{BorrowedParcel, Serialize};
 use crate::proxy::SpIBinder;
 use crate::sys;
 
@@ -161,8 +161,8 @@
     ///        # fn on_transact(
     ///        #     service: &dyn IBar,
     ///        #     code: TransactionCode,
-    ///        #     data: &Parcel,
-    ///        #     reply: &mut Parcel,
+    ///        #     data: &BorrowedParcel,
+    ///        #     reply: &mut BorrowedParcel,
     ///        # ) -> binder::Result<()> {
     ///        #     Ok(())
     ///        # }
@@ -212,7 +212,7 @@
 
     /// Mark this binder object with local stability, which is vendor if we are
     /// building for the VNDK and system otherwise.
-    #[cfg(vendor_ndk)]
+    #[cfg(any(vendor_ndk, android_vndk))]
     fn mark_local_stability(&mut self) {
         unsafe {
             // Safety: Self always contains a valid `AIBinder` pointer, so
@@ -223,7 +223,7 @@
 
     /// Mark this binder object with local stability, which is vendor if we are
     /// building for the VNDK and system otherwise.
-    #[cfg(not(vendor_ndk))]
+    #[cfg(not(any(vendor_ndk, android_vndk)))]
     fn mark_local_stability(&mut self) {
         unsafe {
             // Safety: Self always contains a valid `AIBinder` pointer, so
@@ -277,8 +277,8 @@
         reply: *mut sys::AParcel,
     ) -> status_t {
         let res = {
-            let mut reply = Parcel::borrowed(reply).unwrap();
-            let data = Parcel::borrowed(data as *mut sys::AParcel).unwrap();
+            let mut reply = BorrowedParcel::from_raw(reply).unwrap();
+            let data = BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap();
             let object = sys::AIBinder_getUserData(binder);
             let binder: &T = &*(object as *const T);
             binder.on_transact(code, &data, &mut reply)
@@ -384,7 +384,7 @@
 }
 
 impl<B: Remotable> Serialize for Binder<B> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         parcel.write_binder(Some(&self.as_binder()))
     }
 }
@@ -503,8 +503,8 @@
     fn on_transact(
         &self,
         _code: TransactionCode,
-        _data: &Parcel,
-        _reply: &mut Parcel,
+        _data: &BorrowedParcel<'_>,
+        _reply: &mut BorrowedParcel<'_>,
     ) -> Result<()> {
         Ok(())
     }
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index a0e1478..206b90c 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -21,11 +21,10 @@
 use crate::proxy::SpIBinder;
 use crate::sys;
 
-use std::cell::RefCell;
 use std::convert::TryInto;
 use std::marker::PhantomData;
 use std::mem::ManuallyDrop;
-use std::ptr;
+use std::ptr::{self, NonNull};
 use std::fmt;
 
 mod file_descriptor;
@@ -46,53 +45,41 @@
 /// other side of the IPC, and references to live Binder objects that will
 /// result in the other side receiving a proxy Binder connected with the
 /// original Binder in the Parcel.
-pub enum Parcel {
-    /// Owned parcel pointer
-    Owned(*mut sys::AParcel),
-    /// Borrowed parcel pointer (will not be destroyed on drop)
-    Borrowed(*mut sys::AParcel),
-}
-
-/// A variant of Parcel that is known to be owned.
-pub struct OwnedParcel {
-    ptr: *mut sys::AParcel,
+///
+/// This type represents a parcel that is owned by Rust code.
+#[repr(transparent)]
+pub struct Parcel {
+    ptr: NonNull<sys::AParcel>,
 }
 
 /// # Safety
 ///
 /// This type guarantees that it owns the AParcel and that all access to
-/// the AParcel happens through the OwnedParcel, so it is ok to send across
+/// the AParcel happens through the Parcel, so it is ok to send across
 /// threads.
-unsafe impl Send for OwnedParcel {}
+unsafe impl Send for Parcel {}
 
-/// A variant of Parcel that is known to be borrowed.
+/// Container for a message (data and object references) that can be sent
+/// through Binder.
+///
+/// This object is a borrowed variant of [`Parcel`]. It is a separate type from
+/// `&mut Parcel` because it is not valid to `mem::swap` two parcels.
+#[repr(transparent)]
 pub struct BorrowedParcel<'a> {
-    inner: Parcel,
+    ptr: NonNull<sys::AParcel>,
     _lifetime: PhantomData<&'a mut Parcel>,
 }
 
-impl OwnedParcel {
-    /// Create a new empty `OwnedParcel`.
-    pub fn new() -> OwnedParcel {
+impl Parcel {
+    /// Create a new empty `Parcel`.
+    pub fn new() -> Parcel {
         let ptr = unsafe {
             // Safety: If `AParcel_create` succeeds, it always returns
             // a valid pointer. If it fails, the process will crash.
             sys::AParcel_create()
         };
-        assert!(!ptr.is_null());
-        Self { ptr }
-    }
-
-    /// Convert the provided parcel to an owned parcel, or return `None` if it
-    /// is borrowed.
-    pub fn try_from(parcel: Parcel) -> Option<OwnedParcel> {
-        match &parcel {
-            Parcel::Owned(ptr) => {
-                let ptr = *ptr;
-                std::mem::forget(parcel);
-                Some(OwnedParcel { ptr })
-            }
-            Parcel::Borrowed(_) => None,
+        Self {
+            ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer")
         }
     }
 
@@ -107,108 +94,43 @@
     ///
     /// Additionally, the caller must guarantee that it is valid to take
     /// ownership of the AParcel object. All future access to the AParcel
-    /// must happen through this `OwnedParcel`.
+    /// must happen through this `Parcel`.
     ///
-    /// Because `OwnedParcel` implements `Send`, the pointer must never point
-    /// to any thread-local data, e.g., a variable on the stack, either directly
-    /// or indirectly.
-    pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<OwnedParcel> {
-        ptr.as_mut().map(|ptr| Self { ptr })
+    /// Because `Parcel` implements `Send`, the pointer must never point to any
+    /// thread-local data, e.g., a variable on the stack, either directly or
+    /// indirectly.
+    pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<Parcel> {
+        NonNull::new(ptr).map(|ptr| Self { ptr })
     }
 
     /// Consume the parcel, transferring ownership to the caller.
     pub(crate) fn into_raw(self) -> *mut sys::AParcel {
-        let ptr = self.ptr;
+        let ptr = self.ptr.as_ptr();
         let _ = ManuallyDrop::new(self);
         ptr
     }
 
-    /// Convert this `OwnedParcel` into an owned `Parcel`.
-    pub fn into_parcel(self) -> Parcel {
-        Parcel::Owned(self.into_raw())
-    }
-
     /// Get a borrowed view into the contents of this `Parcel`.
     pub fn borrowed(&mut self) -> BorrowedParcel<'_> {
+        // Safety: The raw pointer is a valid pointer to an AParcel, and the
+        // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
+        // borrow checker will ensure that the `AParcel` can only be accessed
+        // via the `BorrowParcel` until it goes out of scope.
         BorrowedParcel {
-            inner: Parcel::Borrowed(self.ptr),
+            ptr: self.ptr,
             _lifetime: PhantomData,
         }
     }
-}
 
-impl Default for OwnedParcel {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-impl Clone for OwnedParcel {
-    fn clone(&self) -> Self {
-        let mut new_parcel = Self::new();
-        new_parcel
-            .borrowed()
-            .append_all_from(&Parcel::Borrowed(self.ptr))
-            .expect("Failed to append from Parcel");
-        new_parcel
-    }
-}
-
-impl<'a> std::ops::Deref for BorrowedParcel<'a> {
-    type Target = Parcel;
-    fn deref(&self) -> &Parcel {
-        &self.inner
-    }
-}
-impl<'a> std::ops::DerefMut for BorrowedParcel<'a> {
-    fn deref_mut(&mut self) -> &mut Parcel {
-        &mut self.inner
-    }
-}
-
-/// # Safety
-///
-/// The `Parcel` constructors guarantee that a `Parcel` object will always
-/// contain a valid pointer to an `AParcel`.
-unsafe impl AsNative<sys::AParcel> for Parcel {
-    fn as_native(&self) -> *const sys::AParcel {
-        match *self {
-            Self::Owned(x) | Self::Borrowed(x) => x,
+    /// Get an immutable borrowed view into the contents of this `Parcel`.
+    pub fn borrowed_ref(&self) -> &BorrowedParcel<'_> {
+        // Safety: Parcel and BorrowedParcel are both represented in the same
+        // way as a NonNull<sys::AParcel> due to their use of repr(transparent),
+        // so casting references as done here is valid.
+        unsafe {
+            &*(self as *const Parcel as *const BorrowedParcel<'_>)
         }
     }
-
-    fn as_native_mut(&mut self) -> *mut sys::AParcel {
-        match *self {
-            Self::Owned(x) | Self::Borrowed(x) => x,
-        }
-    }
-}
-
-impl Parcel {
-    /// Create a new empty `Parcel`.
-    ///
-    /// Creates a new owned empty parcel that can be written to
-    /// using the serialization methods and appended to and
-    /// from using `append_from` and `append_from_all`.
-    pub fn new() -> Parcel {
-        let parcel = unsafe {
-            // Safety: If `AParcel_create` succeeds, it always returns
-            // a valid pointer. If it fails, the process will crash.
-            sys::AParcel_create()
-        };
-        assert!(!parcel.is_null());
-        Self::Owned(parcel)
-    }
-
-    /// Create a borrowed reference to a parcel object from a raw pointer.
-    ///
-    /// # Safety
-    ///
-    /// This constructor is safe if the raw pointer parameter is either null
-    /// (resulting in `None`), or a valid pointer to an `AParcel` object.
-    pub(crate) unsafe fn borrowed(ptr: *mut sys::AParcel) -> Option<Parcel> {
-        ptr.as_mut().map(|ptr| Self::Borrowed(ptr))
-    }
 }
 
 impl Default for Parcel {
@@ -221,14 +143,77 @@
     fn clone(&self) -> Self {
         let mut new_parcel = Self::new();
         new_parcel
-            .append_all_from(self)
+            .borrowed()
+            .append_all_from(self.borrowed_ref())
             .expect("Failed to append from Parcel");
         new_parcel
     }
 }
 
+impl<'a> BorrowedParcel<'a> {
+    /// Create a borrowed reference to a parcel object from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// This constructor is safe if the raw pointer parameter is either null
+    /// (resulting in `None`), or a valid pointer to an `AParcel` object.
+    ///
+    /// Since the raw pointer is not restricted by any lifetime, the lifetime on
+    /// the returned `BorrowedParcel` object can be chosen arbitrarily by the
+    /// caller. The caller must ensure it is valid to mutably borrow the AParcel
+    /// for the duration of the lifetime that the caller chooses. Note that
+    /// since this is a mutable borrow, it must have exclusive access to the
+    /// AParcel for the duration of the borrow.
+    pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<BorrowedParcel<'a>> {
+        Some(Self {
+            ptr: NonNull::new(ptr)?,
+            _lifetime: PhantomData,
+        })
+    }
+
+    /// Get a sub-reference to this reference to the parcel.
+    pub fn reborrow(&mut self) -> BorrowedParcel<'_> {
+        // Safety: The raw pointer is a valid pointer to an AParcel, and the
+        // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
+        // borrow checker will ensure that the `AParcel` can only be accessed
+        // via the `BorrowParcel` until it goes out of scope.
+        BorrowedParcel {
+            ptr: self.ptr,
+            _lifetime: PhantomData,
+        }
+    }
+}
+
+/// # Safety
+///
+/// The `Parcel` constructors guarantee that a `Parcel` object will always
+/// contain a valid pointer to an `AParcel`.
+unsafe impl AsNative<sys::AParcel> for Parcel {
+    fn as_native(&self) -> *const sys::AParcel {
+        self.ptr.as_ptr()
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AParcel {
+        self.ptr.as_ptr()
+    }
+}
+
+/// # Safety
+///
+/// The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` object
+/// will always contain a valid pointer to an `AParcel`.
+unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> {
+    fn as_native(&self) -> *const sys::AParcel {
+        self.ptr.as_ptr()
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AParcel {
+        self.ptr.as_ptr()
+    }
+}
+
 // Data serialization methods
-impl Parcel {
+impl<'a> BorrowedParcel<'a> {
     /// Data written to parcelable is zero'd before being deleted or reallocated.
     pub fn mark_sensitive(&mut self) {
         unsafe {
@@ -237,12 +222,12 @@
         }
     }
 
-    /// Write a type that implements [`Serialize`] to the `Parcel`.
+    /// Write a type that implements [`Serialize`] to the parcel.
     pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
         parcelable.serialize(self)
     }
 
-    /// Writes the length of a slice to the `Parcel`.
+    /// Writes the length of a slice to the parcel.
     ///
     /// This is used in AIDL-generated client side code to indicate the
     /// allocated space for an output array parameter.
@@ -255,7 +240,7 @@
         }
     }
 
-    /// Perform a series of writes to the `Parcel`, prepended with the length
+    /// Perform a series of writes to the parcel, prepended with the length
     /// (in bytes) of the written data.
     ///
     /// The length `0i32` will be written to the parcel first, followed by the
@@ -269,7 +254,7 @@
     ///
     /// ```
     /// # use binder::{Binder, Interface, Parcel};
-    /// # let mut parcel = Parcel::Owned(std::ptr::null_mut());
+    /// # let mut parcel = Parcel::new();
     /// parcel.sized_write(|subparcel| {
     ///     subparcel.write(&1u32)?;
     ///     subparcel.write(&2u32)?;
@@ -283,14 +268,14 @@
     /// [16i32, 1u32, 2u32, 3u32]
     /// ```
     pub fn sized_write<F>(&mut self, f: F) -> Result<()>
-    where for<'a>
-        F: Fn(&'a WritableSubParcel<'a>) -> Result<()>
+    where
+        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
     {
         let start = self.get_data_position();
         self.write(&0i32)?;
         {
-            let subparcel = WritableSubParcel(RefCell::new(self));
-            f(&subparcel)?;
+            let mut subparcel = WritableSubParcel(self.reborrow());
+            f(&mut subparcel)?;
         }
         let end = self.get_data_position();
         unsafe {
@@ -307,8 +292,8 @@
     /// Returns the current position in the parcel data.
     pub fn get_data_position(&self) -> i32 {
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an `AParcel`,
-            // and this call is otherwise safe.
+            // Safety: `BorrowedParcel` always contains a valid pointer to an
+            // `AParcel`, and this call is otherwise safe.
             sys::AParcel_getDataPosition(self.as_native())
         }
     }
@@ -316,8 +301,8 @@
     /// Returns the total size of the parcel.
     pub fn get_data_size(&self) -> i32 {
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an `AParcel`,
-            // and this call is otherwise safe.
+            // Safety: `BorrowedParcel` always contains a valid pointer to an
+            // `AParcel`, and this call is otherwise safe.
             sys::AParcel_getDataSize(self.as_native())
         }
     }
@@ -335,11 +320,11 @@
         status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
     }
 
-    /// Append a subset of another `Parcel`.
+    /// Append a subset of another parcel.
     ///
     /// This appends `size` bytes of data from `other` starting at offset
-    /// `start` to the current `Parcel`, or returns an error if not possible.
-    pub fn append_from(&mut self, other: &Self, start: i32, size: i32) -> Result<()> {
+    /// `start` to the current parcel, or returns an error if not possible.
+    pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
         let status = unsafe {
             // Safety: `Parcel::appendFrom` from C++ checks that `start`
             // and `size` are in bounds, and returns an error otherwise.
@@ -354,33 +339,125 @@
         status_result(status)
     }
 
-    /// Append the contents of another `Parcel`.
-    pub fn append_all_from(&mut self, other: &Self) -> Result<()> {
-        self.append_from(other, 0, other.get_data_size())
+    /// Append the contents of another parcel.
+    pub fn append_all_from(&mut self, other: &impl AsNative<sys::AParcel>) -> Result<()> {
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`, and this call is otherwise safe.
+        let size = unsafe { sys::AParcel_getDataSize(other.as_native()) };
+        self.append_from(other, 0, size)
     }
 }
 
-/// A segment of a writable parcel, used for [`Parcel::sized_write`].
-pub struct WritableSubParcel<'a>(RefCell<&'a mut Parcel>);
+/// A segment of a writable parcel, used for [`BorrowedParcel::sized_write`].
+pub struct WritableSubParcel<'a>(BorrowedParcel<'a>);
 
 impl<'a> WritableSubParcel<'a> {
     /// Write a type that implements [`Serialize`] to the sub-parcel.
-    pub fn write<S: Serialize + ?Sized>(&self, parcelable: &S) -> Result<()> {
-        parcelable.serialize(&mut *self.0.borrow_mut())
+    pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
+        parcelable.serialize(&mut self.0)
+    }
+}
+
+impl Parcel {
+    /// Data written to parcelable is zero'd before being deleted or reallocated.
+    pub fn mark_sensitive(&mut self) {
+        self.borrowed().mark_sensitive()
+    }
+
+    /// Write a type that implements [`Serialize`] to the parcel.
+    pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
+        self.borrowed().write(parcelable)
+    }
+
+    /// Writes the length of a slice to the parcel.
+    ///
+    /// This is used in AIDL-generated client side code to indicate the
+    /// allocated space for an output array parameter.
+    pub fn write_slice_size<T>(&mut self, slice: Option<&[T]>) -> Result<()> {
+        self.borrowed().write_slice_size(slice)
+    }
+
+    /// Perform a series of writes to the parcel, prepended with the length
+    /// (in bytes) of the written data.
+    ///
+    /// The length `0i32` will be written to the parcel first, followed by the
+    /// writes performed by the callback. The initial length will then be
+    /// updated to the length of all data written by the callback, plus the
+    /// size of the length elemement itself (4 bytes).
+    ///
+    /// # Examples
+    ///
+    /// After the following call:
+    ///
+    /// ```
+    /// # use binder::{Binder, Interface, Parcel};
+    /// # let mut parcel = Parcel::new();
+    /// parcel.sized_write(|subparcel| {
+    ///     subparcel.write(&1u32)?;
+    ///     subparcel.write(&2u32)?;
+    ///     subparcel.write(&3u32)
+    /// });
+    /// ```
+    ///
+    /// `parcel` will contain the following:
+    ///
+    /// ```ignore
+    /// [16i32, 1u32, 2u32, 3u32]
+    /// ```
+    pub fn sized_write<F>(&mut self, f: F) -> Result<()>
+    where
+        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+    {
+        self.borrowed().sized_write(f)
+    }
+
+    /// Returns the current position in the parcel data.
+    pub fn get_data_position(&self) -> i32 {
+        self.borrowed_ref().get_data_position()
+    }
+
+    /// Returns the total size of the parcel.
+    pub fn get_data_size(&self) -> i32 {
+        self.borrowed_ref().get_data_size()
+    }
+
+    /// Move the current read/write position in the parcel.
+    ///
+    /// # Safety
+    ///
+    /// This method is safe if `pos` is less than the current size of the parcel
+    /// data buffer. Otherwise, we are relying on correct bounds checking in the
+    /// Parcel C++ code on every subsequent read or write to this parcel. If all
+    /// accesses are bounds checked, this call is still safe, but we can't rely
+    /// on that.
+    pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
+        self.borrowed_ref().set_data_position(pos)
+    }
+
+    /// Append a subset of another parcel.
+    ///
+    /// This appends `size` bytes of data from `other` starting at offset
+    /// `start` to the current parcel, or returns an error if not possible.
+    pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+        self.borrowed().append_from(other, start, size)
+    }
+
+    /// Append the contents of another parcel.
+    pub fn append_all_from(&mut self, other: &impl AsNative<sys::AParcel>) -> Result<()> {
+        self.borrowed().append_all_from(other)
     }
 }
 
 // Data deserialization methods
-impl Parcel {
-    /// Attempt to read a type that implements [`Deserialize`] from this
-    /// `Parcel`.
+impl<'a> BorrowedParcel<'a> {
+    /// Attempt to read a type that implements [`Deserialize`] from this parcel.
     pub fn read<D: Deserialize>(&self) -> Result<D> {
         D::deserialize(self)
     }
 
-    /// Attempt to read a type that implements [`Deserialize`] from this
-    /// `Parcel` onto an existing value. This operation will overwrite the old
-    /// value partially or completely, depending on how much data is available.
+    /// Attempt to read a type that implements [`Deserialize`] from this parcel
+    /// onto an existing value. This operation will overwrite the old value
+    /// partially or completely, depending on how much data is available.
     pub fn read_onto<D: Deserialize>(&self, x: &mut D) -> Result<()> {
         x.deserialize_from(self)
     }
@@ -413,9 +490,9 @@
     /// });
     /// ```
     ///
-    pub fn sized_read<F>(&self, mut f: F) -> Result<()>
+    pub fn sized_read<F>(&self, f: F) -> Result<()>
     where
-        for<'a> F: FnMut(ReadableSubParcel<'a>) -> Result<()>
+        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
     {
         let start = self.get_data_position();
         let parcelable_size: i32 = self.read()?;
@@ -430,7 +507,10 @@
         }
 
         let subparcel = ReadableSubParcel {
-            parcel: self,
+            parcel: BorrowedParcel {
+                ptr: self.ptr,
+                _lifetime: PhantomData,
+            },
             end_position: end,
         };
         f(subparcel)?;
@@ -444,8 +524,8 @@
         Ok(())
     }
 
-    /// Read a vector size from the `Parcel` and resize the given output vector
-    /// to be correctly sized for that amount of data.
+    /// Read a vector size from the parcel and resize the given output vector to
+    /// be correctly sized for that amount of data.
     ///
     /// This method is used in AIDL-generated server side code for methods that
     /// take a mutable slice reference parameter.
@@ -463,7 +543,7 @@
         Ok(())
     }
 
-    /// Read a vector size from the `Parcel` and either create a correctly sized
+    /// Read a vector size from the parcel and either create a correctly sized
     /// vector for that amount of data or set the output parameter to None if
     /// the vector should be null.
     ///
@@ -491,7 +571,7 @@
 
 /// A segment of a readable parcel, used for [`Parcel::sized_read`].
 pub struct ReadableSubParcel<'a> {
-    parcel: &'a Parcel,
+    parcel: BorrowedParcel<'a>,
     end_position: i32,
 }
 
@@ -501,7 +581,7 @@
         // The caller should have checked this,
         // but it can't hurt to double-check
         assert!(self.has_more_data());
-        D::deserialize(self.parcel)
+        D::deserialize(&self.parcel)
     }
 
     /// Check if the sub-parcel has more data to read
@@ -510,11 +590,82 @@
     }
 }
 
-// Internal APIs
 impl Parcel {
+    /// Attempt to read a type that implements [`Deserialize`] from this parcel.
+    pub fn read<D: Deserialize>(&self) -> Result<D> {
+        self.borrowed_ref().read()
+    }
+
+    /// Attempt to read a type that implements [`Deserialize`] from this parcel
+    /// onto an existing value. This operation will overwrite the old value
+    /// partially or completely, depending on how much data is available.
+    pub fn read_onto<D: Deserialize>(&self, x: &mut D) -> Result<()> {
+        self.borrowed_ref().read_onto(x)
+    }
+
+    /// Safely read a sized parcelable.
+    ///
+    /// Read the size of a parcelable, compute the end position
+    /// of that parcelable, then build a sized readable sub-parcel
+    /// and call a closure with the sub-parcel as its parameter.
+    /// The closure can keep reading data from the sub-parcel
+    /// until it runs out of input data. The closure is responsible
+    /// for calling [`ReadableSubParcel::has_more_data`] to check for
+    /// more data before every read, at least until Rust generators
+    /// are stabilized.
+    /// After the closure returns, skip to the end of the current
+    /// parcelable regardless of how much the closure has read.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// let mut parcelable = Default::default();
+    /// parcel.sized_read(|subparcel| {
+    ///     if subparcel.has_more_data() {
+    ///         parcelable.a = subparcel.read()?;
+    ///     }
+    ///     if subparcel.has_more_data() {
+    ///         parcelable.b = subparcel.read()?;
+    ///     }
+    ///     Ok(())
+    /// });
+    /// ```
+    ///
+    pub fn sized_read<F>(&self, f: F) -> Result<()>
+    where
+        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+    {
+        self.borrowed_ref().sized_read(f)
+    }
+
+    /// Read a vector size from the parcel and resize the given output vector to
+    /// be correctly sized for that amount of data.
+    ///
+    /// This method is used in AIDL-generated server side code for methods that
+    /// take a mutable slice reference parameter.
+    pub fn resize_out_vec<D: Default + Deserialize>(&self, out_vec: &mut Vec<D>) -> Result<()> {
+        self.borrowed_ref().resize_out_vec(out_vec)
+    }
+
+    /// Read a vector size from the parcel and either create a correctly sized
+    /// vector for that amount of data or set the output parameter to None if
+    /// the vector should be null.
+    ///
+    /// This method is used in AIDL-generated server side code for methods that
+    /// take a mutable slice reference parameter.
+    pub fn resize_nullable_out_vec<D: Default + Deserialize>(
+        &self,
+        out_vec: &mut Option<Vec<D>>,
+    ) -> Result<()> {
+        self.borrowed_ref().resize_nullable_out_vec(out_vec)
+    }
+}
+
+// Internal APIs
+impl<'a> BorrowedParcel<'a> {
     pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> {
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
+            // Safety: `BorrowedParcel` always contains a valid pointer to an
             // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
             // null or a valid pointer to an `AIBinder`, both of which are
             // valid, safe inputs to `AParcel_writeStrongBinder`.
@@ -534,7 +685,7 @@
     pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> {
         let mut binder = ptr::null_mut();
         let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
+            // Safety: `BorrowedParcel` always contains a valid pointer to an
             // `AParcel`. We pass a valid, mutable out pointer to the `binder`
             // parameter. After this call, `binder` will be either null or a
             // valid pointer to an `AIBinder` owned by the caller.
@@ -554,25 +705,11 @@
 impl Drop for Parcel {
     fn drop(&mut self) {
         // Run the C++ Parcel complete object destructor
-        if let Self::Owned(ptr) = *self {
-            unsafe {
-                // Safety: `Parcel` always contains a valid pointer to an
-                // `AParcel`. If we own the parcel, we can safely delete it
-                // here.
-                sys::AParcel_delete(ptr)
-            }
-        }
-    }
-}
-
-impl Drop for OwnedParcel {
-    fn drop(&mut self) {
-        // Run the C++ Parcel complete object destructor
         unsafe {
-            // Safety: `OwnedParcel` always contains a valid pointer to an
+            // Safety: `Parcel` always contains a valid pointer to an
             // `AParcel`. Since we own the parcel, we can safely delete it
             // here.
-            sys::AParcel_delete(self.ptr)
+            sys::AParcel_delete(self.ptr.as_ptr())
         }
     }
 }
@@ -584,9 +721,9 @@
     }
 }
 
-impl fmt::Debug for OwnedParcel {
+impl<'a> fmt::Debug for BorrowedParcel<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("OwnedParcel")
+        f.debug_struct("BorrowedParcel")
             .finish()
     }
 }
@@ -608,7 +745,7 @@
     assert_eq!(parcel.read::<Option<String>>(), Ok(None));
     assert_eq!(parcel.read::<String>(), Err(StatusCode::UNEXPECTED_NULL));
 
-    assert_eq!(parcel.read_binder().err(), Some(StatusCode::BAD_TYPE));
+    assert_eq!(parcel.borrowed_ref().read_binder().err(), Some(StatusCode::BAD_TYPE));
 
     parcel.write(&1i32).unwrap();
 
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 8bcc5d0..b0dea94 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -15,7 +15,7 @@
  */
 
 use super::{
-    Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
+    Deserialize, DeserializeArray, DeserializeOption, BorrowedParcel, Serialize, SerializeArray,
     SerializeOption,
 };
 use crate::binder::AsNative;
@@ -61,7 +61,7 @@
 }
 
 impl Serialize for ParcelFileDescriptor {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         let fd = self.0.as_raw_fd();
         let status = unsafe {
             // Safety: `Parcel` always contains a valid pointer to an
@@ -78,7 +78,7 @@
 impl SerializeArray for ParcelFileDescriptor {}
 
 impl SerializeOption for ParcelFileDescriptor {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         if let Some(f) = this {
             f.serialize(parcel)
         } else {
@@ -95,7 +95,7 @@
 }
 
 impl DeserializeOption for ParcelFileDescriptor {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         let mut fd = -1i32;
         unsafe {
             // Safety: `Parcel` always contains a valid pointer to an
@@ -125,7 +125,7 @@
 }
 
 impl Deserialize for ParcelFileDescriptor {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         Deserialize::deserialize(parcel)
             .transpose()
             .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index db9d8b0..9007cba 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -16,14 +16,14 @@
 
 use crate::binder::{AsNative, FromIBinder, Stability, Strong};
 use crate::error::{status_result, status_t, Result, Status, StatusCode};
-use crate::parcel::Parcel;
+use crate::parcel::BorrowedParcel;
 use crate::proxy::SpIBinder;
 use crate::sys;
 
 use std::convert::{TryFrom, TryInto};
 use std::ffi::c_void;
 use std::os::raw::{c_char, c_ulong};
-use std::mem::{self, MaybeUninit};
+use std::mem::{self, MaybeUninit, ManuallyDrop};
 use std::ptr;
 use std::slice;
 
@@ -39,7 +39,7 @@
     /// `Serialize::serialize` and its variants are generally
     /// preferred over this function, since the former also
     /// prepend a header.
-    fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()>;
+    fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
 
     /// Internal deserialization function for parcelables.
     ///
@@ -47,26 +47,26 @@
     /// `Deserialize::deserialize` and its variants are generally
     /// preferred over this function, since the former also
     /// parse the additional header.
-    fn read_from_parcel(&mut self, parcel: &Parcel) -> Result<()>;
+    fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>;
 }
 
 /// A struct whose instances can be written to a [`Parcel`].
 // Might be able to hook this up as a serde backend in the future?
 pub trait Serialize {
     /// Serialize this instance into the given [`Parcel`].
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()>;
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
 }
 
 /// A struct whose instances can be restored from a [`Parcel`].
 // Might be able to hook this up as a serde backend in the future?
 pub trait Deserialize: Sized {
     /// Deserialize an instance from the given [`Parcel`].
-    fn deserialize(parcel: &Parcel) -> Result<Self>;
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self>;
 
     /// Deserialize an instance from the given [`Parcel`] onto the
     /// current object. This operation will overwrite the old value
     /// partially or completely, depending on how much data is available.
-    fn deserialize_from(&mut self, parcel: &Parcel) -> Result<()> {
+    fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
         *self = Self::deserialize(parcel)?;
         Ok(())
     }
@@ -80,8 +80,8 @@
 // We want the default implementation for most types, but an override for
 // a few special ones like `readByteArray` for `u8`.
 pub trait SerializeArray: Serialize + Sized {
-    /// Serialize an array of this type into the given [`Parcel`].
-    fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+    /// Serialize an array of this type into the given parcel.
+    fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         let res = unsafe {
             // Safety: Safe FFI, slice will always be a safe pointer to pass.
             sys::AParcel_writeParcelableArray(
@@ -111,7 +111,7 @@
 
     let slice: &[T] = slice::from_raw_parts(array.cast(), index+1);
 
-    let mut parcel = match Parcel::borrowed(parcel) {
+    let mut parcel = match BorrowedParcel::from_raw(parcel) {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
@@ -126,8 +126,8 @@
 /// Defaults to calling Deserialize::deserialize() manually for every element,
 /// but can be overridden for custom implementations like `readByteArray`.
 pub trait DeserializeArray: Deserialize {
-    /// Deserialize an array of type from the given [`Parcel`].
-    fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+    /// Deserialize an array of type from the given parcel.
+    fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
         let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
         let res = unsafe {
             // Safety: Safe FFI, vec is the correct opaque type expected by
@@ -173,7 +173,7 @@
         None => return StatusCode::BAD_INDEX as status_t,
     };
 
-    let parcel = match Parcel::borrowed(parcel as *mut _) {
+    let parcel = match BorrowedParcel::from_raw(parcel as *mut _) {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
@@ -205,8 +205,8 @@
 // We also use it to provide a default implementation for AIDL-generated
 // parcelables.
 pub trait SerializeOption: Serialize {
-    /// Serialize an Option of this type into the given [`Parcel`].
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    /// Serialize an Option of this type into the given parcel.
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         if let Some(inner) = this {
             parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
             parcel.write(inner)
@@ -218,8 +218,8 @@
 
 /// Helper trait for types that can be nullable when deserialized.
 pub trait DeserializeOption: Deserialize {
-    /// Deserialize an Option of this type from the given [`Parcel`].
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    /// Deserialize an Option of this type from the given parcel.
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         let null: i32 = parcel.read()?;
         if null == NULL_PARCELABLE_FLAG {
             Ok(None)
@@ -228,10 +228,10 @@
         }
     }
 
-    /// Deserialize an Option of this type from the given [`Parcel`] onto the
+    /// Deserialize an Option of this type from the given parcel onto the
     /// current object. This operation will overwrite the current value
     /// partially or completely, depending on how much data is available.
-    fn deserialize_option_from(this: &mut Option<Self>, parcel: &Parcel) -> Result<()> {
+    fn deserialize_option_from(this: &mut Option<Self>, parcel: &BorrowedParcel<'_>) -> Result<()> {
         *this = Self::deserialize_option(parcel)?;
         Ok(())
     }
@@ -297,10 +297,23 @@
     };
 }
 
+/// Safety: All elements in the vector must be properly initialized.
+unsafe fn vec_assume_init<T>(vec: Vec<MaybeUninit<T>>) -> Vec<T> {
+    // We can convert from Vec<MaybeUninit<T>> to Vec<T> because MaybeUninit<T>
+    // has the same alignment and size as T, so the pointer to the vector
+    // allocation will be compatible.
+    let mut vec = ManuallyDrop::new(vec);
+    Vec::from_raw_parts(
+        vec.as_mut_ptr().cast(),
+        vec.len(),
+        vec.capacity(),
+    )
+}
+
 macro_rules! impl_parcelable {
     {Serialize, $ty:ty, $write_fn:path} => {
         impl Serialize for $ty {
-            fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+            fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
                 unsafe {
                     // Safety: `Parcel` always contains a valid pointer to an
                     // `AParcel`, and any `$ty` literal value is safe to pass to
@@ -313,7 +326,7 @@
 
     {Deserialize, $ty:ty, $read_fn:path} => {
         impl Deserialize for $ty {
-            fn deserialize(parcel: &Parcel) -> Result<Self> {
+            fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
                 let mut val = Self::default();
                 unsafe {
                     // Safety: `Parcel` always contains a valid pointer to an
@@ -329,7 +342,7 @@
 
     {SerializeArray, $ty:ty, $write_array_fn:path} => {
         impl SerializeArray for $ty {
-            fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+            fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
                 let status = unsafe {
                     // Safety: `Parcel` always contains a valid pointer to an
                     // `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
@@ -353,7 +366,7 @@
 
     {DeserializeArray, $ty:ty, $read_array_fn:path} => {
         impl DeserializeArray for $ty {
-            fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+            fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
                 let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
                 let status = unsafe {
                     // Safety: `Parcel` always contains a valid pointer to an
@@ -371,11 +384,8 @@
                     // Safety: We are assuming that the NDK correctly
                     // initialized every element of the vector by now, so we
                     // know that all the MaybeUninits are now properly
-                    // initialized. We can transmute from Vec<MaybeUninit<T>> to
-                    // Vec<T> because MaybeUninit<T> has the same alignment and
-                    // size as T, so the pointer to the vector allocation will
-                    // be compatible.
-                    mem::transmute(vec)
+                    // initialized.
+                    vec.map(|vec| vec_assume_init(vec))
                 };
                 Ok(vec)
             }
@@ -443,19 +453,19 @@
 impl DeserializeArray for bool {}
 
 impl Serialize for u8 {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         (*self as i8).serialize(parcel)
     }
 }
 
 impl Deserialize for u8 {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         i8::deserialize(parcel).map(|v| v as u8)
     }
 }
 
 impl SerializeArray for u8 {
-    fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+    fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         let status = unsafe {
             // Safety: `Parcel` always contains a valid pointer to an
             // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
@@ -474,19 +484,19 @@
 }
 
 impl Serialize for i16 {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         (*self as u16).serialize(parcel)
     }
 }
 
 impl Deserialize for i16 {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         u16::deserialize(parcel).map(|v| v as i16)
     }
 }
 
 impl SerializeArray for i16 {
-    fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+    fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         let status = unsafe {
             // Safety: `Parcel` always contains a valid pointer to an
             // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
@@ -505,7 +515,7 @@
 }
 
 impl SerializeOption for str {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         match this {
             None => unsafe {
                 // Safety: `Parcel` always contains a valid pointer to an
@@ -541,7 +551,7 @@
 }
 
 impl Serialize for str {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Some(self).serialize(parcel)
     }
 }
@@ -549,7 +559,7 @@
 impl SerializeArray for &str {}
 
 impl Serialize for String {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Some(self.as_str()).serialize(parcel)
     }
 }
@@ -557,13 +567,13 @@
 impl SerializeArray for String {}
 
 impl SerializeOption for String {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.map(String::as_str), parcel)
     }
 }
 
 impl Deserialize for Option<String> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let mut vec: Option<Vec<u8>> = None;
         let status = unsafe {
             // Safety: `Parcel` always contains a valid pointer to an `AParcel`.
@@ -591,7 +601,7 @@
 impl DeserializeArray for Option<String> {}
 
 impl Deserialize for String {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         Deserialize::deserialize(parcel)
             .transpose()
             .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
@@ -601,19 +611,19 @@
 impl DeserializeArray for String {}
 
 impl<T: SerializeArray> Serialize for [T] {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeArray::serialize_array(self, parcel)
     }
 }
 
 impl<T: SerializeArray> Serialize for Vec<T> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeArray::serialize_array(&self[..], parcel)
     }
 }
 
 impl<T: SerializeArray> SerializeOption for [T] {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         if let Some(v) = this {
             SerializeArray::serialize_array(v, parcel)
         } else {
@@ -623,13 +633,13 @@
 }
 
 impl<T: SerializeArray> SerializeOption for Vec<T> {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.map(Vec::as_slice), parcel)
     }
 }
 
 impl<T: DeserializeArray> Deserialize for Vec<T> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         DeserializeArray::deserialize_array(parcel)
             .transpose()
             .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
@@ -637,25 +647,25 @@
 }
 
 impl<T: DeserializeArray> DeserializeOption for Vec<T> {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         DeserializeArray::deserialize_array(parcel)
     }
 }
 
 impl Serialize for Stability {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         i32::from(*self).serialize(parcel)
     }
 }
 
 impl Deserialize for Stability {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         i32::deserialize(parcel).and_then(Stability::try_from)
     }
 }
 
 impl Serialize for Status {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         unsafe {
             // Safety: `Parcel` always contains a valid pointer to an `AParcel`
             // and `Status` always contains a valid pointer to an `AStatus`, so
@@ -670,7 +680,7 @@
 }
 
 impl Deserialize for Status {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let mut status_ptr = ptr::null_mut();
         let ret_status = unsafe {
             // Safety: `Parcel` always contains a valid pointer to an
@@ -691,13 +701,13 @@
 }
 
 impl<T: Serialize + FromIBinder + ?Sized> Serialize for Strong<T> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Serialize::serialize(&**self, parcel)
     }
 }
 
 impl<T: SerializeOption + FromIBinder + ?Sized> SerializeOption for Strong<T> {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.map(|b| &**b), parcel)
     }
 }
@@ -705,14 +715,14 @@
 impl<T: Serialize + FromIBinder + ?Sized> SerializeArray for Strong<T> {}
 
 impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let ibinder: SpIBinder = parcel.read()?;
         FromIBinder::try_from(ibinder)
     }
 }
 
 impl<T: FromIBinder + ?Sized> DeserializeOption for Strong<T> {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         let ibinder: Option<SpIBinder> = parcel.read()?;
         ibinder.map(FromIBinder::try_from).transpose()
     }
@@ -722,29 +732,29 @@
 
 // We need these to support Option<&T> for all T
 impl<T: Serialize + ?Sized> Serialize for &T {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Serialize::serialize(*self, parcel)
     }
 }
 
 impl<T: SerializeOption + ?Sized> SerializeOption for &T {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.copied(), parcel)
     }
 }
 
 impl<T: SerializeOption> Serialize for Option<T> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(self.as_ref(), parcel)
     }
 }
 
 impl<T: DeserializeOption> Deserialize for Option<T> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         DeserializeOption::deserialize_option(parcel)
     }
 
-    fn deserialize_from(&mut self, parcel: &Parcel) -> Result<()> {
+    fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
         DeserializeOption::deserialize_option_from(self, parcel)
     }
 }
@@ -762,7 +772,7 @@
         impl $crate::parcel::Serialize for $parcelable {
             fn serialize(
                 &self,
-                parcel: &mut $crate::parcel::Parcel,
+                parcel: &mut $crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<()> {
                 <Self as $crate::parcel::SerializeOption>::serialize_option(
                     Some(self),
@@ -776,7 +786,7 @@
         impl $crate::parcel::SerializeOption for $parcelable {
             fn serialize_option(
                 this: Option<&Self>,
-                parcel: &mut $crate::parcel::Parcel,
+                parcel: &mut $crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<()> {
                 if let Some(this) = this {
                     use $crate::parcel::Parcelable;
@@ -796,13 +806,12 @@
 /// `Deserialize`, `DeserializeArray` and `DeserializeOption` for
 /// structured parcelables. The target type must implement the
 /// `Parcelable` trait.
-/// ```
 #[macro_export]
 macro_rules! impl_deserialize_for_parcelable {
     ($parcelable:ident) => {
         impl $crate::parcel::Deserialize for $parcelable {
             fn deserialize(
-                parcel: &$crate::parcel::Parcel,
+                parcel: &$crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<Self> {
                 $crate::parcel::DeserializeOption::deserialize_option(parcel)
                     .transpose()
@@ -810,7 +819,7 @@
             }
             fn deserialize_from(
                 &mut self,
-                parcel: &$crate::parcel::Parcel,
+                parcel: &$crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<()> {
                 let status: i32 = parcel.read()?;
                 if status == $crate::parcel::NULL_PARCELABLE_FLAG {
@@ -826,7 +835,7 @@
 
         impl $crate::parcel::DeserializeOption for $parcelable {
             fn deserialize_option(
-                parcel: &$crate::parcel::Parcel,
+                parcel: &$crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<Option<Self>> {
                 let mut result = None;
                 Self::deserialize_option_from(&mut result, parcel)?;
@@ -834,7 +843,7 @@
             }
             fn deserialize_option_from(
                 this: &mut Option<Self>,
-                parcel: &$crate::parcel::Parcel,
+                parcel: &$crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<()> {
                 let status: i32 = parcel.read()?;
                 if status == $crate::parcel::NULL_PARCELABLE_FLAG {
@@ -851,326 +860,332 @@
 }
 
 impl<T: Serialize> Serialize for Box<T> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Serialize::serialize(&**self, parcel)
     }
 }
 
 impl<T: Deserialize> Deserialize for Box<T> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         Deserialize::deserialize(parcel).map(Box::new)
     }
 }
 
 impl<T: SerializeOption> SerializeOption for Box<T> {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.map(|inner| &**inner), parcel)
     }
 }
 
 impl<T: DeserializeOption> DeserializeOption for Box<T> {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         DeserializeOption::deserialize_option(parcel).map(|t| t.map(Box::new))
     }
 }
 
-#[test]
-fn test_custom_parcelable() {
-    struct Custom(u32, bool, String, Vec<String>);
+#[cfg(test)]
+mod tests {
+    use crate::Parcel;
+    use super::*;
 
-    impl Serialize for Custom {
-        fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
-            self.0.serialize(parcel)?;
-            self.1.serialize(parcel)?;
-            self.2.serialize(parcel)?;
-            self.3.serialize(parcel)
+    #[test]
+    fn test_custom_parcelable() {
+        struct Custom(u32, bool, String, Vec<String>);
+
+        impl Serialize for Custom {
+            fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+                self.0.serialize(parcel)?;
+                self.1.serialize(parcel)?;
+                self.2.serialize(parcel)?;
+                self.3.serialize(parcel)
+            }
         }
-    }
 
-    impl Deserialize for Custom {
-        fn deserialize(parcel: &Parcel) -> Result<Self> {
-            Ok(Custom(
-                parcel.read()?,
-                parcel.read()?,
-                parcel.read()?,
-                parcel.read::<Option<Vec<String>>>()?.unwrap(),
-            ))
+        impl Deserialize for Custom {
+            fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
+                Ok(Custom(
+                        parcel.read()?,
+                        parcel.read()?,
+                        parcel.read()?,
+                        parcel.read::<Option<Vec<String>>>()?.unwrap(),
+                        ))
+            }
         }
+
+        let string8 = "Custom Parcelable".to_string();
+
+        let s1 = "str1".to_string();
+        let s2 = "str2".to_string();
+        let s3 = "str3".to_string();
+
+        let strs = vec![s1, s2, s3];
+
+        let custom = Custom(123_456_789, true, string8, strs);
+
+        let mut parcel = Parcel::new();
+        let start = parcel.get_data_position();
+
+        assert!(custom.serialize(&mut parcel.borrowed()).is_ok());
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let custom2 = Custom::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(custom2.0, 123_456_789);
+        assert!(custom2.1);
+        assert_eq!(custom2.2, custom.2);
+        assert_eq!(custom2.3, custom.3);
     }
 
-    let string8 = "Custom Parcelable".to_string();
+    #[test]
+    #[allow(clippy::excessive_precision)]
+    fn test_slice_parcelables() {
+        let bools = [true, false, false, true];
 
-    let s1 = "str1".to_string();
-    let s2 = "str2".to_string();
-    let s3 = "str3".to_string();
+        let mut parcel = Parcel::new();
+        let start = parcel.get_data_position();
 
-    let strs = vec![s1, s2, s3];
+        assert!(bools.serialize(&mut parcel.borrowed()).is_ok());
 
-    let custom = Custom(123_456_789, true, string8, strs);
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
 
-    let mut parcel = Parcel::new();
-    let start = parcel.get_data_position();
+        assert_eq!(parcel.read::<u32>().unwrap(), 4);
+        assert_eq!(parcel.read::<u32>().unwrap(), 1);
+        assert_eq!(parcel.read::<u32>().unwrap(), 0);
+        assert_eq!(parcel.read::<u32>().unwrap(), 0);
+        assert_eq!(parcel.read::<u32>().unwrap(), 1);
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
 
-    assert!(custom.serialize(&mut parcel).is_ok());
+        let vec = Vec::<bool>::deserialize(parcel.borrowed_ref()).unwrap();
 
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
+        assert_eq!(vec, [true, false, false, true]);
+
+        let u8s = [101u8, 255, 42, 117];
+
+        let mut parcel = Parcel::new();
+        let start = parcel.get_data_position();
+
+        assert!(parcel.write(&u8s[..]).is_ok());
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
+        assert_eq!(vec, [101, 255, 42, 117]);
+
+        let i8s = [-128i8, 127, 42, -117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert!(parcel.write(&i8s[..]).is_ok());
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
+        assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
+
+        let u16s = [u16::max_value(), 12_345, 42, 117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(u16s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
+        assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
+        assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+        assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u16>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
+
+        let i16s = [i16::max_value(), i16::min_value(), 42, -117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(i16s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
+        assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
+        assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+        assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<i16>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
+
+        let u32s = [u32::max_value(), 12_345, 42, 117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(u32s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
+        assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
+        assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+        assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
+
+        let i32s = [i32::max_value(), i32::min_value(), 42, -117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(i32s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
+        assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
+        assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+        assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<i32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
+
+        let u64s = [u64::max_value(), 12_345, 42, 117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(u64s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
+
+        let i64s = [i64::max_value(), i64::min_value(), 42, -117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(i64s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<i64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
+
+        let f32s = [
+            std::f32::NAN,
+            std::f32::INFINITY,
+            1.23456789,
+            std::f32::EPSILON,
+        ];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(f32s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<f32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        // NAN != NAN so we can't use it in the assert_eq:
+        assert!(vec[0].is_nan());
+        assert_eq!(vec[1..], f32s[1..]);
+
+        let f64s = [
+            std::f64::NAN,
+            std::f64::INFINITY,
+            1.234567890123456789,
+            std::f64::EPSILON,
+        ];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(f64s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<f64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        // NAN != NAN so we can't use it in the assert_eq:
+        assert!(vec[0].is_nan());
+        assert_eq!(vec[1..], f64s[1..]);
+
+        let s1 = "Hello, Binder!";
+        let s2 = "This is a utf8 string.";
+        let s3 = "Some more text here.";
+        let s4 = "Embedded nulls \0 \0";
+
+        let strs = [s1, s2, s3, s4];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(strs.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<String>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, strs);
     }
-
-    let custom2 = Custom::deserialize(&parcel).unwrap();
-
-    assert_eq!(custom2.0, 123_456_789);
-    assert!(custom2.1);
-    assert_eq!(custom2.2, custom.2);
-    assert_eq!(custom2.3, custom.3);
-}
-
-#[test]
-#[allow(clippy::excessive_precision)]
-fn test_slice_parcelables() {
-    let bools = [true, false, false, true];
-
-    let mut parcel = Parcel::new();
-    let start = parcel.get_data_position();
-
-    assert!(bools.serialize(&mut parcel).is_ok());
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4);
-    assert_eq!(parcel.read::<u32>().unwrap(), 1);
-    assert_eq!(parcel.read::<u32>().unwrap(), 0);
-    assert_eq!(parcel.read::<u32>().unwrap(), 0);
-    assert_eq!(parcel.read::<u32>().unwrap(), 1);
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<bool>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [true, false, false, true]);
-
-    let u8s = [101u8, 255, 42, 117];
-
-    let mut parcel = Parcel::new();
-    let start = parcel.get_data_position();
-
-    assert!(parcel.write(&u8s[..]).is_ok());
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u8>::deserialize(&parcel).unwrap();
-    assert_eq!(vec, [101, 255, 42, 117]);
-
-    let i8s = [-128i8, 127, 42, -117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert!(parcel.write(&i8s[..]).is_ok());
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u8>::deserialize(&parcel).unwrap();
-    assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
-
-    let u16s = [u16::max_value(), 12_345, 42, 117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(u16s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
-    assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
-    assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
-    assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u16>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
-
-    let i16s = [i16::max_value(), i16::min_value(), 42, -117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(i16s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
-    assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
-    assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
-    assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<i16>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
-
-    let u32s = [u32::max_value(), 12_345, 42, 117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(u32s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
-    assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
-    assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
-    assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u32>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
-
-    let i32s = [i32::max_value(), i32::min_value(), 42, -117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(i32s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
-    assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
-    assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
-    assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<i32>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
-
-    let u64s = [u64::max_value(), 12_345, 42, 117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(u64s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u64>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
-
-    let i64s = [i64::max_value(), i64::min_value(), 42, -117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(i64s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<i64>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
-
-    let f32s = [
-        std::f32::NAN,
-        std::f32::INFINITY,
-        1.23456789,
-        std::f32::EPSILON,
-    ];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(f32s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<f32>::deserialize(&parcel).unwrap();
-
-    // NAN != NAN so we can't use it in the assert_eq:
-    assert!(vec[0].is_nan());
-    assert_eq!(vec[1..], f32s[1..]);
-
-    let f64s = [
-        std::f64::NAN,
-        std::f64::INFINITY,
-        1.234567890123456789,
-        std::f64::EPSILON,
-    ];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(f64s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<f64>::deserialize(&parcel).unwrap();
-
-    // NAN != NAN so we can't use it in the assert_eq:
-    assert!(vec[0].is_nan());
-    assert_eq!(vec[1..], f64s[1..]);
-
-    let s1 = "Hello, Binder!";
-    let s2 = "This is a utf8 string.";
-    let s3 = "Some more text here.";
-    let s4 = "Embedded nulls \0 \0";
-
-    let strs = [s1, s2, s3, s4];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(strs.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<String>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, strs);
 }
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index bccfd2d..b4282b2 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -16,7 +16,7 @@
 
 use crate::binder::Stability;
 use crate::error::{Result, StatusCode};
-use crate::parcel::{OwnedParcel, Parcel, Parcelable};
+use crate::parcel::{Parcel, BorrowedParcel, Parcelable};
 use crate::{impl_deserialize_for_parcelable, impl_serialize_for_parcelable};
 
 use downcast_rs::{impl_downcast, DowncastSync};
@@ -50,7 +50,7 @@
         parcelable: Arc<dyn AnyParcelable>,
         name: String,
     },
-    Parcel(OwnedParcel),
+    Parcel(Parcel),
 }
 
 impl Default for ParcelableHolderData {
@@ -148,7 +148,6 @@
                 }
             }
             ParcelableHolderData::Parcel(ref mut parcel) => {
-                let parcel = parcel.borrowed();
                 unsafe {
                     // Safety: 0 should always be a valid position.
                     parcel.set_data_position(0)?;
@@ -160,7 +159,7 @@
                 }
 
                 let mut parcelable = T::default();
-                parcelable.read_from_parcel(&parcel)?;
+                parcelable.read_from_parcel(parcel.borrowed_ref())?;
 
                 let parcelable = Arc::new(parcelable);
                 let result = Arc::clone(&parcelable);
@@ -181,7 +180,7 @@
 impl_deserialize_for_parcelable!(ParcelableHolder);
 
 impl Parcelable for ParcelableHolder {
-    fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
+    fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         parcel.write(&self.stability)?;
 
         let mut data = self.data.lock().unwrap();
@@ -214,14 +213,13 @@
                 Ok(())
             }
             ParcelableHolderData::Parcel(ref mut p) => {
-                let p = p.borrowed();
                 parcel.write(&p.get_data_size())?;
-                parcel.append_all_from(&p)
+                parcel.append_all_from(&*p)
             }
         }
     }
 
-    fn read_from_parcel(&mut self, parcel: &Parcel) -> Result<()> {
+    fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
         self.stability = parcel.read()?;
 
         let data_size: i32 = parcel.read()?;
@@ -242,10 +240,8 @@
             .checked_add(data_size)
             .ok_or(StatusCode::BAD_VALUE)?;
 
-        let mut new_parcel = OwnedParcel::new();
-        new_parcel
-            .borrowed()
-            .append_from(parcel, data_start, data_size)?;
+        let mut new_parcel = Parcel::new();
+        new_parcel.append_from(parcel, data_start, data_size)?;
         *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
 
         unsafe {
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index a8d0c33..760d862 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,8 +22,7 @@
 };
 use crate::error::{status_result, Result, StatusCode};
 use crate::parcel::{
-    Deserialize, DeserializeArray, DeserializeOption, OwnedParcel, Parcel, Serialize, SerializeArray,
-    SerializeOption,
+    Parcel, BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
 };
 use crate::sys;
 
@@ -235,7 +234,7 @@
 }
 
 impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
-    fn prepare_transact(&self) -> Result<OwnedParcel> {
+    fn prepare_transact(&self) -> Result<Parcel> {
         let mut input = ptr::null_mut();
         let status = unsafe {
             // Safety: `SpIBinder` guarantees that `self` always contains a
@@ -255,16 +254,16 @@
             // Safety: At this point, `input` is either a valid, owned `AParcel`
             // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
             // taking ownership of the parcel.
-            OwnedParcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
+            Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
         }
     }
 
     fn submit_transact(
         &self,
         code: TransactionCode,
-        data: OwnedParcel,
+        data: Parcel,
         flags: TransactionFlags,
-    ) -> Result<OwnedParcel> {
+    ) -> Result<Parcel> {
         let mut reply = ptr::null_mut();
         let status = unsafe {
             // Safety: `SpIBinder` guarantees that `self` always contains a
@@ -299,7 +298,7 @@
             // construct a `Parcel` out of it. `AIBinder_transact` passes
             // ownership of the `reply` parcel to Rust, so we need to
             // construct an owned variant.
-            OwnedParcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
+            Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
         }
     }
 
@@ -324,6 +323,7 @@
         status_result(status)
     }
 
+    #[cfg(not(android_vndk))]
     fn set_requesting_sid(&mut self, enable: bool) {
         unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) };
     }
@@ -415,13 +415,13 @@
 }
 
 impl Serialize for SpIBinder {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         parcel.write_binder(Some(self))
     }
 }
 
 impl SerializeOption for SpIBinder {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         parcel.write_binder(this)
     }
 }
@@ -429,7 +429,7 @@
 impl SerializeArray for SpIBinder {}
 
 impl Deserialize for SpIBinder {
-    fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<SpIBinder> {
         parcel
             .read_binder()
             .transpose()
@@ -438,7 +438,7 @@
 }
 
 impl DeserializeOption for SpIBinder {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<SpIBinder>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<SpIBinder>> {
         parcel.read_binder()
     }
 }
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index ebfe879..1fd2ead 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -17,7 +17,7 @@
 //! Rust Binder crate integration tests
 
 use binder::declare_binder_interface;
-use binder::parcel::{Parcel, OwnedParcel};
+use binder::parcel::BorrowedParcel;
 use binder::{
     Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
     FIRST_CALL_TRANSACTION,
@@ -179,8 +179,8 @@
 fn on_transact(
     service: &dyn ITest,
     code: TransactionCode,
-    _data: &Parcel,
-    reply: &mut Parcel,
+    _data: &BorrowedParcel<'_>,
+    reply: &mut BorrowedParcel<'_>,
 ) -> binder::Result<()> {
     match code.try_into()? {
         TestTransactionCode::Test => reply.write(&service.test()?),
@@ -218,24 +218,24 @@
     fn test(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
         let binder = self.binder.clone();
         P::spawn(
-            move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())).map(|p| OwnedParcel::try_from(p).unwrap()),
-            |reply| async move { reply?.into_parcel().read() }
+            move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())),
+            |reply| async move { reply?.read() }
         )
     }
 
     fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>> {
         let binder = self.binder.clone();
         P::spawn(
-            move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())).map(|p| OwnedParcel::try_from(p).unwrap()),
-            |reply| async move { reply?.into_parcel().read() }
+            move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())),
+            |reply| async move { reply?.read() }
         )
     }
 
     fn get_selinux_context(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
         let binder = self.binder.clone();
         P::spawn(
-            move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())).map(|p| OwnedParcel::try_from(p).unwrap()),
-            |reply| async move { reply?.into_parcel().read() }
+            move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())),
+            |reply| async move { reply?.read() }
         )
     }
 }
@@ -284,8 +284,8 @@
 fn on_transact_same_descriptor(
     _service: &dyn ITestSameDescriptor,
     _code: TransactionCode,
-    _data: &Parcel,
-    _reply: &mut Parcel,
+    _data: &BorrowedParcel<'_>,
+    _reply: &mut BorrowedParcel<'_>,
 ) -> binder::Result<()> {
     Ok(())
 }
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 66ba846..1fc761e 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -20,7 +20,7 @@
 use binder::declare_binder_interface;
 use binder::parcel::ParcelFileDescriptor;
 use binder::{
-    Binder, BinderFeatures, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
+    Binder, BinderFeatures, BorrowedParcel, ExceptionCode, Interface, Result, SpIBinder, Status,
     StatusCode, TransactionCode,
 };
 
@@ -111,8 +111,8 @@
 fn on_transact(
     _service: &dyn ReadParcelTest,
     code: TransactionCode,
-    parcel: &Parcel,
-    reply: &mut Parcel,
+    parcel: &BorrowedParcel<'_>,
+    reply: &mut BorrowedParcel<'_>,
 ) -> Result<()> {
     match code {
         bindings::Transaction_TEST_BOOL => {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 55ad3c6..5a96b78 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -22,6 +22,7 @@
 #include <aidl/IBinderRpcTest.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_libbinder.h>
 #include <binder/Binder.h>
@@ -1514,7 +1515,17 @@
     auto socket = rpcServer->releaseServer();
 
     auto keepAlive = sp<BBinder>::make();
-    ASSERT_EQ(OK, binder->setRpcClientDebug(std::move(socket), keepAlive));
+    auto setRpcClientDebugStatus = binder->setRpcClientDebug(std::move(socket), keepAlive);
+
+    if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+        ASSERT_EQ(INVALID_OPERATION, setRpcClientDebugStatus)
+                << "setRpcClientDebug should return INVALID_OPERATION on non-debuggable builds, "
+                   "but get "
+                << statusToString(setRpcClientDebugStatus);
+        GTEST_SKIP();
+    }
+
+    ASSERT_EQ(OK, setRpcClientDebugStatus);
 
     auto rpcSession = RpcSession::make();
     ASSERT_EQ(OK, rpcSession->setupInetClient("127.0.0.1", port));
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 9080822..5570321 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -138,7 +138,7 @@
         mSize(width, height),
         mRequestedSize(mSize),
         mFormat(format),
-        mNextTransaction(nullptr) {
+        mSyncTransaction(nullptr) {
     createBufferQueue(&mProducer, &mConsumer);
     // since the adapter is in the client process, set dequeue timeout
     // explicitly so that dequeueBuffer will block
@@ -290,7 +290,7 @@
                 // case, we don't actually want to flush the frames in between since they will get
                 // processed and merged with the sync transaction and released earlier than if they
                 // were sent to SF
-                if (mWaitForTransactionCallback && mNextTransaction == nullptr &&
+                if (mWaitForTransactionCallback && mSyncTransaction == nullptr &&
                     currFrameNumber >= mLastAcquiredFrameNumber) {
                     mWaitForTransactionCallback = false;
                     flushShadowQueue();
@@ -407,20 +407,11 @@
 
     // Release all buffers that are beyond the ones that we need to hold
     while (mPendingRelease.size() > numPendingBuffersToHold) {
-        const auto releaseBuffer = mPendingRelease.front();
+        const auto releasedBuffer = mPendingRelease.front();
         mPendingRelease.pop_front();
-        auto it = mSubmitted.find(releaseBuffer.callbackId);
-        if (it == mSubmitted.end()) {
-            BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s",
-                     releaseBuffer.callbackId.to_string().c_str());
-            return;
-        }
-        mNumAcquired--;
-        BQA_LOGV("released %s", releaseBuffer.callbackId.to_string().c_str());
-        mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
-        mSubmitted.erase(it);
+        releaseBuffer(releasedBuffer.callbackId, releasedBuffer.releaseFence);
         // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let
-        // onFrameAvailable handle processing them since it will merge with the nextTransaction.
+        // onFrameAvailable handle processing them since it will merge with the syncTransaction.
         if (!mWaitForTransactionCallback) {
             acquireNextBufferLocked(std::nullopt);
         }
@@ -432,6 +423,20 @@
     mCallbackCV.notify_all();
 }
 
+void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId,
+                                     const sp<Fence>& releaseFence) {
+    auto it = mSubmitted.find(callbackId);
+    if (it == mSubmitted.end()) {
+        BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s",
+                 callbackId.to_string().c_str());
+        return;
+    }
+    mNumAcquired--;
+    BQA_LOGV("released %s", callbackId.to_string().c_str());
+    mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
+    mSubmitted.erase(it);
+}
+
 void BLASTBufferQueue::acquireNextBufferLocked(
         const std::optional<SurfaceComposerClient::Transaction*> transaction) {
     ATRACE_CALL();
@@ -589,34 +594,57 @@
     mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence);
 }
 
+void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) {
+    if (mWaitForTransactionCallback && mNumFrameAvailable > 0) {
+        // We are waiting on a previous sync's transaction callback so allow another sync
+        // transaction to proceed.
+        //
+        // We need to first flush out the transactions that were in between the two syncs.
+        // We do this by merging them into mSyncTransaction so any buffer merging will get
+        // a release callback invoked. The release callback will be async so we need to wait
+        // on max acquired to make sure we have the capacity to acquire another buffer.
+        if (maxBuffersAcquired(false /* includeExtraAcquire */)) {
+            BQA_LOGD("waiting to flush shadow queue...");
+            mCallbackCV.wait(lock);
+        }
+        while (mNumFrameAvailable > 0) {
+            // flush out the shadow queue
+            acquireAndReleaseBuffer();
+        }
+    }
+
+    while (maxBuffersAcquired(false /* includeExtraAcquire */)) {
+        BQA_LOGD("waiting for free buffer.");
+        mCallbackCV.wait(lock);
+    }
+}
+
 void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
     ATRACE_CALL();
     std::unique_lock _lock{mMutex};
 
-    const bool nextTransactionSet = mNextTransaction != nullptr;
-    BQA_LOGV("onFrameAvailable-start nextTransactionSet=%s", boolToString(nextTransactionSet));
-    if (nextTransactionSet) {
-        if (mWaitForTransactionCallback) {
-            // We are waiting on a previous sync's transaction callback so allow another sync
-            // transaction to proceed.
-            //
-            // We need to first flush out the transactions that were in between the two syncs.
-            // We do this by merging them into mNextTransaction so any buffer merging will get
-            // a release callback invoked. The release callback will be async so we need to wait
-            // on max acquired to make sure we have the capacity to acquire another buffer.
-            if (maxBuffersAcquired(false /* includeExtraAcquire */)) {
-                BQA_LOGD("waiting to flush shadow queue...");
-                mCallbackCV.wait(_lock);
-            }
-            while (mNumFrameAvailable > 0) {
-                // flush out the shadow queue
-                acquireAndReleaseBuffer();
+    const bool syncTransactionSet = mSyncTransaction != nullptr;
+    BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet));
+
+    if (syncTransactionSet) {
+        bool mayNeedToWaitForBuffer = true;
+        // If we are going to re-use the same mSyncTransaction, release the buffer that may already
+        // be set in the Transaction. This is to allow us a free slot early to continue processing
+        // a new buffer.
+        if (!mAcquireSingleBuffer) {
+            auto bufferData = mSyncTransaction->getAndClearBuffer(mSurfaceControl);
+            if (bufferData) {
+                BQA_LOGD("Releasing previous buffer when syncing: framenumber=%" PRIu64,
+                         bufferData->frameNumber);
+                releaseBuffer(bufferData->releaseCallbackId, bufferData->acquireFence);
+                // Because we just released a buffer, we know there's no need to wait for a free
+                // buffer.
+                mayNeedToWaitForBuffer = false;
             }
         }
 
-        while (maxBuffersAcquired(false /* includeExtraAcquire */)) {
-            BQA_LOGD("waiting for free buffer.");
-            mCallbackCV.wait(_lock);
+        if (mayNeedToWaitForBuffer) {
+            flushAndWaitForFreeBuffer(_lock);
         }
     }
 
@@ -625,12 +653,14 @@
     ATRACE_INT(mQueuedBufferTrace.c_str(),
                mNumFrameAvailable + mNumAcquired - mPendingRelease.size());
 
-    BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber,
-             boolToString(nextTransactionSet));
+    BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " syncTransactionSet=%s", item.mFrameNumber,
+             boolToString(syncTransactionSet));
 
-    if (nextTransactionSet) {
-        acquireNextBufferLocked(std::move(mNextTransaction));
-        mNextTransaction = nullptr;
+    if (syncTransactionSet) {
+        acquireNextBufferLocked(mSyncTransaction);
+        if (mAcquireSingleBuffer) {
+            mSyncTransaction = nullptr;
+        }
         mWaitForTransactionCallback = true;
     } else if (!mWaitForTransactionCallback) {
         acquireNextBufferLocked(std::nullopt);
@@ -652,9 +682,11 @@
     mDequeueTimestamps.erase(bufferId);
 };
 
-void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
+void BLASTBufferQueue::setSyncTransaction(SurfaceComposerClient::Transaction* t,
+                                          bool acquireSingleBuffer) {
     std::lock_guard _lock{mMutex};
-    mNextTransaction = t;
+    mSyncTransaction = t;
+    mAcquireSingleBuffer = mSyncTransaction ? acquireSingleBuffer : true;
 }
 
 bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 8edf604..a626970 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -71,6 +71,7 @@
         case HAL_PIXEL_FORMAT_Y8:
         case HAL_PIXEL_FORMAT_Y16:
         case HAL_PIXEL_FORMAT_RAW16:
+        case HAL_PIXEL_FORMAT_RAW12:
         case HAL_PIXEL_FORMAT_RAW10:
         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
         case HAL_PIXEL_FORMAT_BLOB:
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index c986b82..8379675 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -33,10 +33,13 @@
 // using just a few large reads.
 static const size_t EVENT_BUFFER_SIZE = 100;
 
+static constexpr nsecs_t WAITING_FOR_VSYNC_TIMEOUT = ms2ns(300);
+
 DisplayEventDispatcher::DisplayEventDispatcher(
         const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
         ISurfaceComposer::EventRegistrationFlags eventRegistration)
-      : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false) {
+      : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false),
+        mLastVsyncCount(0), mLastScheduleVsyncTime(0) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
@@ -86,6 +89,7 @@
         }
 
         mWaitingForVsync = true;
+        mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC);
     }
     return OK;
 }
@@ -124,9 +128,21 @@
               this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
               vsyncEventData.id);
         mWaitingForVsync = false;
+        mLastVsyncCount = vsyncCount;
         dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
     }
 
+    if (mWaitingForVsync) {
+        const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+        const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime;
+        if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) {
+            ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
+            mWaitingForVsync = false;
+            dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
+                          ++mLastVsyncCount, vsyncEventData /* empty data */);
+        }
+    }
+
     return 1; // keep the callback
 }
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2713be0..b139cf1 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -413,6 +413,14 @@
     return callback;
 }
 
+void TransactionCompletedListener::removeReleaseBufferCallback(
+        const ReleaseCallbackId& callbackId) {
+    {
+        std::scoped_lock<std::mutex> lock(mMutex);
+        popReleaseBufferCallbackLocked(callbackId);
+    }
+}
+
 // ---------------------------------------------------------------------------
 
 void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId);
@@ -1307,6 +1315,28 @@
     return *this;
 }
 
+std::optional<BufferData> SurfaceComposerClient::Transaction::getAndClearBuffer(
+        const sp<SurfaceControl>& sc) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        return std::nullopt;
+    }
+    if (!(s->what & layer_state_t::eBufferChanged)) {
+        return std::nullopt;
+    }
+
+    BufferData bufferData = s->bufferData;
+
+    TransactionCompletedListener::getInstance()->removeReleaseBufferCallback(
+            bufferData.releaseCallbackId);
+    BufferData emptyBufferData;
+    s->what &= ~layer_state_t::eBufferChanged;
+    s->bufferData = emptyBufferData;
+
+    mContainsBuffer = false;
+    return bufferData;
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
         const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
         const std::optional<sp<Fence>>& fence, const std::optional<uint64_t>& frameNumber,
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 3881620..d766173 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -88,13 +88,13 @@
     void onFrameDequeued(const uint64_t) override;
     void onFrameCancelled(const uint64_t) override;
 
-    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 transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+                                      const std::vector<SurfaceControlStats>& stats);
+    virtual void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+                                     const std::vector<SurfaceControlStats>& stats);
     void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
                                std::optional<uint32_t> currentMaxAcquiredBufferCount);
-    void setNextTransaction(SurfaceComposerClient::Transaction *t);
+    void setSyncTransaction(SurfaceComposerClient::Transaction* t, bool acquireSingleBuffer = true);
     void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
     void applyPendingTransactions(uint64_t frameNumber);
 
@@ -132,6 +132,9 @@
 
     void flushShadowQueue() REQUIRES(mMutex);
     void acquireAndReleaseBuffer() REQUIRES(mMutex);
+    void releaseBuffer(const ReleaseCallbackId& callbackId, const sp<Fence>& releaseFence)
+            REQUIRES(mMutex);
+    void flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock);
 
     std::string mName;
     // Represents the queued buffer count from buffer queue,
@@ -208,7 +211,7 @@
     sp<IGraphicBufferProducer> mProducer;
     sp<BLASTBufferItemConsumer> mBufferItemConsumer;
 
-    SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
+    SurfaceComposerClient::Transaction* mSyncTransaction GUARDED_BY(mMutex);
     std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>>
             mPendingTransactions GUARDED_BY(mMutex);
 
@@ -239,7 +242,11 @@
     std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex);
 
     uint32_t mCurrentMaxAcquiredBufferCount;
-    bool mWaitForTransactionCallback = false;
+    bool mWaitForTransactionCallback GUARDED_BY(mMutex) = false;
+
+    // Flag to determine if syncTransaction should only acquire a single buffer and then clear or
+    // continue to acquire buffers until explicitly cleared
+    bool mAcquireSingleBuffer GUARDED_BY(mMutex) = true;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 92c89b8..8a3a476 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -80,6 +80,8 @@
     sp<Looper> mLooper;
     DisplayEventReceiver mReceiver;
     bool mWaitingForVsync;
+    uint32_t mLastVsyncCount;
+    nsecs_t mLastScheduleVsyncTime;
 
     std::vector<FrameRateOverride> mFrameRateOverrides;
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e62c76e..e05c364 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -493,6 +493,7 @@
                                const std::optional<uint64_t>& frameNumber = std::nullopt,
                                const ReleaseCallbackId& id = ReleaseCallbackId::INVALID_ID,
                                ReleaseBufferCallback callback = nullptr);
+        std::optional<BufferData> getAndClearBuffer(const sp<SurfaceControl>& sc);
         Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
         Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
         Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
@@ -751,6 +752,8 @@
     void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence,
                          uint32_t currentMaxAcquiredBufferCount) override;
 
+    void removeReleaseBufferCallback(const ReleaseCallbackId& callbackId);
+
     // For Testing Only
     static void setInstance(const sp<TransactionCompletedListener>&);
 
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index b2d5048..48b8621 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -72,31 +72,30 @@
                          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);
-
+    void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
+                             const std::vector<SurfaceControlStats>& stats) override {
+        BLASTBufferQueue::transactionCallback(latchTime, presentFence, stats);
         uint64_t frameNumber = stats[0].frameEventStats.frameNumber;
 
         {
             std::unique_lock lock{frameNumberMutex};
-            mLastTransactionCommittedFrameNumber = frameNumber;
-            mCommittedCV.notify_all();
+            mLastTransactionFrameNumber = frameNumber;
+            mWaitForCallbackCV.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);
+        while (mLastTransactionFrameNumber < frameNumber) {
+            mWaitForCallbackCV.wait(lock);
         }
     }
 
 private:
     std::mutex frameNumberMutex;
-    std::condition_variable mCommittedCV;
-    int64_t mLastTransactionCommittedFrameNumber = -1;
+    std::condition_variable mWaitForCallbackCV;
+    int64_t mLastTransactionFrameNumber = -1;
 };
 
 class BLASTBufferQueueHelper {
@@ -110,15 +109,15 @@
         mBlastBufferQueueAdapter->update(sc, width, height, PIXEL_FORMAT_RGBA_8888);
     }
 
-    void setNextTransaction(Transaction* next) {
-        mBlastBufferQueueAdapter->setNextTransaction(next);
+    void setSyncTransaction(Transaction* next, bool acquireSingleBuffer = true) {
+        mBlastBufferQueueAdapter->setSyncTransaction(next, acquireSingleBuffer);
     }
 
     int getWidth() { return mBlastBufferQueueAdapter->mSize.width; }
 
     int getHeight() { return mBlastBufferQueueAdapter->mSize.height; }
 
-    Transaction* getNextTransaction() { return mBlastBufferQueueAdapter->mNextTransaction; }
+    Transaction* getSyncTransaction() { return mBlastBufferQueueAdapter->mSyncTransaction; }
 
     sp<IGraphicBufferProducer> getIGraphicBufferProducer() {
         return mBlastBufferQueueAdapter->getIGraphicBufferProducer();
@@ -144,6 +143,11 @@
         mBlastBufferQueueAdapter->waitForCallback(frameNumber);
     }
 
+    void validateNumFramesSubmitted(int64_t numFramesSubmitted) {
+        std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
+        ASSERT_EQ(numFramesSubmitted, mBlastBufferQueueAdapter->mSubmitted.size());
+    }
+
 private:
     sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
 };
@@ -299,7 +303,7 @@
         auto ret = igbp->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
                                        PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
                                        nullptr, nullptr);
-        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+        ASSERT_TRUE(ret == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION || ret == NO_ERROR);
         ASSERT_EQ(OK, igbp->requestBuffer(slot, &buf));
 
         uint32_t* bufData;
@@ -338,7 +342,7 @@
     ASSERT_EQ(mSurfaceControl, adapter.getSurfaceControl());
     ASSERT_EQ(mDisplayWidth, adapter.getWidth());
     ASSERT_EQ(mDisplayHeight, adapter.getHeight());
-    ASSERT_EQ(nullptr, adapter.getNextTransaction());
+    ASSERT_EQ(nullptr, adapter.getSyncTransaction());
 }
 
 TEST_F(BLASTBufferQueueTest, Update) {
@@ -359,11 +363,11 @@
     ASSERT_EQ(mDisplayHeight / 2, height);
 }
 
-TEST_F(BLASTBufferQueueTest, SetNextTransaction) {
+TEST_F(BLASTBufferQueueTest, SetSyncTransaction) {
     BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
-    Transaction next;
-    adapter.setNextTransaction(&next);
-    ASSERT_EQ(&next, adapter.getNextTransaction());
+    Transaction sync;
+    adapter.setSyncTransaction(&sync);
+    ASSERT_EQ(&sync, adapter.getSyncTransaction());
 }
 
 TEST_F(BLASTBufferQueueTest, DISABLED_onFrameAvailable_ApplyDesiredPresentTime) {
@@ -802,8 +806,8 @@
     sp<IGraphicBufferProducer> igbProducer;
     setUpProducer(adapter, igbProducer);
 
-    Transaction next;
-    adapter.setNextTransaction(&next);
+    Transaction sync;
+    adapter.setSyncTransaction(&sync);
     queueBuffer(igbProducer, 0, 255, 0, 0);
 
     // queue non sync buffer, so this one should get blocked
@@ -812,14 +816,14 @@
     queueBuffer(igbProducer, r, g, b, presentTimeDelay);
 
     CallbackHelper transactionCallback;
-    next.addTransactionCompletedCallback(transactionCallback.function,
+    sync.addTransactionCompletedCallback(transactionCallback.function,
                                          transactionCallback.getContext())
             .apply();
 
     CallbackData callbackData;
     transactionCallback.getCallbackData(&callbackData);
 
-    // capture screen and verify that it is red
+    // capture screen and verify that it is green
     ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
     ASSERT_NO_FATAL_FAILURE(
             checkScreenCapture(0, 255, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
@@ -842,16 +846,16 @@
 
     Transaction mainTransaction;
 
-    Transaction next;
-    adapter.setNextTransaction(&next);
+    Transaction sync;
+    adapter.setSyncTransaction(&sync);
     queueBuffer(igbProducer, 0, 255, 0, 0);
 
-    mainTransaction.merge(std::move(next));
+    mainTransaction.merge(std::move(sync));
 
-    adapter.setNextTransaction(&next);
+    adapter.setSyncTransaction(&sync);
     queueBuffer(igbProducer, r, g, b, 0);
 
-    mainTransaction.merge(std::move(next));
+    mainTransaction.merge(std::move(sync));
     // Expect 1 buffer to be released even before sending to SurfaceFlinger
     mProducerListener->waitOnNumberReleased(1);
 
@@ -882,24 +886,24 @@
 
     Transaction mainTransaction;
 
-    Transaction next;
+    Transaction sync;
     // queue a sync transaction
-    adapter.setNextTransaction(&next);
+    adapter.setSyncTransaction(&sync);
     queueBuffer(igbProducer, 0, 255, 0, 0);
 
-    mainTransaction.merge(std::move(next));
+    mainTransaction.merge(std::move(sync));
 
-    // queue another buffer without setting next transaction
+    // queue another buffer without setting sync transaction
     queueBuffer(igbProducer, 0, 0, 255, 0);
 
     // queue another sync transaction
-    adapter.setNextTransaction(&next);
+    adapter.setSyncTransaction(&sync);
     queueBuffer(igbProducer, r, g, b, 0);
     // Expect 1 buffer to be released because the non sync transaction should merge
     // with the sync
     mProducerListener->waitOnNumberReleased(1);
 
-    mainTransaction.merge(std::move(next));
+    mainTransaction.merge(std::move(sync));
     // Expect 2 buffers to be released due to merging the two syncs.
     mProducerListener->waitOnNumberReleased(2);
 
@@ -930,26 +934,26 @@
 
     Transaction mainTransaction;
 
-    Transaction next;
+    Transaction sync;
     // queue a sync transaction
-    adapter.setNextTransaction(&next);
+    adapter.setSyncTransaction(&sync);
     queueBuffer(igbProducer, 0, 255, 0, 0);
 
-    mainTransaction.merge(std::move(next));
+    mainTransaction.merge(std::move(sync));
 
-    // queue a few buffers without setting next transaction
+    // queue a few buffers without setting sync transaction
     queueBuffer(igbProducer, 0, 0, 255, 0);
     queueBuffer(igbProducer, 0, 0, 255, 0);
     queueBuffer(igbProducer, 0, 0, 255, 0);
 
     // queue another sync transaction
-    adapter.setNextTransaction(&next);
+    adapter.setSyncTransaction(&sync);
     queueBuffer(igbProducer, r, g, b, 0);
     // Expect 3 buffers to be released because the non sync transactions should merge
     // with the sync
     mProducerListener->waitOnNumberReleased(3);
 
-    mainTransaction.merge(std::move(next));
+    mainTransaction.merge(std::move(sync));
     // Expect 4 buffers to be released due to merging the two syncs.
     mProducerListener->waitOnNumberReleased(4);
 
@@ -987,14 +991,14 @@
     // Send a buffer to SF
     queueBuffer(igbProducer, 0, 255, 0, 0);
 
-    Transaction next;
+    Transaction sync;
     // queue a sync transaction
-    adapter.setNextTransaction(&next);
+    adapter.setSyncTransaction(&sync);
     queueBuffer(igbProducer, 0, 255, 0, 0);
 
-    mainTransaction.merge(std::move(next));
+    mainTransaction.merge(std::move(sync));
 
-    // queue a few buffers without setting next transaction
+    // queue a few buffers without setting sync transaction
     queueBuffer(igbProducer, 0, 0, 255, 0);
     queueBuffer(igbProducer, 0, 0, 255, 0);
     queueBuffer(igbProducer, 0, 0, 255, 0);
@@ -1003,13 +1007,13 @@
     mainTransaction.apply();
 
     // queue another sync transaction
-    adapter.setNextTransaction(&next);
+    adapter.setSyncTransaction(&sync);
     queueBuffer(igbProducer, r, g, b, 0);
     // Expect 2 buffers to be released because the non sync transactions should merge
     // with the sync
     mProducerListener->waitOnNumberReleased(3);
 
-    mainTransaction.merge(std::move(next));
+    mainTransaction.merge(std::move(sync));
 
     CallbackHelper transactionCallback;
     mainTransaction
@@ -1026,6 +1030,45 @@
             checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
 }
 
+TEST_F(BLASTBufferQueueTest, SetSyncTransactionAcquireMultipleBuffers) {
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+    sp<IGraphicBufferProducer> igbProducer;
+    setUpProducer(adapter, igbProducer);
+
+    Transaction next;
+    adapter.setSyncTransaction(&next, false);
+    queueBuffer(igbProducer, 0, 255, 0, 0);
+    queueBuffer(igbProducer, 0, 0, 255, 0);
+    // There should only be one frame submitted since the first frame will be released.
+    adapter.validateNumFramesSubmitted(1);
+    adapter.setSyncTransaction(nullptr);
+
+    // queue non sync buffer, so this one should get blocked
+    // Add a present delay to allow the first screenshot to get taken.
+    nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+    queueBuffer(igbProducer, 255, 0, 0, presentTimeDelay);
+
+    CallbackHelper transactionCallback;
+    next.addTransactionCompletedCallback(transactionCallback.function,
+                                         transactionCallback.getContext())
+            .apply();
+
+    CallbackData callbackData;
+    transactionCallback.getCallbackData(&callbackData);
+
+    // capture screen and verify that it is blue
+    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+    ASSERT_NO_FATAL_FAILURE(
+            checkScreenCapture(0, 0, 255, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+
+    mProducerListener->waitOnNumberReleased(2);
+    // capture screen and verify that it is red
+    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+    ASSERT_NO_FATAL_FAILURE(
+            checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
 class TestProducerListener : public BnProducerListener {
 public:
     sp<IGraphicBufferProducer> mIgbp;
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index a1d75d5..8974b22 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -859,17 +859,15 @@
 
 // --- FocusEvent ---
 
-void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) {
+void FocusEvent::initialize(int32_t id, bool hasFocus) {
     InputEvent::initialize(id, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN,
                            ADISPLAY_ID_NONE, INVALID_HMAC);
     mHasFocus = hasFocus;
-    mInTouchMode = inTouchMode;
 }
 
 void FocusEvent::initialize(const FocusEvent& from) {
     InputEvent::initialize(from);
     mHasFocus = from.mHasFocus;
-    mInTouchMode = from.mInTouchMode;
 }
 
 // --- CaptureEvent ---
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 02a5a08..a065ce2 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -278,7 +278,6 @@
         case InputMessage::Type::FOCUS: {
             msg->body.focus.eventId = body.focus.eventId;
             msg->body.focus.hasFocus = body.focus.hasFocus;
-            msg->body.focus.inTouchMode = body.focus.inTouchMode;
             break;
         }
         case InputMessage::Type::CAPTURE: {
@@ -622,13 +621,10 @@
     return mChannel->sendMessage(&msg);
 }
 
-status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus,
-                                           bool inTouchMode) {
+status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus) {
     if (ATRACE_ENABLED()) {
-        std::string message =
-                StringPrintf("publishFocusEvent(inputChannel=%s, hasFocus=%s, inTouchMode=%s)",
-                             mChannel->getName().c_str(), toString(hasFocus),
-                             toString(inTouchMode));
+        std::string message = StringPrintf("publishFocusEvent(inputChannel=%s, hasFocus=%s)",
+                                           mChannel->getName().c_str(), toString(hasFocus));
         ATRACE_NAME(message.c_str());
     }
 
@@ -637,7 +633,6 @@
     msg.header.seq = seq;
     msg.body.focus.eventId = eventId;
     msg.body.focus.hasFocus = hasFocus;
-    msg.body.focus.inTouchMode = inTouchMode;
     return mChannel->sendMessage(&msg);
 }
 
@@ -1371,8 +1366,7 @@
 }
 
 void InputConsumer::initializeFocusEvent(FocusEvent* event, const InputMessage* msg) {
-    event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus,
-                      msg->body.focus.inTouchMode);
+    event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus);
 }
 
 void InputConsumer::initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg) {
@@ -1491,9 +1485,8 @@
                     break;
                 }
                 case InputMessage::Type::FOCUS: {
-                    out += android::base::StringPrintf("hasFocus=%s inTouchMode=%s",
-                                                       toString(msg.body.focus.hasFocus),
-                                                       toString(msg.body.focus.inTouchMode));
+                    out += android::base::StringPrintf("hasFocus=%s",
+                                                       toString(msg.body.focus.hasFocus));
                     break;
                 }
                 case InputMessage::Type::CAPTURE: {
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 973194c..05bc0bc 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -290,10 +290,9 @@
     constexpr uint32_t seq = 15;
     int32_t eventId = InputEvent::nextId();
     constexpr bool hasFocus = true;
-    constexpr bool inTouchMode = true;
     const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    status = mPublisher->publishFocusEvent(seq, eventId, hasFocus, inTouchMode);
+    status = mPublisher->publishFocusEvent(seq, eventId, hasFocus);
     ASSERT_EQ(OK, status) << "publisher publishFocusEvent should return OK";
 
     uint32_t consumeSeq;
@@ -309,7 +308,6 @@
     EXPECT_EQ(seq, consumeSeq);
     EXPECT_EQ(eventId, focusEvent->getId());
     EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
-    EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode());
 
     status = mConsumer->sendFinishedSignal(seq, true);
     ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK";
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 2f88704..b6a9476 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -84,8 +84,7 @@
 
   CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0);
   CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4);
-  CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 5);
-  CHECK_OFFSET(InputMessage::Body::Focus, empty, 6);
+  CHECK_OFFSET(InputMessage::Body::Focus, empty, 5);
 
   CHECK_OFFSET(InputMessage::Body::Capture, eventId, 0);
   CHECK_OFFSET(InputMessage::Body::Capture, pointerCaptureEnabled, 4);
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 93e7239..c447d31 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -162,6 +162,8 @@
     static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB));
     static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
     static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ));
+    static_assert(static_cast<int>(ADATASPACE_BT2020_ITU_PQ) ==
+        static_cast<int>(HAL_DATASPACE_BT2020_ITU_PQ));
     static_assert(static_cast<int>(ADATASPACE_ADOBE_RGB) == static_cast<int>(HAL_DATASPACE_ADOBE_RGB));
     static_assert(static_cast<int>(ADATASPACE_JFIF) == static_cast<int>(HAL_DATASPACE_V0_JFIF));
     static_assert(static_cast<int>(ADATASPACE_BT601_625) == static_cast<int>(HAL_DATASPACE_V0_BT601_625));
@@ -170,6 +172,10 @@
     static_assert(static_cast<int>(ADATASPACE_BT709) == static_cast<int>(HAL_DATASPACE_V0_BT709));
     static_assert(static_cast<int>(ADATASPACE_DCI_P3) == static_cast<int>(HAL_DATASPACE_DCI_P3));
     static_assert(static_cast<int>(ADATASPACE_SRGB_LINEAR) == static_cast<int>(HAL_DATASPACE_V0_SRGB_LINEAR));
+    static_assert(static_cast<int>(ADATASPACE_BT2020_HLG) ==
+        static_cast<int>(HAL_DATASPACE_BT2020_HLG));
+    static_assert(static_cast<int>(ADATASPACE_BT2020_ITU_HLG) ==
+        static_cast<int>(HAL_DATASPACE_BT2020_ITU_HLG));
 
     if (!window || !query(window, NATIVE_WINDOW_IS_VALID) ||
             !isDataSpaceValid(window, dataSpace)) {
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 0565f42..30ac220 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -444,6 +444,15 @@
     ADATASPACE_BT2020_PQ = 163971072, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
 
     /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     */
+    ADATASPACE_BT2020_ITU_PQ = 298188800,  // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED
+
+    /**
      * Adobe RGB
      *
      * Use full range, gamma 2.2 transfer and Adobe RGB primaries
@@ -519,6 +528,20 @@
      * components.
      */
     ADATASPACE_SRGB_LINEAR = 138477568, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
+
+    /**
+     * Hybrid Log Gamma encoding:
+     *
+     * Use full range, hybrid log gamma transfer and BT2020 standard.
+     */
+    ADATASPACE_BT2020_HLG = 168165376, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL
+
+    /**
+     * ITU Hybrid Log Gamma encoding:
+     *
+     * Use limited range, hybrid log gamma transfer and BT2020 standard.
+     */
+    ADATASPACE_BT2020_ITU_HLG = 302383104 // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
 };
 
 __END_DECLS
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index a62d2b9..ecfaef8 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -40,6 +40,10 @@
         "libui",
         "libutils",
     ],
+
+    static_libs: [
+        "libtonemap",
+    ],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
 }
@@ -97,7 +101,7 @@
         "skia/filters/GaussianBlurFilter.cpp",
         "skia/filters/KawaseBlurFilter.cpp",
         "skia/filters/LinearEffect.cpp",
-        "skia/filters/StretchShaderFactory.cpp"
+        "skia/filters/StretchShaderFactory.cpp",
     ],
 }
 
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index a9ea690..65d4895 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -26,55 +26,39 @@
 namespace android {
 namespace renderengine {
 
-std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
-    RenderEngineType renderEngineType = args.renderEngineType;
-
+std::unique_ptr<RenderEngine> RenderEngine::create(RenderEngineCreationArgs args) {
     // Keep the ability to override by PROPERTIES:
     char prop[PROPERTY_VALUE_MAX];
     property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "");
     if (strcmp(prop, "gles") == 0) {
-        renderEngineType = RenderEngineType::GLES;
+        args.renderEngineType = RenderEngineType::GLES;
     }
     if (strcmp(prop, "threaded") == 0) {
-        renderEngineType = RenderEngineType::THREADED;
+        args.renderEngineType = RenderEngineType::THREADED;
     }
     if (strcmp(prop, "skiagl") == 0) {
-        renderEngineType = RenderEngineType::SKIA_GL;
+        args.renderEngineType = RenderEngineType::SKIA_GL;
     }
     if (strcmp(prop, "skiaglthreaded") == 0) {
-        renderEngineType = RenderEngineType::SKIA_GL_THREADED;
+        args.renderEngineType = RenderEngineType::SKIA_GL_THREADED;
     }
 
-    switch (renderEngineType) {
+    switch (args.renderEngineType) {
         case RenderEngineType::THREADED:
             ALOGD("Threaded RenderEngine with GLES Backend");
             return renderengine::threaded::RenderEngineThreaded::create(
                     [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); },
-                    renderEngineType);
+                    args.renderEngineType);
         case RenderEngineType::SKIA_GL:
             ALOGD("RenderEngine with SkiaGL Backend");
             return renderengine::skia::SkiaGLRenderEngine::create(args);
         case RenderEngineType::SKIA_GL_THREADED: {
-            // These need to be recreated, since they are a constant reference, and we need to
-            // let SkiaRE know that it's running as threaded, and all GL operation will happen on
-            // the same thread.
-            RenderEngineCreationArgs skiaArgs =
-                    RenderEngineCreationArgs::Builder()
-                            .setPixelFormat(args.pixelFormat)
-                            .setImageCacheSize(args.imageCacheSize)
-                            .setUseColorManagerment(args.useColorManagement)
-                            .setEnableProtectedContext(args.enableProtectedContext)
-                            .setPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly)
-                            .setSupportsBackgroundBlur(args.supportsBackgroundBlur)
-                            .setContextPriority(args.contextPriority)
-                            .setRenderEngineType(renderEngineType)
-                            .build();
             ALOGD("Threaded RenderEngine with SkiaGL Backend");
             return renderengine::threaded::RenderEngineThreaded::create(
-                    [skiaArgs]() {
-                        return android::renderengine::skia::SkiaGLRenderEngine::create(skiaArgs);
+                    [args]() {
+                        return android::renderengine::skia::SkiaGLRenderEngine::create(args);
                     },
-                    renderEngineType);
+                    args.renderEngineType);
         }
         case RenderEngineType::GLES:
         default:
diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp
index 5968399..baa5054 100644
--- a/libs/renderengine/benchmark/Android.bp
+++ b/libs/renderengine/benchmark/Android.bp
@@ -23,7 +23,10 @@
 
 cc_benchmark {
     name: "librenderengine_bench",
-    defaults: ["skia_deps", "surfaceflinger_defaults"],
+    defaults: [
+        "skia_deps",
+        "surfaceflinger_defaults",
+    ],
     srcs: [
         "main.cpp",
         "Codec.cpp",
@@ -32,6 +35,7 @@
     ],
     static_libs: [
         "librenderengine",
+        "libtonemap",
     ],
     cflags: [
         "-DLOG_TAG=\"RenderEngineBench\"",
@@ -50,5 +54,5 @@
         "libutils",
     ],
 
-    data: [ "resources/*"],
+    data: ["resources/*"],
 }
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index 9ee7e4d..6c8f8e8 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -46,8 +46,8 @@
 }
 
 /**
- * Passed (indirectly - see RunSkiaGL) to Benchmark::Apply to create a Benchmark
- * which specifies which RenderEngineType it uses.
+ * Passed (indirectly - see RunSkiaGLThreaded) to Benchmark::Apply to create a
+ * Benchmark which specifies which RenderEngineType it uses.
  *
  * This simplifies calling ->Arg(type)->Arg(type) and provides strings to make
  * it obvious which version is being run.
@@ -62,10 +62,10 @@
 }
 
 /**
- * Run a benchmark once using SKIA_GL.
+ * Run a benchmark once using SKIA_GL_THREADED.
  */
-static void RunSkiaGL(benchmark::internal::Benchmark* b) {
-    AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL);
+static void RunSkiaGLThreaded(benchmark::internal::Benchmark* b) {
+    AddRenderEngineType(b, RenderEngine::RenderEngineType::SKIA_GL_THREADED);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -256,4 +256,4 @@
     benchDrawLayers(*re, layers, benchState, "blurred");
 }
 
-BENCHMARK(BM_blur)->Apply(RunSkiaGL);
+BENCHMARK(BM_blur)->Apply(RunSkiaGLThreaded);
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index b9cc648..6b85c57 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -99,7 +99,7 @@
         SKIA_GL_THREADED = 4,
     };
 
-    static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
+    static std::unique_ptr<RenderEngine> create(RenderEngineCreationArgs args);
 
     virtual ~RenderEngine() = 0;
 
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 73dadef..c3a5a60 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -19,6 +19,7 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <SkString.h>
+#include <tonemap/tonemap.h>
 #include <utils/Trace.h>
 
 #include <optional>
@@ -32,6 +33,11 @@
 namespace renderengine {
 namespace skia {
 
+static aidl::android::hardware::graphics::common::Dataspace toAidlDataspace(
+        ui::Dataspace dataspace) {
+    return static_cast<aidl::android::hardware::graphics::common::Dataspace>(dataspace);
+}
+
 static void generateEOTF(ui::Dataspace dataspace, SkString& shader) {
     switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
         case HAL_DATASPACE_TRANSFER_ST2084:
@@ -108,7 +114,8 @@
 }
 
 // Conversion from relative light to absolute light (maps from [0, 1] to [0, maxNits])
-static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, SkString& shader) {
+static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace,
+                                           ui::Dataspace outputDataspace, SkString& shader) {
     switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
         case HAL_DATASPACE_TRANSFER_ST2084:
             shader.append(R"(
@@ -125,158 +132,26 @@
                 )");
             break;
         default:
-            shader.append(R"(
-                    float3 ScaleLuminance(float3 xyz) {
-                        return xyz * in_inputMaxLuminance;
-                    }
-                )");
-            break;
-    }
-}
-
-static void generateToneMapInterpolation(ui::Dataspace inputDataspace,
-                                         ui::Dataspace outputDataspace, SkString& shader) {
-    switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
-        case HAL_DATASPACE_TRANSFER_ST2084:
-        case HAL_DATASPACE_TRANSFER_HLG:
             switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
                 case HAL_DATASPACE_TRANSFER_ST2084:
-                    shader.append(R"(
-                            float3 ToneMap(float3 xyz) {
-                                return xyz;
-                            }
-                        )");
-                    break;
                 case HAL_DATASPACE_TRANSFER_HLG:
-                    // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
-                    // we'll clamp the luminance range in case we're mapping from PQ input to HLG
-                    // output.
+                    // SDR -> HDR tonemap
                     shader.append(R"(
-                            float3 ToneMap(float3 xyz) {
-                                return clamp(xyz, 0.0, 1000.0);
+                            float3 ScaleLuminance(float3 xyz) {
+                                return xyz * in_libtonemap_inputMaxLuminance;
                             }
                         )");
                     break;
                 default:
-                    // Here we're mapping from HDR to SDR content, so interpolate using a Hermitian
-                    // polynomial onto the smaller luminance range.
+                    // Input and output are both SDR, so no tone-mapping is expected so
+                    // no-op the luminance normalization.
                     shader.append(R"(
-                            float3 ToneMap(float3 xyz) {
-                                float maxInLumi = in_inputMaxLuminance;
-                                float maxOutLumi = in_displayMaxLuminance;
-
-                                float nits = xyz.y;
-
-                                // if the max input luminance is less than what we can output then
-                                // no tone mapping is needed as all color values will be in range.
-                                if (maxInLumi <= maxOutLumi) {
-                                    return xyz;
-                                } else {
-
-                                    // three control points
-                                    const float x0 = 10.0;
-                                    const float y0 = 17.0;
-                                    float x1 = maxOutLumi * 0.75;
-                                    float y1 = x1;
-                                    float x2 = x1 + (maxInLumi - x1) / 2.0;
-                                    float y2 = y1 + (maxOutLumi - y1) * 0.75;
-
-                                    // horizontal distances between the last three control points
-                                    float h12 = x2 - x1;
-                                    float h23 = maxInLumi - x2;
-                                    // tangents at the last three control points
-                                    float m1 = (y2 - y1) / h12;
-                                    float m3 = (maxOutLumi - y2) / h23;
-                                    float m2 = (m1 + m3) / 2.0;
-
-                                    if (nits < x0) {
-                                        // scale [0.0, x0] to [0.0, y0] linearly
-                                        float slope = y0 / x0;
-                                        return xyz * slope;
-                                    } else if (nits < x1) {
-                                        // scale [x0, x1] to [y0, y1] linearly
-                                        float slope = (y1 - y0) / (x1 - x0);
-                                        nits = y0 + (nits - x0) * slope;
-                                    } else if (nits < x2) {
-                                        // scale [x1, x2] to [y1, y2] using Hermite interp
-                                        float t = (nits - x1) / h12;
-                                        nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
-                                                (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
-                                    } else {
-                                        // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
-                                        float t = (nits - x2) / h23;
-                                        nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
-                                                (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
-                                    }
+                                float3 ScaleLuminance(float3 xyz) {
+                                    return xyz * in_libtonemap_displayMaxLuminance;
                                 }
-
-                                // color.y is greater than x0 and is thus non-zero
-                                return xyz * (nits / xyz.y);
-                            }
-                        )");
+                            )");
                     break;
             }
-            break;
-        default:
-            switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
-                case HAL_DATASPACE_TRANSFER_ST2084:
-                case HAL_DATASPACE_TRANSFER_HLG:
-                    // Map from SDR onto an HDR output buffer
-                    // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto
-                    // [0, maxOutLumi] which is hard-coded to be 3000 nits.
-                    shader.append(R"(
-                            float3 ToneMap(float3 xyz) {
-                                const float maxOutLumi = 3000.0;
-
-                                const float x0 = 5.0;
-                                const float y0 = 2.5;
-                                float x1 = in_displayMaxLuminance * 0.7;
-                                float y1 = maxOutLumi * 0.15;
-                                float x2 = in_displayMaxLuminance * 0.9;
-                                float y2 = maxOutLumi * 0.45;
-                                float x3 = in_displayMaxLuminance;
-                                float y3 = maxOutLumi;
-
-                                float c1 = y1 / 3.0;
-                                float c2 = y2 / 2.0;
-                                float c3 = y3 / 1.5;
-
-                                float nits = xyz.y;
-
-                                if (nits <= x0) {
-                                    // scale [0.0, x0] to [0.0, y0] linearly
-                                    float slope = y0 / x0;
-                                    return xyz * slope;
-                                } else if (nits <= x1) {
-                                    // scale [x0, x1] to [y0, y1] using a curve
-                                    float t = (nits - x0) / (x1 - x0);
-                                    nits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + t * t * y1;
-                                } else if (nits <= x2) {
-                                    // scale [x1, x2] to [y1, y2] using a curve
-                                    float t = (nits - x1) / (x2 - x1);
-                                    nits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + t * t * y2;
-                                } else {
-                                    // scale [x2, x3] to [y2, y3] using a curve
-                                    float t = (nits - x2) / (x3 - x2);
-                                    nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3;
-                                }
-
-                                // xyz.y is greater than x0 and is thus non-zero
-                                return xyz * (nits / xyz.y);
-                            }
-                        )");
-                    break;
-                default:
-                    // For completeness, this is tone-mapping from SDR to SDR, where this is just a
-                    // no-op.
-                    shader.append(R"(
-                            float3 ToneMap(float3 xyz) {
-                                return xyz;
-                            }
-                        )");
-                    break;
-            }
-            break;
     }
 }
 
@@ -300,7 +175,7 @@
         default:
             shader.append(R"(
                     float3 NormalizeLuminance(float3 xyz) {
-                        return xyz / in_displayMaxLuminance;
+                        return xyz / in_libtonemap_displayMaxLuminance;
                     }
                 )");
             break;
@@ -309,19 +184,22 @@
 
 static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
                          SkString& shader) {
-    // Input uniforms
-    shader.append(R"(
-            uniform float in_displayMaxLuminance;
-            uniform float in_inputMaxLuminance;
-        )");
+    shader.append(tonemap::getToneMapper()
+                          ->generateTonemapGainShaderSkSL(toAidlDataspace(inputDataspace),
+                                                          toAidlDataspace(outputDataspace))
+                          .c_str());
 
-    generateLuminanceScalesForOOTF(inputDataspace, shader);
-    generateToneMapInterpolation(inputDataspace, outputDataspace, shader);
+    generateLuminanceScalesForOOTF(inputDataspace, outputDataspace, shader);
     generateLuminanceNormalizationForOOTF(outputDataspace, shader);
 
     shader.append(R"(
-            float3 OOTF(float3 xyz) {
-                return NormalizeLuminance(ToneMap(ScaleLuminance(xyz)));
+            float3 OOTF(float3 linearRGB, float3 xyz) {
+                float3 scaledLinearRGB = ScaleLuminance(linearRGB);
+                float3 scaledXYZ = ScaleLuminance(xyz);
+
+                float gain = libtonemap_LookupTonemapGain(scaledLinearRGB, scaledXYZ);
+
+                return NormalizeLuminance(scaledXYZ * gain);
             }
         )");
 }
@@ -399,7 +277,9 @@
         )");
     }
     shader.append(R"(
-        c.rgb = OETF(ToRGB(OOTF(ToXYZ(EOTF(c.rgb)))));
+        float3 linearRGB = EOTF(c.rgb);
+        float3 xyz = ToXYZ(linearRGB);
+        c.rgb = OETF(ToRGB(OOTF(linearRGB, xyz)));
     )");
     if (undoPremultipliedAlpha) {
         shader.append(R"(
@@ -465,11 +345,20 @@
                 colorTransform * mat4(outputColorSpace.getXYZtoRGB());
     }
 
-    effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance;
-    // If the input luminance is unknown, use display luminance (aka, no-op any luminance changes)
-    // This will be the case for eg screenshots in addition to uncalibrated displays
-    effectBuilder.uniform("in_inputMaxLuminance") =
-            maxLuminance > 0 ? maxLuminance : maxDisplayLuminance;
+    tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance,
+                               // If the input luminance is unknown, use display luminance (aka,
+                               // no-op any luminance changes)
+                               // This will be the case for eg screenshots in addition to
+                               // uncalibrated displays
+                               .contentMaxLuminance =
+                                       maxLuminance > 0 ? maxLuminance : maxDisplayLuminance};
+
+    const auto uniforms = tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata);
+
+    for (const auto& uniform : uniforms) {
+        effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
+    }
+
     return effectBuilder.makeShader(nullptr, false);
 }
 
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index d0e19dd..52b6c8f 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -23,7 +23,10 @@
 
 cc_test {
     name: "librenderengine_test",
-    defaults: ["skia_deps", "surfaceflinger_defaults"],
+    defaults: [
+        "skia_deps",
+        "surfaceflinger_defaults",
+    ],
     test_suites: ["device-tests"],
     srcs: [
         "RenderEngineTest.cpp",
@@ -36,6 +39,7 @@
         "libgmock",
         "librenderengine",
         "librenderengine_mocks",
+        "libtonemap",
     ],
 
     shared_libs: [
diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp
new file mode 100644
index 0000000..231a342
--- /dev/null
+++ b/libs/tonemap/Android.bp
@@ -0,0 +1,37 @@
+// 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_static {
+    name: "libtonemap",
+    vendor_available: true,
+
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+
+    shared_libs: [
+        "android.hardware.graphics.common-V3-ndk",
+    ],
+    srcs: [
+        "tonemap.cpp",
+    ],
+}
diff --git a/libs/tonemap/OWNERS b/libs/tonemap/OWNERS
new file mode 100644
index 0000000..6d91da3
--- /dev/null
+++ b/libs/tonemap/OWNERS
@@ -0,0 +1,4 @@
+alecmouri@google.com
+jreck@google.com
+sallyqi@google.com
+scroggo@google.com
\ No newline at end of file
diff --git a/libs/tonemap/TEST_MAPPING b/libs/tonemap/TEST_MAPPING
new file mode 100644
index 0000000..00f83ba
--- /dev/null
+++ b/libs/tonemap/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+      "name": "librenderengine_test"
+    },
+    {
+      "name": "libtonemap_test"
+    }
+  ]
+}
diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h
new file mode 100644
index 0000000..d350e16
--- /dev/null
+++ b/libs/tonemap/include/tonemap/tonemap.h
@@ -0,0 +1,103 @@
+/*
+ * 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 <aidl/android/hardware/graphics/common/Dataspace.h>
+
+#include <string>
+#include <vector>
+
+namespace android::tonemap {
+
+// Describes a shader uniform
+// The shader uniform is intended to be passed into a SkRuntimeShaderBuilder, i.e.:
+//
+// SkRuntimeShaderBuilder builder;
+// builder.uniform(<uniform name>).set(<uniform value>.data(), <uniform value>.size());
+struct ShaderUniform {
+    // The name of the uniform, used for binding into a shader.
+    // The shader must contain a uniform whose name matches this.
+    std::string name;
+
+    // The value for the uniform, which should be bound to the uniform identified by <name>
+    std::vector<uint8_t> value;
+};
+
+// Describes metadata which may be used for constructing the shader uniforms.
+// This metadata should not be used for manipulating the source code of the shader program directly,
+// as otherwise caching by other system of these shaders may break.
+struct Metadata {
+    float displayMaxLuminance = 0.0;
+    float contentMaxLuminance = 0.0;
+};
+
+class ToneMapper {
+public:
+    virtual ~ToneMapper() {}
+    // Constructs a tonemap shader whose shader language is SkSL
+    //
+    // The returned shader string *must* contain a function with the following signature:
+    // float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz);
+    //
+    // The arguments are:
+    // * linearRGB is the absolute nits of the RGB pixels in linear space
+    // * xyz is linearRGB converted into XYZ
+    //
+    // libtonemap_LookupTonemapGain() returns a float representing the amount by which to scale the
+    // absolute nits of the pixels. This function may be plugged into any existing SkSL shader, and
+    // is expected to look something like this:
+    //
+    // vec3 rgb = ...;
+    // // apply the EOTF based on the incoming dataspace to convert to linear nits.
+    // vec3 linearRGB = applyEOTF(rgb);
+    // // apply a RGB->XYZ matrix float3
+    // vec3 xyz = toXYZ(linearRGB);
+    // // Scale the luminance based on the content standard
+    // vec3 absoluteRGB = ScaleLuminance(linearRGB);
+    // vec3 absoluteXYZ = ScaleLuminance(xyz);
+    // float gain = libtonemap_LookupTonemapGain(absoluteRGB, absoluteXYZ);
+    // // Normalize the luminance back down to a [0, 1] range
+    // xyz = NormalizeLuminance(absoluteXYZ * gain);
+    // // apply a XYZ->RGB matrix and apply the output OETf.
+    // vec3 finalColor = applyOETF(ToRGB(xyz));
+    // ...
+    //
+    // Helper methods in this shader should be prefixed with "libtonemap_". Accordingly, libraries
+    // which consume this shader must *not* contain any methods prefixed with "libtonemap_" to
+    // guarantee that there are no conflicts in name resolution.
+    virtual std::string generateTonemapGainShaderSkSL(
+            aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
+            aidl::android::hardware::graphics::common::Dataspace destinationDataspace) = 0;
+
+    // Constructs uniform descriptions that correspond to those that are generated for the tonemap
+    // shader. Uniforms must be prefixed with "in_libtonemap_". Libraries which consume this shader
+    // must not bind any new uniforms that begin with this prefix.
+    //
+    // Downstream shaders may assume the existence of the uniform in_libtonemap_displayMaxLuminance
+    // and in_libtonemap_inputMaxLuminance, in order to assist with scaling and normalizing
+    // luminance as described in the documentation for generateTonemapGainShaderSkSL(). That is,
+    // shaders plugging in a tone-mapping shader returned by generateTonemapGainShaderSkSL() may
+    // assume that there are predefined floats in_libtonemap_displayMaxLuminance and
+    // in_libtonemap_inputMaxLuminance inside of the body of the tone-mapping shader.
+    virtual std::vector<ShaderUniform> generateShaderSkSLUniforms(const Metadata& metadata) = 0;
+};
+
+// Retrieves a tonemapper instance.
+// This instance is globally constructed.
+ToneMapper* getToneMapper();
+
+} // namespace android::tonemap
\ No newline at end of file
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
new file mode 100644
index 0000000..e58d519
--- /dev/null
+++ b/libs/tonemap/tests/Android.bp
@@ -0,0 +1,38 @@
+// 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.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_test {
+    name: "libtonemap_test",
+    test_suites: ["device-tests"],
+    srcs: [
+        "tonemap_test.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.common-V3-ndk",
+    ],
+    static_libs: [
+        "libgmock",
+        "libgtest",
+        "libtonemap",
+    ],
+}
diff --git a/libs/tonemap/tests/tonemap_test.cpp b/libs/tonemap/tests/tonemap_test.cpp
new file mode 100644
index 0000000..7a7958f
--- /dev/null
+++ b/libs/tonemap/tests/tonemap_test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <tonemap/tonemap.h>
+#include <cmath>
+
+namespace android {
+
+using testing::HasSubstr;
+
+struct TonemapTest : public ::testing::Test {};
+
+TEST_F(TonemapTest, generateShaderSkSLUniforms_containsDefaultUniforms) {
+    static const constexpr float kDisplayMaxLuminance = 1.f;
+    static const constexpr float kContentMaxLuminance = 2.f;
+    tonemap::Metadata metadata{.displayMaxLuminance = kDisplayMaxLuminance,
+                               .contentMaxLuminance = kContentMaxLuminance};
+    const auto uniforms = tonemap::getToneMapper()->generateShaderSkSLUniforms(metadata);
+
+    ASSERT_EQ(1, std::count_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) {
+                  return data.name == "in_libtonemap_displayMaxLuminance";
+              }));
+    ASSERT_EQ(1, std::count_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) {
+                  return data.name == "in_libtonemap_inputMaxLuminance";
+              }));
+
+    // Smoke check that metadata values are "real", specifically that they're non-zero and actually
+    // numbers. This is to help avoid shaders using these uniforms from dividing by zero or other
+    // catastrophic errors.
+    const auto& displayLum = std::find_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) {
+                                 return data.name == "in_libtonemap_displayMaxLuminance";
+                             })->value;
+
+    float displayLumFloat = 0.f;
+    std::memcpy(&displayLumFloat, displayLum.data(), displayLum.size());
+    EXPECT_FALSE(std::isnan(displayLumFloat));
+    EXPECT_GT(displayLumFloat, 0);
+
+    const auto& contentLum = std::find_if(uniforms.cbegin(), uniforms.cend(), [](const auto& data) {
+                                 return data.name == "in_libtonemap_inputMaxLuminance";
+                             })->value;
+
+    float contentLumFloat = 0.f;
+    std::memcpy(&contentLumFloat, contentLum.data(), contentLum.size());
+    EXPECT_FALSE(std::isnan(contentLumFloat));
+    EXPECT_GT(contentLumFloat, 0);
+}
+
+TEST_F(TonemapTest, generateTonemapGainShaderSkSL_containsEntryPoint) {
+    const auto shader =
+            tonemap::getToneMapper()
+                    ->generateTonemapGainShaderSkSL(aidl::android::hardware::graphics::common::
+                                                            Dataspace::BT2020_ITU_PQ,
+                                                    aidl::android::hardware::graphics::common::
+                                                            Dataspace::DISPLAY_P3);
+
+    // Other tests such as librenderengine_test will plug in the shader to check compilation.
+    EXPECT_THAT(shader, HasSubstr("float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)"));
+}
+
+} // namespace android
diff --git a/libs/tonemap/tonemap.cpp b/libs/tonemap/tonemap.cpp
new file mode 100644
index 0000000..2cec773
--- /dev/null
+++ b/libs/tonemap/tonemap.cpp
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <tonemap/tonemap.h>
+
+#include <cstdint>
+#include <mutex>
+#include <type_traits>
+
+namespace android::tonemap {
+
+namespace {
+
+// Flag containing the variant of tone map algorithm to use.
+enum class ToneMapAlgorithm {
+    AndroidO,  // Default algorithm in place since Android O,
+    Android13, // Algorithm used in Android 13.
+};
+
+static const constexpr auto kToneMapAlgorithm = ToneMapAlgorithm::Android13;
+
+static const constexpr auto kTransferMask =
+        static_cast<int32_t>(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_MASK);
+static const constexpr auto kTransferST2084 =
+        static_cast<int32_t>(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_ST2084);
+static const constexpr auto kTransferHLG =
+        static_cast<int32_t>(aidl::android::hardware::graphics::common::Dataspace::TRANSFER_HLG);
+
+template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
+std::vector<uint8_t> buildUniformValue(T value) {
+    std::vector<uint8_t> result;
+    result.resize(sizeof(value));
+    std::memcpy(result.data(), &value, sizeof(value));
+    return result;
+}
+
+class ToneMapperO : public ToneMapper {
+public:
+    std::string generateTonemapGainShaderSkSL(
+            aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
+            aidl::android::hardware::graphics::common::Dataspace destinationDataspace) override {
+        const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
+        const int32_t destinationDataspaceInt = static_cast<int32_t>(destinationDataspace);
+
+        std::string program;
+        // Define required uniforms
+        program.append(R"(
+                uniform float in_libtonemap_displayMaxLuminance;
+                uniform float in_libtonemap_inputMaxLuminance;
+            )");
+        switch (sourceDataspaceInt & kTransferMask) {
+            case kTransferST2084:
+            case kTransferHLG:
+                switch (destinationDataspaceInt & kTransferMask) {
+                    case kTransferST2084:
+                        program.append(R"(
+                                    float libtonemap_ToneMapTargetNits(vec3 xyz) {
+                                        return xyz.y;
+                                    }
+                                )");
+                        break;
+                    case kTransferHLG:
+                        // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
+                        // we'll clamp the luminance range in case we're mapping from PQ input to
+                        // HLG output.
+                        program.append(R"(
+                                    float libtonemap_ToneMapTargetNits(vec3 xyz) {
+                                        return clamp(xyz.y, 0.0, 1000.0);
+                                    }
+                                )");
+                        break;
+                    default:
+                        // Here we're mapping from HDR to SDR content, so interpolate using a
+                        // Hermitian polynomial onto the smaller luminance range.
+                        program.append(R"(
+                                    float libtonemap_ToneMapTargetNits(vec3 xyz) {
+                                        float maxInLumi = in_libtonemap_inputMaxLuminance;
+                                        float maxOutLumi = in_libtonemap_displayMaxLuminance;
+
+                                        float nits = xyz.y;
+
+                                        // if the max input luminance is less than what we can
+                                        // output then no tone mapping is needed as all color
+                                        // values will be in range.
+                                        if (maxInLumi <= maxOutLumi) {
+                                            return xyz.y;
+                                        } else {
+
+                                            // three control points
+                                            const float x0 = 10.0;
+                                            const float y0 = 17.0;
+                                            float x1 = maxOutLumi * 0.75;
+                                            float y1 = x1;
+                                            float x2 = x1 + (maxInLumi - x1) / 2.0;
+                                            float y2 = y1 + (maxOutLumi - y1) * 0.75;
+
+                                            // horizontal distances between the last three
+                                            // control points
+                                            float h12 = x2 - x1;
+                                            float h23 = maxInLumi - x2;
+                                            // tangents at the last three control points
+                                            float m1 = (y2 - y1) / h12;
+                                            float m3 = (maxOutLumi - y2) / h23;
+                                            float m2 = (m1 + m3) / 2.0;
+
+                                            if (nits < x0) {
+                                                // scale [0.0, x0] to [0.0, y0] linearly
+                                                float slope = y0 / x0;
+                                                return nits * slope;
+                                            } else if (nits < x1) {
+                                                // scale [x0, x1] to [y0, y1] linearly
+                                                float slope = (y1 - y0) / (x1 - x0);
+                                                nits = y0 + (nits - x0) * slope;
+                                            } else if (nits < x2) {
+                                                // scale [x1, x2] to [y1, y2] using Hermite interp
+                                                float t = (nits - x1) / h12;
+                                                nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) *
+                                                        (1.0 - t) * (1.0 - t) +
+                                                        (y2 * (3.0 - 2.0 * t) +
+                                                        h12 * m2 * (t - 1.0)) * t * t;
+                                            } else {
+                                                // scale [x2, maxInLumi] to [y2, maxOutLumi] using
+                                                // Hermite interp
+                                                float t = (nits - x2) / h23;
+                                                nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) *
+                                                        (1.0 - t) * (1.0 - t) + (maxOutLumi *
+                                                        (3.0 - 2.0 * t) + h23 * m3 *
+                                                        (t - 1.0)) * t * t;
+                                            }
+                                        }
+
+                                        return nits;
+                                    }
+                                )");
+                        break;
+                }
+                break;
+            default:
+                switch (destinationDataspaceInt & kTransferMask) {
+                    case kTransferST2084:
+                    case kTransferHLG:
+                        // Map from SDR onto an HDR output buffer
+                        // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto
+                        // [0, maxOutLumi] which is hard-coded to be 3000 nits.
+                        program.append(R"(
+                                    float libtonemap_ToneMapTargetNits(vec3 xyz) {
+                                        const float maxOutLumi = 3000.0;
+
+                                        const float x0 = 5.0;
+                                        const float y0 = 2.5;
+                                        float x1 = in_libtonemap_displayMaxLuminance * 0.7;
+                                        float y1 = maxOutLumi * 0.15;
+                                        float x2 = in_libtonemap_displayMaxLuminance * 0.9;
+                                        float y2 = maxOutLumi * 0.45;
+                                        float x3 = in_libtonemap_displayMaxLuminance;
+                                        float y3 = maxOutLumi;
+
+                                        float c1 = y1 / 3.0;
+                                        float c2 = y2 / 2.0;
+                                        float c3 = y3 / 1.5;
+
+                                        float nits = xyz.y;
+
+                                        if (nits <= x0) {
+                                            // scale [0.0, x0] to [0.0, y0] linearly
+                                            float slope = y0 / x0;
+                                            return nits * slope;
+                                        } else if (nits <= x1) {
+                                            // scale [x0, x1] to [y0, y1] using a curve
+                                            float t = (nits - x0) / (x1 - x0);
+                                            nits = (1.0 - t) * (1.0 - t) * y0 +
+                                                    2.0 * (1.0 - t) * t * c1 + t * t * y1;
+                                        } else if (nits <= x2) {
+                                            // scale [x1, x2] to [y1, y2] using a curve
+                                            float t = (nits - x1) / (x2 - x1);
+                                            nits = (1.0 - t) * (1.0 - t) * y1 +
+                                                    2.0 * (1.0 - t) * t * c2 + t * t * y2;
+                                        } else {
+                                            // scale [x2, x3] to [y2, y3] using a curve
+                                            float t = (nits - x2) / (x3 - x2);
+                                            nits = (1.0 - t) * (1.0 - t) * y2 +
+                                                    2.0 * (1.0 - t) * t * c3 + t * t * y3;
+                                        }
+
+                                        return nits;
+                                    }
+                                )");
+                        break;
+                    default:
+                        // For completeness, this is tone-mapping from SDR to SDR, where this is
+                        // just a no-op.
+                        program.append(R"(
+                                    float libtonemap_ToneMapTargetNits(vec3 xyz) {
+                                        return xyz.y;
+                                    }
+                                )");
+                        break;
+                }
+                break;
+        }
+
+        program.append(R"(
+            float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz) {
+                if (xyz.y <= 0.0) {
+                    return 1.0;
+                }
+                return libtonemap_ToneMapTargetNits(xyz) / xyz.y;
+            }
+        )");
+        return program;
+    }
+
+    std::vector<ShaderUniform> generateShaderSkSLUniforms(const Metadata& metadata) override {
+        std::vector<ShaderUniform> uniforms;
+
+        uniforms.reserve(2);
+
+        uniforms.push_back({.name = "in_libtonemap_displayMaxLuminance",
+                            .value = buildUniformValue<float>(metadata.displayMaxLuminance)});
+        uniforms.push_back({.name = "in_libtonemap_inputMaxLuminance",
+                            .value = buildUniformValue<float>(metadata.contentMaxLuminance)});
+        return uniforms;
+    }
+};
+
+class ToneMapper13 : public ToneMapper {
+public:
+    std::string generateTonemapGainShaderSkSL(
+            aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
+            aidl::android::hardware::graphics::common::Dataspace destinationDataspace) override {
+        const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
+        const int32_t destinationDataspaceInt = static_cast<int32_t>(destinationDataspace);
+
+        std::string program;
+        // Input uniforms
+        program.append(R"(
+                uniform float in_libtonemap_displayMaxLuminance;
+                uniform float in_libtonemap_inputMaxLuminance;
+            )");
+        switch (sourceDataspaceInt & kTransferMask) {
+            case kTransferST2084:
+            case kTransferHLG:
+                switch (destinationDataspaceInt & kTransferMask) {
+                    case kTransferST2084:
+                        program.append(R"(
+                                    float libtonemap_ToneMapTargetNits(float maxRGB) {
+                                        return maxRGB;
+                                    }
+                                )");
+                        break;
+                    case kTransferHLG:
+                        // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
+                        // we'll clamp the luminance range in case we're mapping from PQ input to
+                        // HLG output.
+                        program.append(R"(
+                                    float libtonemap_ToneMapTargetNits(float maxRGB) {
+                                        return clamp(maxRGB, 0.0, 1000.0);
+                                    }
+                                )");
+                        break;
+
+                    default:
+                        switch (sourceDataspaceInt & kTransferMask) {
+                            case kTransferST2084:
+                                program.append(R"(
+                                        float libtonemap_OETFTone(float channel) {
+                                            channel = channel / 10000.0;
+                                            float m1 = (2610.0 / 4096.0) / 4.0;
+                                            float m2 = (2523.0 / 4096.0) * 128.0;
+                                            float c1 = (3424.0 / 4096.0);
+                                            float c2 = (2413.0 / 4096.0) * 32.0;
+                                            float c3 = (2392.0 / 4096.0) * 32.0;
+
+                                            float tmp = pow(channel, float(m1));
+                                            tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
+                                            return pow(tmp, float(m2));
+                                        }
+                                    )");
+                                break;
+                            case kTransferHLG:
+                                program.append(R"(
+                                        float libtonemap_OETFTone(float channel) {
+                                            channel = channel / 1000.0;
+                                            const float a = 0.17883277;
+                                            const float b = 0.28466892;
+                                            const float c = 0.55991073;
+                                            return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) :
+                                                    a * log(12.0 * channel - b) + c;
+                                        }
+                                    )");
+                                break;
+                        }
+                        // Here we're mapping from HDR to SDR content, so interpolate using a
+                        // Hermitian polynomial onto the smaller luminance range.
+                        program.append(R"(
+                                float libtonemap_ToneMapTargetNits(float maxRGB) {
+                                    float maxInLumi = in_libtonemap_inputMaxLuminance;
+                                    float maxOutLumi = in_libtonemap_displayMaxLuminance;
+
+                                    float nits = maxRGB;
+
+                                    float x1 = maxOutLumi * 0.65;
+                                    float y1 = x1;
+
+                                    float x3 = maxInLumi;
+                                    float y3 = maxOutLumi;
+
+                                    float x2 = x1 + (x3 - x1) * 4.0 / 17.0;
+                                    float y2 = maxOutLumi * 0.9;
+
+                                    float greyNorm1 = libtonemap_OETFTone(x1);
+                                    float greyNorm2 = libtonemap_OETFTone(x2);
+                                    float greyNorm3 = libtonemap_OETFTone(x3);
+
+                                    float slope1 = 0;
+                                    float slope2 = (y2 - y1) / (greyNorm2 - greyNorm1);
+                                    float slope3 = (y3 - y2 ) / (greyNorm3 - greyNorm2);
+
+                                    if (nits < x1) {
+                                        return nits;
+                                    }
+
+                                    if (nits > maxInLumi) {
+                                        return maxOutLumi;
+                                    }
+
+                                    float greyNits = libtonemap_OETFTone(nits);
+
+                                    if (greyNits <= greyNorm2) {
+                                        nits = (greyNits - greyNorm2) * slope2 + y2;
+                                    } else if (greyNits <= greyNorm3) {
+                                        nits = (greyNits - greyNorm3) * slope3 + y3;
+                                    } else {
+                                        nits = maxOutLumi;
+                                    }
+
+                                    return nits;
+                                }
+                                )");
+                        break;
+                }
+                break;
+            default:
+                // Inverse tone-mapping and SDR-SDR mapping is not supported.
+                program.append(R"(
+                            float libtonemap_ToneMapTargetNits(float maxRGB) {
+                                return maxRGB;
+                            }
+                        )");
+                break;
+        }
+
+        program.append(R"(
+            float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz) {
+                float maxRGB = max(linearRGB.r, max(linearRGB.g, linearRGB.b));
+                if (maxRGB <= 0.0) {
+                    return 1.0;
+                }
+                return libtonemap_ToneMapTargetNits(maxRGB) / maxRGB;
+            }
+        )");
+        return program;
+    }
+
+    std::vector<ShaderUniform> generateShaderSkSLUniforms(const Metadata& metadata) override {
+        // Hardcode the max content luminance to a "reasonable" level
+        static const constexpr float kContentMaxLuminance = 4000.f;
+        std::vector<ShaderUniform> uniforms;
+        uniforms.reserve(2);
+        uniforms.push_back({.name = "in_libtonemap_displayMaxLuminance",
+                            .value = buildUniformValue<float>(metadata.displayMaxLuminance)});
+        uniforms.push_back({.name = "in_libtonemap_inputMaxLuminance",
+                            .value = buildUniformValue<float>(kContentMaxLuminance)});
+        return uniforms;
+    }
+};
+
+} // namespace
+
+ToneMapper* getToneMapper() {
+    static std::once_flag sOnce;
+    static std::unique_ptr<ToneMapper> sToneMapper;
+
+    std::call_once(sOnce, [&] {
+        switch (kToneMapAlgorithm) {
+            case ToneMapAlgorithm::AndroidO:
+                sToneMapper = std::unique_ptr<ToneMapper>(new ToneMapperO());
+                break;
+            case ToneMapAlgorithm::Android13:
+                sToneMapper = std::unique_ptr<ToneMapper>(new ToneMapper13());
+        }
+    });
+
+    return sToneMapper.get();
+}
+
+} // namespace android::tonemap
\ No newline at end of file
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 73e5749..8cdb706 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -73,7 +73,6 @@
         "libui",
         "lib-platform-compat-native-api",
         "server_configurable_flags",
-        "InputFlingerProperties",
     ],
     static_libs: [
         "libattestation",
@@ -125,7 +124,7 @@
         "InputListener.cpp",
         "InputReaderBase.cpp",
         "InputThread.cpp",
-        "VibrationElement.cpp"
+        "VibrationElement.cpp",
     ],
 }
 
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 171f2b5..4757d31 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -68,7 +68,6 @@
         "libutils",
         "lib-platform-compat-native-api",
         "server_configurable_flags",
-        "InputFlingerProperties",
     ],
     static_libs: [
         "libattestation",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 44409a2..7f68d1b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -19,7 +19,6 @@
 
 #define LOG_NDEBUG 1
 
-#include <InputFlingerProperties.sysprop.h>
 #include <android-base/chrono_utils.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
@@ -112,15 +111,6 @@
     std::mutex& mMutex;
 };
 
-// When per-window-input-rotation is enabled, InputFlinger works in the un-rotated display
-// coordinates and SurfaceFlinger includes the display rotation in the input window transforms.
-bool isPerWindowInputRotationEnabled() {
-    static const bool PER_WINDOW_INPUT_ROTATION =
-            sysprop::InputFlingerProperties::per_window_input_rotation().value_or(true);
-
-    return PER_WINDOW_INPUT_ROTATION;
-}
-
 // Default input dispatching timeout if there is no focused application or paused window
 // from which to determine an appropriate dispatching timeout.
 const std::chrono::duration DEFAULT_INPUT_DISPATCHING_TIMEOUT = std::chrono::milliseconds(
@@ -2515,8 +2505,7 @@
         if (displayInfoIt != mDisplayInfos.end()) {
             inputTarget.displayTransform = displayInfoIt->second.transform;
         } else {
-            ALOGI_IF(isPerWindowInputRotationEnabled(),
-                     "DisplayInfo not found for window on display: %d", windowInfo->displayId);
+            ALOGE("DisplayInfo not found for window on display: %d", windowInfo->displayId);
         }
         inputTargets.push_back(inputTarget);
         it = inputTargets.end() - 1;
@@ -3241,8 +3230,7 @@
                 const FocusEntry& focusEntry = static_cast<const FocusEntry&>(eventEntry);
                 status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq,
                                                                       focusEntry.id,
-                                                                      focusEntry.hasFocus,
-                                                                      mInTouchMode);
+                                                                      focusEntry.hasFocus);
                 break;
             }
 
@@ -4721,21 +4709,19 @@
         }
     }
 
-    if (isPerWindowInputRotationEnabled()) {
-        // Determine if the orientation of any of the input windows have changed, and cancel all
-        // pointer events if necessary.
-        for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
-            const sp<WindowInfoHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle);
-            if (newWindowHandle != nullptr &&
-                newWindowHandle->getInfo()->transform.getOrientation() !=
-                        oldWindowOrientations[oldWindowHandle->getId()]) {
-                std::shared_ptr<InputChannel> inputChannel =
-                        getInputChannelLocked(newWindowHandle->getToken());
-                if (inputChannel != nullptr) {
-                    CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
-                                               "touched window's orientation changed");
-                    synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
-                }
+    // Determine if the orientation of any of the input windows have changed, and cancel all
+    // pointer events if necessary.
+    for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
+        const sp<WindowInfoHandle> newWindowHandle = getWindowHandleLocked(oldWindowHandle);
+        if (newWindowHandle != nullptr &&
+            newWindowHandle->getInfo()->transform.getOrientation() !=
+                    oldWindowOrientations[oldWindowHandle->getId()]) {
+            std::shared_ptr<InputChannel> inputChannel =
+                    getInputChannelLocked(newWindowHandle->getToken());
+            if (inputChannel != nullptr) {
+                CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
+                                           "touched window's orientation changed");
+                synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
             }
         }
     }
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index ee7b392..51546ce 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -71,7 +71,6 @@
         "libstatslog",
         "libui",
         "libutils",
-        "InputFlingerProperties",
     ],
     static_libs: [
         "libc++fs",
@@ -86,7 +85,7 @@
     name: "libinputreader",
     defaults: [
         "inputflinger_defaults",
-        "libinputreader_defaults"
+        "libinputreader_defaults",
     ],
     srcs: [
         "InputReaderFactory.cpp",
@@ -100,6 +99,6 @@
         "libinputreader_headers",
     ],
     static_libs: [
-        "libc++fs"
+        "libc++fs",
     ],
 }
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index f3d7cdc..15ba459 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -193,28 +193,18 @@
         const bool isOrientedDevice =
                 (mParameters.orientationAware && mParameters.hasAssociatedDisplay);
 
-        if (isPerWindowInputRotationEnabled()) {
-            // When per-window input rotation is enabled, InputReader works in the un-rotated
-            // coordinate space, so we don't need to do anything if the device is already
-            // orientation-aware. If the device is not orientation-aware, then we need to apply the
-            // inverse rotation of the display so that when the display rotation is applied later
-            // as a part of the per-window transform, we get the expected screen coordinates.
-            if (!isOrientedDevice) {
-                std::optional<DisplayViewport> internalViewport =
-                        config->getDisplayViewportByType(ViewportType::INTERNAL);
-                if (internalViewport) {
-                    mOrientation = getInverseRotation(internalViewport->orientation);
-                    mDisplayWidth = internalViewport->deviceWidth;
-                    mDisplayHeight = internalViewport->deviceHeight;
-                }
-            }
-        } else {
-            if (isOrientedDevice) {
-                std::optional<DisplayViewport> internalViewport =
-                        config->getDisplayViewportByType(ViewportType::INTERNAL);
-                if (internalViewport) {
-                    mOrientation = internalViewport->orientation;
-                }
+        // InputReader works in the un-rotated display coordinate space, so we don't need to do
+        // anything if the device is already orientation-aware. If the device is not
+        // orientation-aware, then we need to apply the inverse rotation of the display so that
+        // when the display rotation is applied later as a part of the per-window transform, we
+        // get the expected screen coordinates.
+        if (!isOrientedDevice) {
+            std::optional<DisplayViewport> internalViewport =
+                    config->getDisplayViewportByType(ViewportType::INTERNAL);
+            if (internalViewport) {
+                mOrientation = getInverseRotation(internalViewport->orientation);
+                mDisplayWidth = internalViewport->deviceWidth;
+                mDisplayHeight = internalViewport->deviceHeight;
             }
         }
 
@@ -347,12 +337,11 @@
             if (moved) {
                 float dx = deltaX;
                 float dy = deltaY;
-                if (isPerWindowInputRotationEnabled()) {
-                    // Rotate the delta from InputReader's un-rotated coordinate space to
-                    // PointerController's rotated coordinate space that is oriented with the
-                    // viewport.
-                    rotateDelta(getInverseRotation(mOrientation), &dx, &dy);
-                }
+                // Rotate the delta from InputReader's un-rotated coordinate space to
+                // PointerController's rotated coordinate space that is oriented with the
+                // viewport.
+                rotateDelta(getInverseRotation(mOrientation), &dx, &dy);
+
                 mPointerController->move(dx, dy);
             }
 
@@ -364,12 +353,11 @@
         }
 
         mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
-        if (isPerWindowInputRotationEnabled()) {
-            // Rotate the cursor position that is in PointerController's rotated coordinate space
-            // to InputReader's un-rotated coordinate space.
-            rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/,
-                        mDisplayWidth, mDisplayHeight);
-        }
+        // Rotate the cursor position that is in PointerController's rotated coordinate space
+        // to InputReader's un-rotated coordinate space.
+        rotatePoint(mOrientation, xCursorPosition /*byRef*/, yCursorPosition /*byRef*/,
+                    mDisplayWidth, mDisplayHeight);
+
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 197be98..8c30e38 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -17,7 +17,6 @@
 #ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
 #define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
 
-#include <InputFlingerProperties.sysprop.h>
 #include <input/DisplayViewport.h>
 #include <stdint.h>
 
@@ -29,13 +28,6 @@
 
 // --- Static Definitions ---
 
-// When per-window input rotation is enabled, display transformations such as rotation and
-// projection are part of the input window's transform. This means InputReader should work in the
-// un-rotated coordinate space.
-static bool isPerWindowInputRotationEnabled() {
-    return sysprop::InputFlingerProperties::per_window_input_rotation().value_or(true);
-}
-
 static int32_t getInverseRotation(int32_t orientation) {
     switch (orientation) {
         case DISPLAY_ORIENTATION_90:
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index fd33df9..3fe6fd1 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -168,17 +168,13 @@
       : InputMapper(deviceContext),
         mSource(0),
         mDeviceMode(DeviceMode::DISABLED),
-        mRawSurfaceWidth(-1),
-        mRawSurfaceHeight(-1),
-        mSurfaceLeft(0),
-        mSurfaceTop(0),
-        mSurfaceRight(0),
-        mSurfaceBottom(0),
+        mDisplayWidth(-1),
+        mDisplayHeight(-1),
         mPhysicalWidth(-1),
         mPhysicalHeight(-1),
         mPhysicalLeft(0),
         mPhysicalTop(0),
-        mSurfaceOrientation(DISPLAY_ORIENTATION_0) {}
+        mInputDeviceOrientation(DISPLAY_ORIENTATION_0) {}
 
 TouchInputMapper::~TouchInputMapper() {}
 
@@ -266,11 +262,9 @@
     dumpRawPointerAxes(dump);
     dumpCalibration(dump);
     dumpAffineTransformation(dump);
-    dumpSurface(dump);
+    dumpDisplay(dump);
 
     dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n");
-    dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
-    dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
     dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale);
     dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale);
     dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
@@ -390,9 +384,9 @@
           InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT |
           InputReaderConfiguration::CHANGE_SHOW_TOUCHES |
           InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
-        // Configure device sources, surface dimensions, orientation and
+        // Configure device sources, display dimensions, orientation and
         // scaling factors.
-        configureSurface(when, &resetNeeded);
+        configureInputDevice(when, &resetNeeded);
     }
 
     if (changes && resetNeeded) {
@@ -615,7 +609,7 @@
     return std::make_optional(newViewport);
 }
 
-void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
+void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) {
     DeviceMode oldDeviceMode = mDeviceMode;
 
     resolveExternalStylusPresence();
@@ -673,31 +667,28 @@
     }
 
     // Raw width and height in the natural orientation.
-    int32_t rawWidth = mRawPointerAxes.getRawWidth();
-    int32_t rawHeight = mRawPointerAxes.getRawHeight();
+    const int32_t rawWidth = mRawPointerAxes.getRawWidth();
+    const int32_t rawHeight = mRawPointerAxes.getRawHeight();
 
-    bool viewportChanged = mViewport != *newViewport;
+    const bool viewportChanged = mViewport != *newViewport;
     bool skipViewportUpdate = false;
     if (viewportChanged) {
-        bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation;
+        const bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation;
         mViewport = *newViewport;
 
         if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
-            // Convert rotated viewport to natural surface coordinates.
-            int32_t naturalLogicalWidth, naturalLogicalHeight;
+            // Convert rotated viewport to the natural orientation.
             int32_t naturalPhysicalWidth, naturalPhysicalHeight;
             int32_t naturalPhysicalLeft, naturalPhysicalTop;
             int32_t naturalDeviceWidth, naturalDeviceHeight;
 
-            // Apply the inverse of the input device orientation so that the surface is configured
-            // in the same orientation as the device. The input device orientation will be
-            // re-applied to mSurfaceOrientation.
-            const int32_t naturalSurfaceOrientation =
+            // Apply the inverse of the input device orientation so that the input device is
+            // configured in the same orientation as the viewport. The input device orientation will
+            // be re-applied by mInputDeviceOrientation.
+            const int32_t naturalDeviceOrientation =
                     (mViewport.orientation - static_cast<int32_t>(mParameters.orientation) + 4) % 4;
-            switch (naturalSurfaceOrientation) {
+            switch (naturalDeviceOrientation) {
                 case DISPLAY_ORIENTATION_90:
-                    naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
-                    naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
                     naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
                     naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
                     naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
@@ -706,8 +697,6 @@
                     naturalDeviceHeight = mViewport.deviceWidth;
                     break;
                 case DISPLAY_ORIENTATION_180:
-                    naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
-                    naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
                     naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
                     naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
                     naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight;
@@ -716,8 +705,6 @@
                     naturalDeviceHeight = mViewport.deviceHeight;
                     break;
                 case DISPLAY_ORIENTATION_270:
-                    naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
-                    naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
                     naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
                     naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
                     naturalPhysicalLeft = mViewport.physicalTop;
@@ -727,8 +714,6 @@
                     break;
                 case DISPLAY_ORIENTATION_0:
                 default:
-                    naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
-                    naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
                     naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
                     naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
                     naturalPhysicalLeft = mViewport.physicalLeft;
@@ -749,58 +734,36 @@
             mPhysicalLeft = naturalPhysicalLeft;
             mPhysicalTop = naturalPhysicalTop;
 
-            if (isPerWindowInputRotationEnabled()) {
-                // When per-window input rotation is enabled, InputReader works in the display
-                // space, so the surface bounds are the bounds of the display device.
-                const int32_t oldSurfaceWidth = mRawSurfaceWidth;
-                const int32_t oldSurfaceHeight = mRawSurfaceHeight;
-                mRawSurfaceWidth = naturalDeviceWidth;
-                mRawSurfaceHeight = naturalDeviceHeight;
-                mSurfaceLeft = 0;
-                mSurfaceTop = 0;
-                mSurfaceRight = mRawSurfaceWidth;
-                mSurfaceBottom = mRawSurfaceHeight;
-                // When per-window input rotation is enabled, InputReader works in the un-rotated
-                // coordinate space, so we don't need to do anything if the device is already
-                // orientation-aware. If the device is not orientation-aware, then we need to apply
-                // the inverse rotation of the display so that when the display rotation is applied
-                // later as a part of the per-window transform, we get the expected screen
-                // coordinates.
-                mSurfaceOrientation = mParameters.orientationAware
-                        ? DISPLAY_ORIENTATION_0
-                        : getInverseRotation(mViewport.orientation);
-                // For orientation-aware devices that work in the un-rotated coordinate space, the
-                // viewport update should be skipped if it is only a change in the orientation.
-                skipViewportUpdate = mParameters.orientationAware &&
-                        mRawSurfaceWidth == oldSurfaceWidth &&
-                        mRawSurfaceHeight == oldSurfaceHeight && viewportOrientationChanged;
-            } else {
-                mRawSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
-                mRawSurfaceHeight =
-                        naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
-                mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
-                mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
-                mSurfaceRight = mSurfaceLeft + naturalLogicalWidth;
-                mSurfaceBottom = mSurfaceTop + naturalLogicalHeight;
+            const int32_t oldDisplayWidth = mDisplayWidth;
+            const int32_t oldDisplayHeight = mDisplayHeight;
+            mDisplayWidth = naturalDeviceWidth;
+            mDisplayHeight = naturalDeviceHeight;
 
-                mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation
-                                                                   : DISPLAY_ORIENTATION_0;
-            }
+            // InputReader works in the un-rotated display coordinate space, so we don't need to do
+            // anything if the device is already orientation-aware. If the device is not
+            // orientation-aware, then we need to apply the inverse rotation of the display so that
+            // when the display rotation is applied later as a part of the per-window transform, we
+            // get the expected screen coordinates.
+            mInputDeviceOrientation = mParameters.orientationAware
+                    ? DISPLAY_ORIENTATION_0
+                    : getInverseRotation(mViewport.orientation);
+            // For orientation-aware devices that work in the un-rotated coordinate space, the
+            // viewport update should be skipped if it is only a change in the orientation.
+            skipViewportUpdate = mParameters.orientationAware && mDisplayWidth == oldDisplayWidth &&
+                    mDisplayHeight == oldDisplayHeight && viewportOrientationChanged;
 
             // Apply the input device orientation for the device.
-            mSurfaceOrientation =
-                    (mSurfaceOrientation + static_cast<int32_t>(mParameters.orientation)) % 4;
+            mInputDeviceOrientation =
+                    (mInputDeviceOrientation + static_cast<int32_t>(mParameters.orientation)) % 4;
         } else {
             mPhysicalWidth = rawWidth;
             mPhysicalHeight = rawHeight;
             mPhysicalLeft = 0;
             mPhysicalTop = 0;
 
-            mRawSurfaceWidth = rawWidth;
-            mRawSurfaceHeight = rawHeight;
-            mSurfaceLeft = 0;
-            mSurfaceTop = 0;
-            mSurfaceOrientation = DISPLAY_ORIENTATION_0;
+            mDisplayWidth = rawWidth;
+            mDisplayHeight = rawHeight;
+            mInputDeviceOrientation = DISPLAY_ORIENTATION_0;
         }
     }
 
@@ -829,14 +792,12 @@
     if ((viewportChanged && !skipViewportUpdate) || deviceModeChanged) {
         ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
               "display id %d",
-              getDeviceId(), getDeviceName().c_str(), mRawSurfaceWidth, mRawSurfaceHeight,
-              mSurfaceOrientation, mDeviceMode, mViewport.displayId);
+              getDeviceId(), getDeviceName().c_str(), mDisplayWidth, mDisplayHeight,
+              mInputDeviceOrientation, mDeviceMode, mViewport.displayId);
 
         // Configure X and Y factors.
-        mXScale = float(mRawSurfaceWidth) / rawWidth;
-        mYScale = float(mRawSurfaceHeight) / rawHeight;
-        mXTranslate = -mSurfaceLeft;
-        mYTranslate = -mSurfaceTop;
+        mXScale = float(mDisplayWidth) / rawWidth;
+        mYScale = float(mDisplayHeight) / rawHeight;
         mXPrecision = 1.0f / mXScale;
         mYPrecision = 1.0f / mYScale;
 
@@ -853,7 +814,7 @@
         mGeometricScale = avg(mXScale, mYScale);
 
         // Size of diagonal axis.
-        float diagonalSize = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
+        float diagonalSize = hypotf(mDisplayWidth, mDisplayHeight);
 
         // Size factors.
         if (mCalibration.sizeCalibration != Calibration::SizeCalibration::NONE) {
@@ -1015,21 +976,21 @@
 
         // Compute oriented precision, scales and ranges.
         // Note that the maximum value reported is an inclusive maximum value so it is one
-        // unit less than the total width or height of surface.
-        switch (mSurfaceOrientation) {
+        // unit less than the total width or height of the display.
+        switch (mInputDeviceOrientation) {
             case DISPLAY_ORIENTATION_90:
             case DISPLAY_ORIENTATION_270:
                 mOrientedXPrecision = mYPrecision;
                 mOrientedYPrecision = mXPrecision;
 
-                mOrientedRanges.x.min = mYTranslate;
-                mOrientedRanges.x.max = mRawSurfaceHeight + mYTranslate - 1;
+                mOrientedRanges.x.min = 0;
+                mOrientedRanges.x.max = mDisplayHeight - 1;
                 mOrientedRanges.x.flat = 0;
                 mOrientedRanges.x.fuzz = 0;
                 mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
 
-                mOrientedRanges.y.min = mXTranslate;
-                mOrientedRanges.y.max = mRawSurfaceWidth + mXTranslate - 1;
+                mOrientedRanges.y.min = 0;
+                mOrientedRanges.y.max = mDisplayWidth - 1;
                 mOrientedRanges.y.flat = 0;
                 mOrientedRanges.y.fuzz = 0;
                 mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
@@ -1039,14 +1000,14 @@
                 mOrientedXPrecision = mXPrecision;
                 mOrientedYPrecision = mYPrecision;
 
-                mOrientedRanges.x.min = mXTranslate;
-                mOrientedRanges.x.max = mRawSurfaceWidth + mXTranslate - 1;
+                mOrientedRanges.x.min = 0;
+                mOrientedRanges.x.max = mDisplayWidth - 1;
                 mOrientedRanges.x.flat = 0;
                 mOrientedRanges.x.fuzz = 0;
                 mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
 
-                mOrientedRanges.y.min = mYTranslate;
-                mOrientedRanges.y.max = mRawSurfaceHeight + mYTranslate - 1;
+                mOrientedRanges.y.min = 0;
+                mOrientedRanges.y.max = mDisplayHeight - 1;
                 mOrientedRanges.y.flat = 0;
                 mOrientedRanges.y.fuzz = 0;
                 mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
@@ -1059,7 +1020,7 @@
         if (mDeviceMode == DeviceMode::POINTER) {
             // Compute pointer gesture detection parameters.
             float rawDiagonal = hypotf(rawWidth, rawHeight);
-            float displayDiagonal = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
+            float displayDiagonal = hypotf(mDisplayWidth, mDisplayHeight);
 
             // Scale movements such that one whole swipe of the touch pad covers a
             // given area relative to the diagonal size of the display when no acceleration
@@ -1093,19 +1054,15 @@
     }
 }
 
-void TouchInputMapper::dumpSurface(std::string& dump) {
+void TouchInputMapper::dumpDisplay(std::string& dump) {
     dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str());
-    dump += StringPrintf(INDENT3 "RawSurfaceWidth: %dpx\n", mRawSurfaceWidth);
-    dump += StringPrintf(INDENT3 "RawSurfaceHeight: %dpx\n", mRawSurfaceHeight);
-    dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
-    dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
-    dump += StringPrintf(INDENT3 "SurfaceRight: %d\n", mSurfaceRight);
-    dump += StringPrintf(INDENT3 "SurfaceBottom: %d\n", mSurfaceBottom);
+    dump += StringPrintf(INDENT3 "DisplayWidth: %dpx\n", mDisplayWidth);
+    dump += StringPrintf(INDENT3 "DisplayHeight: %dpx\n", mDisplayHeight);
     dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth);
     dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight);
     dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft);
     dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop);
-    dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
+    dump += StringPrintf(INDENT3 "InputDeviceOrientation: %d\n", mInputDeviceOrientation);
 }
 
 void TouchInputMapper::configureVirtualKeys() {
@@ -1144,16 +1101,16 @@
         int32_t halfHeight = virtualKeyDefinition.height / 2;
 
         virtualKey.hitLeft =
-                (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mRawSurfaceWidth +
+                (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mDisplayWidth +
                 touchScreenLeft;
         virtualKey.hitRight =
-                (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mRawSurfaceWidth +
+                (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mDisplayWidth +
                 touchScreenLeft;
-        virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight /
-                        mRawSurfaceHeight +
+        virtualKey.hitTop =
+                (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mDisplayHeight +
                 touchScreenTop;
-        virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight /
-                        mRawSurfaceHeight +
+        virtualKey.hitBottom =
+                (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mDisplayHeight +
                 touchScreenTop;
         mVirtualKeys.push_back(virtualKey);
     }
@@ -1419,7 +1376,7 @@
 
 void TouchInputMapper::updateAffineTransformation() {
     mAffineTransform = getPolicy()->getTouchAffineTransformation(getDeviceContext().getDescriptor(),
-                                                                 mSurfaceOrientation);
+                                                                 mInputDeviceOrientation);
 }
 
 void TouchInputMapper::reset(nsecs_t when) {
@@ -1867,8 +1824,10 @@
         // Pointer just went down.  Check for virtual key press or off-screen touches.
         uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
         const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
-        // Exclude unscaled device for inside surface checking.
-        if (!isPointInsideSurface(pointer.x, pointer.y) && mDeviceMode != DeviceMode::UNSCALED) {
+        // Skip checking whether the pointer is inside the physical frame if the device is in
+        // unscaled mode.
+        if (!isPointInsidePhysicalFrame(pointer.x, pointer.y) &&
+            mDeviceMode != DeviceMode::UNSCALED) {
             // If exactly one pointer went down, check for virtual key hit.
             // Otherwise we will drop the entire stroke.
             if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
@@ -2137,7 +2096,7 @@
     }
 
     // Walk through the the active pointers and map device coordinates onto
-    // surface coordinates and adjust for display orientation.
+    // display coordinates and adjust for display orientation.
     for (uint32_t i = 0; i < currentPointerCount; i++) {
         const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
 
@@ -2297,15 +2256,15 @@
         mAffineTransform.applyTo(xTransformed, yTransformed);
         rotateAndScale(xTransformed, yTransformed);
 
-        // Adjust X, Y, and coverage coords for surface orientation.
+        // Adjust X, Y, and coverage coords for input device orientation.
         float left, top, right, bottom;
 
-        switch (mSurfaceOrientation) {
+        switch (mInputDeviceOrientation) {
             case DISPLAY_ORIENTATION_90:
-                left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-                right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-                bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
-                top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
+                left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale;
+                right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale;
+                bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
+                top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
                 orientation -= M_PI_2;
                 if (mOrientedRanges.haveOrientation &&
                     orientation < mOrientedRanges.orientation.min) {
@@ -2316,8 +2275,8 @@
             case DISPLAY_ORIENTATION_180:
                 left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
                 right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
-                bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
-                top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
+                bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
+                top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
                 orientation -= M_PI;
                 if (mOrientedRanges.haveOrientation &&
                     orientation < mOrientedRanges.orientation.min) {
@@ -2328,8 +2287,8 @@
             case DISPLAY_ORIENTATION_270:
                 left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
                 right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
-                bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-                top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
+                bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale;
+                top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale;
                 orientation += M_PI_2;
                 if (mOrientedRanges.haveOrientation &&
                     orientation > mOrientedRanges.orientation.max) {
@@ -2338,10 +2297,10 @@
                 }
                 break;
             default:
-                left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-                right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
-                bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
-                top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
+                left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale;
+                right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale;
+                bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale;
+                top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale;
                 break;
         }
 
@@ -2854,7 +2813,7 @@
             deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
             deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
 
-            rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
+            rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
             mPointerVelocityControl.move(when, &deltaX, &deltaY);
 
             // Move the pointer using a relative motion.
@@ -2988,7 +2947,7 @@
             deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
             deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
 
-            rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
+            rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
             mPointerVelocityControl.move(when, &deltaX, &deltaY);
 
             // Move the pointer using a relative motion.
@@ -3246,7 +3205,7 @@
             commonDeltaX *= mPointerXMovementScale;
             commonDeltaY *= mPointerYMovementScale;
 
-            rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY);
+            rotateDelta(mInputDeviceOrientation, &commonDeltaX, &commonDeltaY);
             mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
 
             mPointerGesture.referenceGestureX += commonDeltaX;
@@ -3356,7 +3315,7 @@
                         mCurrentRawState.rawPointerData.pointerForId(touchId);
                 float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale;
                 float deltaY = (pointer.y - mPointerGesture.referenceTouchY) * mPointerYZoomScale;
-                rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
+                rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
 
                 mPointerGesture.currentGestureProperties[i].clear();
                 mPointerGesture.currentGestureProperties[i].id = gestureId;
@@ -3472,7 +3431,7 @@
                       mLastRawState.rawPointerData.pointers[lastIndex].y) *
                     mPointerYMovementScale;
 
-            rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
+            rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
             mPointerVelocityControl.move(when, &deltaX, &deltaY);
 
             moveMouseCursor(deltaX, deltaY);
@@ -3697,7 +3656,7 @@
     const int32_t deviceId = getDeviceId();
     std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
     std::for_each(frames.begin(), frames.end(),
-                  [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
+                  [this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); });
     NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
                           policyFlags, action, actionButton, flags, metaState, buttonState,
                           MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
@@ -3741,56 +3700,49 @@
     abortTouches(when, readTime, 0 /* policyFlags*/);
 }
 
-// Transform raw coordinate to surface coordinate
-void TouchInputMapper::rotateAndScale(float& x, float& y) {
-    // Scale to surface coordinate.
+// Transform input device coordinates to display panel coordinates.
+void TouchInputMapper::rotateAndScale(float& x, float& y) const {
     const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale;
     const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale;
 
     const float xScaledMax = float(mRawPointerAxes.x.maxValue - x) * mXScale;
     const float yScaledMax = float(mRawPointerAxes.y.maxValue - y) * mYScale;
 
-    // Rotate to surface coordinate.
+    // Rotate to display coordinate.
     // 0 - no swap and reverse.
     // 90 - swap x/y and reverse y.
     // 180 - reverse x, y.
     // 270 - swap x/y and reverse x.
-    switch (mSurfaceOrientation) {
+    switch (mInputDeviceOrientation) {
         case DISPLAY_ORIENTATION_0:
-            x = xScaled + mXTranslate;
-            y = yScaled + mYTranslate;
+            x = xScaled;
+            y = yScaled;
             break;
         case DISPLAY_ORIENTATION_90:
-            y = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
-            x = yScaled + mYTranslate;
+            y = xScaledMax;
+            x = yScaled;
             break;
         case DISPLAY_ORIENTATION_180:
-            x = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
-            y = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
+            x = xScaledMax;
+            y = yScaledMax;
             break;
         case DISPLAY_ORIENTATION_270:
-            y = xScaled + mXTranslate;
-            x = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
+            y = xScaled;
+            x = yScaledMax;
             break;
         default:
             assert(false);
     }
 }
 
-bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
+bool TouchInputMapper::isPointInsidePhysicalFrame(int32_t x, int32_t y) const {
     const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale;
     const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale;
 
-    if (isPerWindowInputRotationEnabled()) {
-        return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
-                xScaled >= mPhysicalLeft && xScaled <= (mPhysicalLeft + mPhysicalWidth) &&
-                y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
-                yScaled >= mPhysicalTop && yScaled <= (mPhysicalTop + mPhysicalHeight);
-    }
     return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
-            xScaled >= mSurfaceLeft && xScaled <= mSurfaceRight &&
+            xScaled >= mPhysicalLeft && xScaled <= (mPhysicalLeft + mPhysicalWidth) &&
             y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
-            yScaled >= mSurfaceTop && yScaled <= mSurfaceBottom;
+            yScaled >= mPhysicalTop && yScaled <= (mPhysicalTop + mPhysicalHeight);
 }
 
 const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
@@ -4048,11 +4000,9 @@
 }
 
 void TouchInputMapper::moveMouseCursor(float dx, float dy) const {
-    if (isPerWindowInputRotationEnabled()) {
-        // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate
-        // space that is oriented with the viewport.
-        rotateDelta(mViewport.orientation, &dx, &dy);
-    }
+    // Convert from InputReader's un-rotated coordinate space to PointerController's coordinate
+    // space that is oriented with the viewport.
+    rotateDelta(mViewport.orientation, &dx, &dy);
 
     mPointerController->move(dx, dy);
 }
@@ -4062,7 +4012,6 @@
     float y = 0;
     mPointerController->getPosition(&x, &y);
 
-    if (!isPerWindowInputRotationEnabled()) return {x, y};
     if (!mViewport.isValid()) return {x, y};
 
     // Convert from PointerController's rotated coordinate space that is oriented with the viewport
@@ -4073,11 +4022,9 @@
 }
 
 void TouchInputMapper::setMouseCursorPosition(float x, float y) const {
-    if (isPerWindowInputRotationEnabled() && mViewport.isValid()) {
-        // Convert from InputReader's un-rotated coordinate space to PointerController's rotated
-        // coordinate space that is oriented with the viewport.
-        rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight);
-    }
+    // Convert from InputReader's un-rotated coordinate space to PointerController's rotated
+    // coordinate space that is oriented with the viewport.
+    rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight);
 
     mPointerController->setPosition(x, y);
 }
@@ -4092,11 +4039,9 @@
         float y = spotCoords[index].getY();
         float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
 
-        if (isPerWindowInputRotationEnabled()) {
-            // Convert from InputReader's un-rotated coordinate space to PointerController's rotated
-            // coordinate space.
-            rotatePoint(mViewport.orientation, x, y, mRawSurfaceWidth, mRawSurfaceHeight);
-        }
+        // Convert from InputReader's un-rotated coordinate space to PointerController's rotated
+        // coordinate space.
+        rotatePoint(mViewport.orientation, x, y, mDisplayWidth, mDisplayHeight);
 
         outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, x);
         outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 3340672..496491b 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -406,8 +406,8 @@
     virtual void dumpParameters(std::string& dump);
     virtual void configureRawPointerAxes();
     virtual void dumpRawPointerAxes(std::string& dump);
-    virtual void configureSurface(nsecs_t when, bool* outResetNeeded);
-    virtual void dumpSurface(std::string& dump);
+    virtual void configureInputDevice(nsecs_t when, bool* outResetNeeded);
+    virtual void dumpDisplay(std::string& dump);
     virtual void configureVirtualKeys();
     virtual void dumpVirtualKeys(std::string& dump);
     virtual void parseCalibration();
@@ -426,39 +426,27 @@
     // The components of the viewport are specified in the display's rotated orientation.
     DisplayViewport mViewport;
 
-    // The surface orientation, width and height set by configureSurface().
-    // The width and height are derived from the viewport but are specified
+    // The width and height are obtained from the viewport and are specified
     // in the natural orientation.
-    // They could be used for calculating diagonal, scaling factors, and virtual keys.
-    int32_t mRawSurfaceWidth;
-    int32_t mRawSurfaceHeight;
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
 
-    // The surface origin specifies how the surface coordinates should be translated
-    // to align with the logical display coordinate space.
-    // TODO(b/188939842): Remove surface coordinates when Per-Window Input Rotation is enabled.
-    int32_t mSurfaceLeft;
-    int32_t mSurfaceTop;
-    int32_t mSurfaceRight;
-    int32_t mSurfaceBottom;
-
-    // Similar to the surface coordinates, but in the raw display coordinate space rather than in
-    // the logical coordinate space.
+    // The physical frame is the rectangle in the display's coordinate space that maps to the
+    // the logical display frame.
     int32_t mPhysicalWidth;
     int32_t mPhysicalHeight;
     int32_t mPhysicalLeft;
     int32_t mPhysicalTop;
 
-    // The orientation may be different from the viewport orientation as it specifies
-    // the rotation of the surface coordinates required to produce the viewport's
-    // requested orientation, so it will depend on whether the device is orientation aware.
-    int32_t mSurfaceOrientation;
+    // The orientation of the input device relative to that of the display panel. It specifies
+    // the rotation of the input device coordinates required to produce the display panel
+    // orientation, so it will depend on whether the device is orientation aware.
+    int32_t mInputDeviceOrientation;
 
     // Translation and scaling factors, orientation-independent.
-    float mXTranslate;
     float mXScale;
     float mXPrecision;
 
-    float mYTranslate;
     float mYScale;
     float mYPrecision;
 
@@ -808,13 +796,13 @@
     // touchscreen.
     void updateTouchSpots();
 
-    bool isPointInsideSurface(int32_t x, int32_t y);
+    bool isPointInsidePhysicalFrame(int32_t x, int32_t y) const;
     const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y);
 
     static void assignPointerIds(const RawState& last, RawState& current);
 
     const char* modeToString(DeviceMode deviceMode);
-    void rotateAndScale(float& x, float& y);
+    void rotateAndScale(float& x, float& y) const;
 
     // Wrapper methods for interfacing with PointerController. These are used to convert points
     // between the coordinate spaces used by InputReader and PointerController, if they differ.
diff --git a/services/inputflinger/sysprop/Android.bp b/services/inputflinger/sysprop/Android.bp
deleted file mode 100644
index b9d65ee..0000000
--- a/services/inputflinger/sysprop/Android.bp
+++ /dev/null
@@ -1,15 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-}
-
-sysprop_library {
-    name: "InputFlingerProperties",
-    srcs: ["*.sysprop"],
-    api_packages: ["android.sysprop"],
-    property_owner: "Platform",
-}
diff --git a/services/inputflinger/sysprop/InputFlingerProperties.sysprop b/services/inputflinger/sysprop/InputFlingerProperties.sysprop
deleted file mode 100644
index 1c7e724..0000000
--- a/services/inputflinger/sysprop/InputFlingerProperties.sysprop
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 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.
-
-module: "android.sysprop.InputFlingerProperties"
-owner: Platform
-
-# When per-window-input-rotation is enabled, InputReader works in the un-rotated
-# display coordinate space, and the display rotation is encoded as part of the
-# input window transform that is sent from SurfaceFlinger to InputDispatcher.
-prop {
-    api_name: "per_window_input_rotation"
-    type: Boolean
-    scope: Internal
-    access: ReadWrite
-    prop_name: "persist.debug.per_window_input_rotation"
-}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index d8fd16c..515a01e 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -842,7 +842,6 @@
 
         FocusEvent* focusEvent = static_cast<FocusEvent*>(event);
         EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
-        EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode());
     }
 
     void consumeCaptureEvent(bool hasCapture) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 53b03ad..336afc6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -16,7 +16,6 @@
 
 #include <CursorInputMapper.h>
 #include <InputDevice.h>
-#include <InputFlingerProperties.sysprop.h>
 #include <InputMapper.h>
 #include <InputReader.h>
 #include <InputReaderBase.h>
@@ -2695,7 +2694,6 @@
     static const int32_t DEVICE_CONTROLLER_NUMBER;
     static const Flags<InputDeviceClass> DEVICE_CLASSES;
     static const int32_t EVENTHUB_ID;
-    static const std::optional<bool> INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE;
 
     std::shared_ptr<FakeEventHub> mFakeEventHub;
     sp<FakeInputReaderPolicy> mFakePolicy;
@@ -2713,18 +2711,12 @@
     }
 
     void SetUp() override {
-        // Ensure per_window_input_rotation is enabled.
-        sysprop::InputFlingerProperties::per_window_input_rotation(true);
-
         SetUp(DEVICE_CLASSES);
     }
 
     void TearDown() override {
         mFakeListener.reset();
         mFakePolicy.clear();
-
-        sysprop::InputFlingerProperties::per_window_input_rotation(
-                INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE);
     }
 
     void addConfigurationProperty(const char* key, const char* value) {
@@ -2836,8 +2828,6 @@
 const Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
         Flags<InputDeviceClass>(0); // not needed for current tests
 const int32_t InputMapperTest::EVENTHUB_ID = 1;
-const std::optional<bool> InputMapperTest::INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE =
-        sysprop::InputFlingerProperties::per_window_input_rotation();
 
 // --- SwitchInputMapperTest ---
 
diff --git a/services/sensorservice/ISensorHalWrapper.h b/services/sensorservice/ISensorHalWrapper.h
new file mode 100644
index 0000000..c9e089e
--- /dev/null
+++ b/services/sensorservice/ISensorHalWrapper.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_ISENSOR_HAL_WRAPPER_H
+#define ANDROID_ISENSOR_HAL_WRAPPER_H
+
+#include <hardware/sensors.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "SensorService.h"
+
+namespace android {
+
+/**
+ * A wrapper for various types of HAL implementation, e.g. to distinguish HIDL and AIDL versions.
+ */
+class ISensorHalWrapper {
+public:
+    class ICallback : public ISensorsCallback {
+
+        void onDynamicSensorsConnected(
+                const std::vector<sensor_t> &dynamicSensorsAdded) = 0;
+
+        void onDynamicSensorsDisconnected(
+                const std::vector<int32_t> &dynamicSensorHandlesRemoved) = 0;
+    };
+
+    /**
+     * Connects to the underlying sensors HAL. This should also be used for any reconnections
+     * due to HAL resets.
+     */
+    virtual bool connect(ICallback *callback) = 0;
+
+    /**
+     * Polls for available sensor events. This could be using the traditional sensors
+     * polling or from a FMQ.
+     */
+    virtual ssize_t poll(sensors_event_t* buffer, size_t count) = 0;
+
+    /**
+     * The below functions directly mirrors the sensors HAL definitions.
+     */
+    virtual std::vector<sensor_t> getSensorsList() = 0;
+
+    virtual status_t setOperationMode(SensorService::Mode mode) = 0;
+
+    virtual status_t activate(int32_t sensorHandle, bool enabled) = 0;
+
+    virtual status_t batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                           int64_t maxReportLatencyNs) = 0;
+
+    virtual status_t flush(int32_t sensorHandle) = 0;
+
+    virtual status_t injectSensorData(const sensors_event_t *event) = 0;
+
+    virtual status_t registerDirectChannel(const sensors_direct_mem_t *memory,
+                                           int32_t *channelHandle) = 0;
+
+    virtual void unregisterDirectChannel(int32_t channelHandle) = 0;
+
+    virtual status_t configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
+                                            const struct sensors_direct_cfg_t *config) = 0;
+}
+
+} // namespace android
+
+#endif // ANDROID_ISENSOR_HAL_WRAPPER_H
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index db1a1cc..c67acbf 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -23,31 +23,32 @@
 
 #include <android-base/logging.h>
 #include <android/util/ProtoOutputStream.h>
+#include <cutils/atomic.h>
 #include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
 #include <sensors/convert.h>
-#include <cutils/atomic.h>
 #include <utils/Errors.h>
 #include <utils/Singleton.h>
 
-#include <cstddef>
 #include <chrono>
 #include <cinttypes>
+#include <cstddef>
 #include <thread>
 
 using namespace android::hardware::sensors;
 using namespace android::hardware::sensors::V1_0;
 using namespace android::hardware::sensors::V1_0::implementation;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
 using android::hardware::sensors::V2_0::EventQueueFlagBits;
 using android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
 using android::hardware::sensors::V2_1::ISensorsCallback;
-using android::hardware::sensors::V2_1::implementation::convertToOldSensorInfo;
-using android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos;
 using android::hardware::sensors::V2_1::implementation::convertToNewEvents;
+using android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos;
+using android::hardware::sensors::V2_1::implementation::convertToOldSensorInfo;
+using android::hardware::sensors::V2_1::implementation::convertToSensor;
 using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV1_0;
 using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_0;
 using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_1;
-using android::hardware::hidl_vec;
-using android::hardware::Return;
 using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
 using android::util::ProtoOutputStream;
 
@@ -73,7 +74,7 @@
     }
 }
 
-template<typename EnumType>
+template <typename EnumType>
 constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
     return static_cast<typename std::underlying_type<EnumType>::type>(value);
 }
@@ -81,14 +82,13 @@
 // Used internally by the framework to wake the Event FMQ. These values must start after
 // the last value of EventQueueFlagBits
 enum EventQueueFlagBitsInternal : uint32_t {
-    INTERNAL_WAKE =  1 << 16,
+    INTERNAL_WAKE = 1 << 16,
 };
 
-}  // anonymous namespace
+} // anonymous namespace
 
 void SensorsHalDeathReceivier::serviceDied(
-        uint64_t /* cookie */,
-        const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
+        uint64_t /* cookie */, const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
     ALOGW("Sensors HAL died, attempting to reconnect.");
     SensorDevice::getInstance().prepareForReconnect();
 }
@@ -98,29 +98,36 @@
     using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
 
     Return<void> onDynamicSensorsConnected_2_1(
-            const hidl_vec<SensorInfo> &dynamicSensorsAdded) override {
-        return SensorDevice::getInstance().onDynamicSensorsConnected(dynamicSensorsAdded);
+            const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+        std::vector<sensor_t> sensors;
+        for (const V2_1::SensorInfo& info : dynamicSensorsAdded) {
+            sensor_t sensor;
+            convertToSensor(info, &sensor);
+            sensors.push_back(sensor);
+        }
+
+        SensorDevice::getInstance().onDynamicSensorsConnected(sensors);
+        return Return<void>();
     }
 
     Return<void> onDynamicSensorsConnected(
-            const hidl_vec<V1_0::SensorInfo> &dynamicSensorsAdded) override {
-        return SensorDevice::getInstance().onDynamicSensorsConnected(
-                convertToNewSensorInfos(dynamicSensorsAdded));
+            const hidl_vec<V1_0::SensorInfo>& dynamicSensorsAdded) override {
+        return onDynamicSensorsConnected_2_1(convertToNewSensorInfos(dynamicSensorsAdded));
     }
 
     Return<void> onDynamicSensorsDisconnected(
-            const hidl_vec<int32_t> &dynamicSensorHandlesRemoved) override {
-        return SensorDevice::getInstance().onDynamicSensorsDisconnected(
-                dynamicSensorHandlesRemoved);
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+        SensorDevice::getInstance().onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved);
+        return Return<void>();
     }
 };
 
 SensorDevice::SensorDevice()
-        : mHidlTransportErrors(20),
-          mRestartWaiter(new HidlServiceRegistrationWaiter()),
-          mEventQueueFlag(nullptr),
-          mWakeLockQueueFlag(nullptr),
-          mReconnecting(false) {
+      : mHidlTransportErrors(20),
+        mRestartWaiter(new HidlServiceRegistrationWaiter()),
+        mEventQueueFlag(nullptr),
+        mWakeLockQueueFlag(nullptr),
+        mReconnecting(false) {
     if (!connectHidlService()) {
         return;
     }
@@ -132,61 +139,59 @@
 }
 
 void SensorDevice::initializeSensorList() {
-    checkReturn(mSensors->getSensorsList(
-            [&](const auto &list) {
-                const size_t count = list.size();
+    checkReturn(mSensors->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
 
-                mActivationCount.setCapacity(count);
-                Info model;
-                for (size_t i=0 ; i < count; i++) {
-                    sensor_t sensor;
-                    convertToSensor(convertToOldSensorInfo(list[i]), &sensor);
+        mActivationCount.setCapacity(count);
+        Info model;
+        for (size_t i = 0; i < count; i++) {
+            sensor_t sensor;
+            convertToSensor(list[i], &sensor);
 
-                    if (sensor.type < static_cast<int>(SensorType::DEVICE_PRIVATE_BASE)) {
-                        sensor.resolution = SensorDeviceUtils::resolutionForSensor(sensor);
+            if (sensor.type < static_cast<int>(SensorType::DEVICE_PRIVATE_BASE)) {
+                sensor.resolution = SensorDeviceUtils::resolutionForSensor(sensor);
 
-                        // Some sensors don't have a default resolution and will be left at 0.
-                        // Don't crash in this case since CTS will verify that devices don't go to
-                        // production with a resolution of 0.
-                        if (sensor.resolution != 0) {
-                            float quantizedRange = sensor.maxRange;
-                            SensorDeviceUtils::quantizeValue(
-                                    &quantizedRange, sensor.resolution, /*factor=*/ 1);
-                            // Only rewrite maxRange if the requantization produced a "significant"
-                            // change, which is fairly arbitrarily defined as resolution / 8.
-                            // Smaller deltas are permitted, as they may simply be due to floating
-                            // point representation error, etc.
-                            if (fabsf(sensor.maxRange - quantizedRange) > sensor.resolution / 8) {
-                                ALOGW("%s's max range %.12f is not a multiple of the resolution "
-                                      "%.12f - updated to %.12f", sensor.name, sensor.maxRange,
-                                      sensor.resolution, quantizedRange);
-                                sensor.maxRange = quantizedRange;
-                            }
-                        } else {
-                            // Don't crash here or the device will go into a crashloop.
-                            ALOGW("%s should have a non-zero resolution", sensor.name);
-                        }
+                // Some sensors don't have a default resolution and will be left at 0.
+                // Don't crash in this case since CTS will verify that devices don't go to
+                // production with a resolution of 0.
+                if (sensor.resolution != 0) {
+                    float quantizedRange = sensor.maxRange;
+                    SensorDeviceUtils::quantizeValue(&quantizedRange, sensor.resolution,
+                                                     /*factor=*/1);
+                    // Only rewrite maxRange if the requantization produced a "significant"
+                    // change, which is fairly arbitrarily defined as resolution / 8.
+                    // Smaller deltas are permitted, as they may simply be due to floating
+                    // point representation error, etc.
+                    if (fabsf(sensor.maxRange - quantizedRange) > sensor.resolution / 8) {
+                        ALOGW("%s's max range %.12f is not a multiple of the resolution "
+                              "%.12f - updated to %.12f",
+                              sensor.name, sensor.maxRange, sensor.resolution, quantizedRange);
+                        sensor.maxRange = quantizedRange;
                     }
-
-                    // Check and clamp power if it is 0 (or close)
-                    constexpr float MIN_POWER_MA = 0.001; // 1 microAmp
-                    if (sensor.power < MIN_POWER_MA) {
-                        ALOGI("%s's reported power %f invalid, clamped to %f",
-                              sensor.name, sensor.power, MIN_POWER_MA);
-                        sensor.power = MIN_POWER_MA;
-                    }
-                    mSensorList.push_back(sensor);
-
-                    mActivationCount.add(list[i].sensorHandle, model);
-
-                    // Only disable all sensors on HAL 1.0 since HAL 2.0
-                    // handles this in its initialize method
-                    if (!mSensors->supportsMessageQueues()) {
-                        checkReturn(mSensors->activate(list[i].sensorHandle,
-                                    0 /* enabled */));
-                    }
+                } else {
+                    // Don't crash here or the device will go into a crashloop.
+                    ALOGW("%s should have a non-zero resolution", sensor.name);
                 }
-            }));
+            }
+
+            // Check and clamp power if it is 0 (or close)
+            constexpr float MIN_POWER_MA = 0.001; // 1 microAmp
+            if (sensor.power < MIN_POWER_MA) {
+                ALOGI("%s's reported power %f invalid, clamped to %f", sensor.name, sensor.power,
+                      MIN_POWER_MA);
+                sensor.power = MIN_POWER_MA;
+            }
+            mSensorList.push_back(sensor);
+
+            mActivationCount.add(list[i].sensorHandle, model);
+
+            // Only disable all sensors on HAL 1.0 since HAL 2.0
+            // handles this in its initialize method
+            if (!mSensors->supportsMessageQueues()) {
+                checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+            }
+        }
+    }));
 }
 
 SensorDevice::~SensorDevice() {
@@ -231,7 +236,7 @@
         // Poke ISensor service. If it has lingering connection from previous generation of
         // system server, it will kill itself. There is no intention to handle the poll result,
         // which will be done since the size is 0.
-        if(mSensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
+        if (mSensors->poll(0, [](auto, const auto&, const auto&) {}).isOk()) {
             // ok to continue
             connectionStatus = HalConnectionStatus::CONNECTED;
             break;
@@ -278,23 +283,23 @@
 SensorDevice::HalConnectionStatus SensorDevice::initializeHidlServiceV2_X() {
     HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
 
-    mWakeLockQueue = std::make_unique<WakeLockQueue>(
-            SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
-            true /* configureEventFlagWord */);
+    mWakeLockQueue =
+            std::make_unique<WakeLockQueue>(SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
+                                            true /* configureEventFlagWord */);
 
     hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
-    hardware::EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(), &mEventQueueFlag);
+    hardware::EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(),
+                                         &mEventQueueFlag);
 
     hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
-    hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(),
-                                            &mWakeLockQueueFlag);
+    hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakeLockQueueFlag);
 
-    CHECK(mSensors != nullptr && mWakeLockQueue != nullptr &&
-            mEventQueueFlag != nullptr && mWakeLockQueueFlag != nullptr);
+    CHECK(mSensors != nullptr && mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
+          mWakeLockQueueFlag != nullptr);
 
-    status_t status = checkReturnAndGetStatus(mSensors->initialize(
-            *mWakeLockQueue->getDesc(),
-            new SensorsCallback()));
+    mCallback = new SensorsCallback();
+    status_t status =
+            checkReturnAndGetStatus(mSensors->initialize(*mWakeLockQueue->getDesc(), mCallback));
 
     if (status != NO_ERROR) {
         connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
@@ -326,7 +331,7 @@
     mActivationCount.clear();
     mSensorList.clear();
 
-    if (connectHidlServiceV2_0() == HalConnectionStatus::CONNECTED) {
+    if (connectHidlService()) {
         initializeSensorList();
 
         if (sensorHandlesChanged(previousSensorList, mSensorList)) {
@@ -338,8 +343,8 @@
     mReconnecting = false;
 }
 
-bool SensorDevice::sensorHandlesChanged(const Vector<sensor_t>& oldSensorList,
-                                        const Vector<sensor_t>& newSensorList) {
+bool SensorDevice::sensorHandlesChanged(const std::vector<sensor_t>& oldSensorList,
+                                        const std::vector<sensor_t>& newSensorList) {
     bool didChange = false;
 
     if (oldSensorList.size() != newSensorList.size()) {
@@ -375,19 +380,17 @@
 bool SensorDevice::sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor) {
     bool equivalent = true;
     if (prevSensor.handle != newSensor.handle ||
-            (strcmp(prevSensor.vendor, newSensor.vendor) != 0) ||
-            (strcmp(prevSensor.stringType, newSensor.stringType) != 0) ||
-            (strcmp(prevSensor.requiredPermission, newSensor.requiredPermission) != 0) ||
-            (prevSensor.version != newSensor.version) ||
-            (prevSensor.type != newSensor.type) ||
-            (std::abs(prevSensor.maxRange - newSensor.maxRange) > 0.001f) ||
-            (std::abs(prevSensor.resolution - newSensor.resolution) > 0.001f) ||
-            (std::abs(prevSensor.power - newSensor.power) > 0.001f) ||
-            (prevSensor.minDelay != newSensor.minDelay) ||
-            (prevSensor.fifoReservedEventCount != newSensor.fifoReservedEventCount) ||
-            (prevSensor.fifoMaxEventCount != newSensor.fifoMaxEventCount) ||
-            (prevSensor.maxDelay != newSensor.maxDelay) ||
-            (prevSensor.flags != newSensor.flags)) {
+        (strcmp(prevSensor.vendor, newSensor.vendor) != 0) ||
+        (strcmp(prevSensor.stringType, newSensor.stringType) != 0) ||
+        (strcmp(prevSensor.requiredPermission, newSensor.requiredPermission) != 0) ||
+        (prevSensor.version != newSensor.version) || (prevSensor.type != newSensor.type) ||
+        (std::abs(prevSensor.maxRange - newSensor.maxRange) > 0.001f) ||
+        (std::abs(prevSensor.resolution - newSensor.resolution) > 0.001f) ||
+        (std::abs(prevSensor.power - newSensor.power) > 0.001f) ||
+        (prevSensor.minDelay != newSensor.minDelay) ||
+        (prevSensor.fifoReservedEventCount != newSensor.fifoReservedEventCount) ||
+        (prevSensor.fifoMaxEventCount != newSensor.fifoMaxEventCount) ||
+        (prevSensor.maxDelay != newSensor.maxDelay) || (prevSensor.flags != newSensor.flags)) {
         equivalent = false;
     }
     return equivalent;
@@ -405,7 +408,7 @@
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             const BatchParams& batchParams = info.batchParams[j];
             status_t res = batchLocked(info.batchParams.keyAt(j), handle, 0 /* flags */,
-                    batchParams.mTSample, batchParams.mTBatch);
+                                       batchParams.mTSample, batchParams.mTBatch);
 
             if (res == NO_ERROR) {
                 activateLocked(info.batchParams.keyAt(j), handle, true /* enabled */);
@@ -433,7 +436,7 @@
                         mSensorList.size(), mActivationCount.size(), mDisabledClients.size());
 
     Mutex::Autolock _l(mLock);
-    for (const auto & s : mSensorList) {
+    for (const auto& s : mSensorList) {
         int32_t handle = s.handle;
         const Info& info = mActivationCount.valueFor(handle);
         if (info.numActiveClients() == 0) continue;
@@ -444,8 +447,9 @@
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             const BatchParams& params = info.batchParams[j];
             result.appendFormat("%.1f%s%s", params.mTSample / 1e6f,
-                isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" : "",
-                (j < info.batchParams.size() - 1) ? ", " : "");
+                                isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)"
+                                                                                  : "",
+                                (j < info.batchParams.size() - 1) ? ", " : "");
         }
         result.appendFormat("}, selected = %.2f ms; ", info.bestBatchParams.mTSample / 1e6f);
 
@@ -453,8 +457,9 @@
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             const BatchParams& params = info.batchParams[j];
             result.appendFormat("%.1f%s%s", params.mTBatch / 1e6f,
-                    isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" : "",
-                    (j < info.batchParams.size() - 1) ? ", " : "");
+                                isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)"
+                                                                                  : "",
+                                (j < info.batchParams.size() - 1) ? ", " : "");
         }
         result.appendFormat("}, selected = %.2f ms\n", info.bestBatchParams.mTBatch / 1e6f);
     }
@@ -472,29 +477,29 @@
 void SensorDevice::dump(ProtoOutputStream* proto) const {
     using namespace service::SensorDeviceProto;
     if (mSensors == nullptr) {
-        proto->write(INITIALIZED , false);
+        proto->write(INITIALIZED, false);
         return;
     }
-    proto->write(INITIALIZED , true);
-    proto->write(TOTAL_SENSORS , int(mSensorList.size()));
-    proto->write(ACTIVE_SENSORS , int(mActivationCount.size()));
+    proto->write(INITIALIZED, true);
+    proto->write(TOTAL_SENSORS, int(mSensorList.size()));
+    proto->write(ACTIVE_SENSORS, int(mActivationCount.size()));
 
     Mutex::Autolock _l(mLock);
-    for (const auto & s : mSensorList) {
+    for (const auto& s : mSensorList) {
         int32_t handle = s.handle;
         const Info& info = mActivationCount.valueFor(handle);
         if (info.numActiveClients() == 0) continue;
 
         uint64_t token = proto->start(SENSORS);
-        proto->write(SensorProto::HANDLE , handle);
-        proto->write(SensorProto::ACTIVE_COUNT , int(info.batchParams.size()));
+        proto->write(SensorProto::HANDLE, handle);
+        proto->write(SensorProto::ACTIVE_COUNT, int(info.batchParams.size()));
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             const BatchParams& params = info.batchParams[j];
-            proto->write(SensorProto::SAMPLING_PERIOD_MS , params.mTSample / 1e6f);
-            proto->write(SensorProto::BATCHING_PERIOD_MS , params.mTBatch / 1e6f);
+            proto->write(SensorProto::SAMPLING_PERIOD_MS, params.mTSample / 1e6f);
+            proto->write(SensorProto::BATCHING_PERIOD_MS, params.mTBatch / 1e6f);
         }
-        proto->write(SensorProto::SAMPLING_PERIOD_SELECTED , info.bestBatchParams.mTSample / 1e6f);
-        proto->write(SensorProto::BATCHING_PERIOD_SELECTED , info.bestBatchParams.mTBatch / 1e6f);
+        proto->write(SensorProto::SAMPLING_PERIOD_SELECTED, info.bestBatchParams.mTSample / 1e6f);
+        proto->write(SensorProto::BATCHING_PERIOD_SELECTED, info.bestBatchParams.mTBatch / 1e6f);
         proto->end(token);
     }
 }
@@ -531,20 +536,19 @@
 
     do {
         auto ret = mSensors->poll(
-                count,
-                [&](auto result,
-                    const auto &events,
-                    const auto &dynamicSensorsAdded) {
+                count, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) {
                     if (result == Result::OK) {
                         convertToSensorEventsAndQuantize(convertToNewEvents(events),
-                                convertToNewSensorInfos(dynamicSensorsAdded), buffer);
+                                                         convertToNewSensorInfos(
+                                                                 dynamicSensorsAdded),
+                                                         buffer);
                         err = (ssize_t)events.size();
                     } else {
                         err = statusFromResult(result);
                     }
                 });
 
-        if (ret.isOk())  {
+        if (ret.isOk()) {
             hidlTransportError = false;
         } else {
             hidlTransportError = true;
@@ -559,7 +563,7 @@
         }
     } while (hidlTransportError);
 
-    if(numHidlTransportErrors > 0) {
+    if (numHidlTransportErrors > 0) {
         ALOGE("Saw %d Hidl transport failures", numHidlTransportErrors);
         HidlTransportErrorLog errLog(time(nullptr), numHidlTransportErrors);
         mHidlTransportErrors.add(errLog);
@@ -581,7 +585,8 @@
         // events is not available, then read() would return no events, possibly introducing
         // additional latency in delivering events to applications.
         mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS) |
-                              asBaseType(INTERNAL_WAKE), &eventFlagState);
+                                      asBaseType(INTERNAL_WAKE),
+                              &eventFlagState);
         availableEvents = mSensors->getEventQueue()->availableToRead();
 
         if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
@@ -600,47 +605,39 @@
             for (size_t i = 0; i < eventsToRead; i++) {
                 convertToSensorEvent(mEventBuffer[i], &buffer[i]);
                 android::SensorDeviceUtils::quantizeSensorEventValues(&buffer[i],
-                        getResolutionForSensor(buffer[i].sensor));
+                                                                      getResolutionForSensor(
+                                                                              buffer[i].sensor));
             }
             eventsRead = eventsToRead;
         } else {
-            ALOGW("Failed to read %zu events, currently %zu events available",
-                    eventsToRead, availableEvents);
+            ALOGW("Failed to read %zu events, currently %zu events available", eventsToRead,
+                  availableEvents);
         }
     }
 
     return eventsRead;
 }
 
-Return<void> SensorDevice::onDynamicSensorsConnected(
-        const hidl_vec<SensorInfo> &dynamicSensorsAdded) {
+void SensorDevice::onDynamicSensorsConnected(const std::vector<sensor_t>& dynamicSensorsAdded) {
     std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
 
     // Allocate a sensor_t structure for each dynamic sensor added and insert
     // it into the dictionary of connected dynamic sensors keyed by handle.
     for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) {
-        const SensorInfo &info = dynamicSensorsAdded[i];
+        const sensor_t& sensor = dynamicSensorsAdded[i];
 
-        auto it = mConnectedDynamicSensors.find(info.sensorHandle);
+        auto it = mConnectedDynamicSensors.find(sensor.handle);
         CHECK(it == mConnectedDynamicSensors.end());
 
-        sensor_t *sensor = new sensor_t();
-        convertToSensor(convertToOldSensorInfo(info), sensor);
-
-        mConnectedDynamicSensors.insert(
-                std::make_pair(sensor->handle, sensor));
+        mConnectedDynamicSensors.insert(std::make_pair(sensor.handle, sensor));
     }
 
     mDynamicSensorsCv.notify_all();
-
-    return Return<void>();
 }
 
-Return<void> SensorDevice::onDynamicSensorsDisconnected(
-        const hidl_vec<int32_t> &dynamicSensorHandlesRemoved) {
-    (void) dynamicSensorHandlesRemoved;
+void SensorDevice::onDynamicSensorsDisconnected(
+        const std::vector<int32_t>& /* dynamicSensorHandlesRemoved */) {
     // TODO: Currently dynamic sensors do not seem to be removed
-    return Return<void>();
 }
 
 void SensorDevice::writeWakeLockHandled(uint32_t count) {
@@ -653,7 +650,7 @@
     }
 }
 
-void SensorDevice::autoDisable(void *ident, int handle) {
+void SensorDevice::autoDisable(void* ident, int handle) {
     Mutex::Autolock _l(mLock);
     ssize_t activationIndex = mActivationCount.indexOfKey(handle);
     if (activationIndex < 0) {
@@ -687,15 +684,15 @@
     Info& info(mActivationCount.editValueAt(activationIndex));
 
     ALOGD_IF(DEBUG_CONNECTIONS,
-             "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu",
-             ident, handle, enabled, info.batchParams.size());
+             "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu", ident,
+             handle, enabled, info.batchParams.size());
 
     if (enabled) {
         ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident));
 
         if (isClientDisabledLocked(ident)) {
-            ALOGW("SensorDevice::activate, isClientDisabledLocked(%p):true, handle:%d",
-                    ident, handle);
+            ALOGW("SensorDevice::activate, isClientDisabledLocked(%p):true, handle:%d", ident,
+                  handle);
             return NO_ERROR;
         }
 
@@ -714,7 +711,6 @@
         // dictionary.
         auto it = mConnectedDynamicSensors.find(handle);
         if (it != mConnectedDynamicSensors.end()) {
-            delete it->second;
             mConnectedDynamicSensors.erase(it);
         }
 
@@ -726,11 +722,10 @@
                 // Call batch for this sensor with the previously calculated best effort
                 // batch_rate and timeout. One of the apps has unregistered for sensor
                 // events, and the best effort batch parameters might have changed.
-                ALOGD_IF(DEBUG_CONNECTIONS,
-                         "\t>>> actuating h/w batch 0x%08x %" PRId64 " %" PRId64, handle,
-                         info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
-                checkReturn(mSensors->batch(
-                        handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch));
+                ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w batch 0x%08x %" PRId64 " %" PRId64,
+                         handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
+                checkReturn(mSensors->batch(handle, info.bestBatchParams.mTSample,
+                                            info.bestBatchParams.mTBatch));
             }
         } else {
             // sensor wasn't enabled for this ident
@@ -767,12 +762,8 @@
     return err;
 }
 
-status_t SensorDevice::batch(
-        void* ident,
-        int handle,
-        int flags,
-        int64_t samplingPeriodNs,
-        int64_t maxBatchReportLatencyNs) {
+status_t SensorDevice::batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
+                             int64_t maxBatchReportLatencyNs) {
     if (mSensors == nullptr) return NO_INIT;
 
     if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
@@ -783,7 +774,8 @@
     }
 
     ALOGD_IF(DEBUG_CONNECTIONS,
-             "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64,
+             "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64
+             " timeout=%" PRId64,
              ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
 
     Mutex::Autolock _l(mLock);
@@ -807,25 +799,24 @@
         info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs);
     }
 
-    status_t err =  updateBatchParamsLocked(handle, info);
+    status_t err = updateBatchParamsLocked(handle, info);
     if (err != NO_ERROR) {
-        ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s",
-              mSensors.get(), handle, info.bestBatchParams.mTSample,
-              info.bestBatchParams.mTBatch, strerror(-err));
+        ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s", mSensors.get(),
+              handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch, strerror(-err));
         info.removeBatchParamsForIdent(ident);
     }
 
     return err;
 }
 
-status_t SensorDevice::updateBatchParamsLocked(int handle, Info &info) {
+status_t SensorDevice::updateBatchParamsLocked(int handle, Info& info) {
     BatchParams prevBestBatchParams = info.bestBatchParams;
     // Find the minimum of all timeouts and batch_rates for this sensor.
     info.selectBatchParams();
 
     ALOGD_IF(DEBUG_CONNECTIONS,
-             "\t>>> curr_period=%" PRId64 " min_period=%" PRId64
-             " curr_timeout=%" PRId64 " min_timeout=%" PRId64,
+             "\t>>> curr_period=%" PRId64 " min_period=%" PRId64 " curr_timeout=%" PRId64
+             " min_timeout=%" PRId64,
              prevBestBatchParams.mTSample, info.bestBatchParams.mTSample,
              prevBestBatchParams.mTBatch, info.bestBatchParams.mTBatch);
 
@@ -834,8 +825,8 @@
     if (prevBestBatchParams != info.bestBatchParams && info.numActiveClients() > 0) {
         ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH 0x%08x %" PRId64 " %" PRId64, handle,
                  info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
-        err = checkReturnAndGetStatus(mSensors->batch(
-                handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch));
+        err = checkReturnAndGetStatus(mSensors->batch(handle, info.bestBatchParams.mTSample,
+                                                      info.bestBatchParams.mTBatch));
     }
 
     return err;
@@ -866,8 +857,8 @@
     return mDisabledClients.count(ident) > 0;
 }
 
-std::vector<void *> SensorDevice::getDisabledClientsLocked() const {
-    std::vector<void *> vec;
+std::vector<void*> SensorDevice::getDisabledClientsLocked() const {
+    std::vector<void*> vec;
     for (const auto& it : mDisabledClients) {
         vec.push_back(it.first);
     }
@@ -896,7 +887,7 @@
         addDisabledReasonForIdentLocked(ident, DisabledReason::DISABLED_REASON_UID_IDLE);
     }
 
-    for (size_t i = 0; i< mActivationCount.size(); ++i) {
+    for (size_t i = 0; i < mActivationCount.size(); ++i) {
         int handle = mActivationCount.keyAt(i);
         Info& info = mActivationCount.editValueAt(i);
 
@@ -905,8 +896,7 @@
             bool disable = info.numActiveClients() == 0 && info.isActive;
             bool enable = info.numActiveClients() > 0 && !info.isActive;
 
-            if ((enable || disable) &&
-                doActivateHardwareLocked(handle, enable) == NO_ERROR) {
+            if ((enable || disable) && doActivateHardwareLocked(handle, enable) == NO_ERROR) {
                 info.isActive = enable;
             }
         }
@@ -941,22 +931,21 @@
     if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
 
-    for (void *client : getDisabledClientsLocked()) {
-        removeDisabledReasonForIdentLocked(
-            client, DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED);
+    for (void* client : getDisabledClientsLocked()) {
+        removeDisabledReasonForIdentLocked(client,
+                                           DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED);
     }
 
-    for (size_t i = 0; i< mActivationCount.size(); ++i) {
+    for (size_t i = 0; i < mActivationCount.size(); ++i) {
         Info& info = mActivationCount.editValueAt(i);
         if (info.batchParams.isEmpty()) continue;
         info.selectBatchParams();
         const int sensor_handle = mActivationCount.keyAt(i);
         ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
-                   sensor_handle);
-        status_t err = checkReturnAndGetStatus(mSensors->batch(
-                sensor_handle,
-                info.bestBatchParams.mTSample,
-                info.bestBatchParams.mTBatch));
+                 sensor_handle);
+        status_t err = checkReturnAndGetStatus(mSensors->batch(sensor_handle,
+                                                               info.bestBatchParams.mTSample,
+                                                               info.bestBatchParams.mTBatch));
         ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
 
         if (err == NO_ERROR) {
@@ -973,38 +962,36 @@
 void SensorDevice::disableAllSensors() {
     if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
-    for (size_t i = 0; i< mActivationCount.size(); ++i) {
+    for (size_t i = 0; i < mActivationCount.size(); ++i) {
         Info& info = mActivationCount.editValueAt(i);
         // Check if this sensor has been activated previously and disable it.
         if (info.batchParams.size() > 0) {
-           const int sensor_handle = mActivationCount.keyAt(i);
-           ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
-                   sensor_handle);
-           checkReturn(mSensors->activate(sensor_handle, 0 /* enabled */));
+            const int sensor_handle = mActivationCount.keyAt(i);
+            ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
+                     sensor_handle);
+            checkReturn(mSensors->activate(sensor_handle, 0 /* enabled */));
 
-           // Add all the connections that were registered for this sensor to the disabled
-           // clients list.
-           for (size_t j = 0; j < info.batchParams.size(); ++j) {
-               addDisabledReasonForIdentLocked(
-                   info.batchParams.keyAt(j), DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED);
-               ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j));
-           }
+            // Add all the connections that were registered for this sensor to the disabled
+            // clients list.
+            for (size_t j = 0; j < info.batchParams.size(); ++j) {
+                addDisabledReasonForIdentLocked(info.batchParams.keyAt(j),
+                                                DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED);
+                ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j));
+            }
 
-           info.isActive = false;
+            info.isActive = false;
         }
     }
 }
 
-status_t SensorDevice::injectSensorData(
-        const sensors_event_t *injected_sensor_event) {
+status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) {
     if (mSensors == nullptr) return NO_INIT;
     ALOGD_IF(DEBUG_CONNECTIONS,
-            "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
-            injected_sensor_event->sensor,
-            injected_sensor_event->timestamp, injected_sensor_event->data[0],
-            injected_sensor_event->data[1], injected_sensor_event->data[2],
-            injected_sensor_event->data[3], injected_sensor_event->data[4],
-            injected_sensor_event->data[5]);
+             "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+             injected_sensor_event->sensor, injected_sensor_event->timestamp,
+             injected_sensor_event->data[0], injected_sensor_event->data[1],
+             injected_sensor_event->data[2], injected_sensor_event->data[3],
+             injected_sensor_event->data[4], injected_sensor_event->data[5]);
 
     Event ev;
     V2_1::implementation::convertFromSensorEvent(*injected_sensor_event, &ev);
@@ -1014,8 +1001,8 @@
 
 status_t SensorDevice::setMode(uint32_t mode) {
     if (mSensors == nullptr) return NO_INIT;
-    return checkReturnAndGetStatus(mSensors->setOperationMode(
-            static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
+    return checkReturnAndGetStatus(
+            mSensors->setOperationMode(static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
 }
 
 int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
@@ -1041,21 +1028,20 @@
     format = SharedMemFormat::SENSORS_EVENT;
 
     SharedMemInfo mem = {
-        .type = type,
-        .format = format,
-        .size = static_cast<uint32_t>(memory->size),
-        .memoryHandle = memory->handle,
+            .type = type,
+            .format = format,
+            .size = static_cast<uint32_t>(memory->size),
+            .memoryHandle = memory->handle,
     };
 
     int32_t ret;
-    checkReturn(mSensors->registerDirectChannel(mem,
-            [&ret](auto result, auto channelHandle) {
-                if (result == Result::OK) {
-                    ret = channelHandle;
-                } else {
-                    ret = statusFromResult(result);
-                }
-            }));
+    checkReturn(mSensors->registerDirectChannel(mem, [&ret](auto result, auto channelHandle) {
+        if (result == Result::OK) {
+            ret = channelHandle;
+        } else {
+            ret = statusFromResult(result);
+        }
+    }));
     return ret;
 }
 
@@ -1065,13 +1051,13 @@
     checkReturn(mSensors->unregisterDirectChannel(channelHandle));
 }
 
-int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
-        int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
+int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
+                                             const struct sensors_direct_cfg_t* config) {
     if (mSensors == nullptr) return NO_INIT;
     Mutex::Autolock _l(mLock);
 
     RateLevel rate;
-    switch(config->rate_level) {
+    switch (config->rate_level) {
         case SENSOR_DIRECT_RATE_STOP:
             rate = RateLevel::STOP;
             break;
@@ -1090,17 +1076,17 @@
 
     int32_t ret;
     checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
-            [&ret, rate] (auto result, auto token) {
-                if (rate == RateLevel::STOP) {
-                    ret = statusFromResult(result);
-                } else {
-                    if (result == Result::OK) {
-                        ret = token;
-                    } else {
-                        ret = statusFromResult(result);
-                    }
-                }
-            }));
+                                             [&ret, rate](auto result, auto token) {
+                                                 if (rate == RateLevel::STOP) {
+                                                     ret = statusFromResult(result);
+                                                 } else {
+                                                     if (result == Result::OK) {
+                                                         ret = token;
+                                                     } else {
+                                                         ret = statusFromResult(result);
+                                                     }
+                                                 }
+                                             }));
 
     return ret;
 }
@@ -1118,13 +1104,12 @@
     return num;
 }
 
-status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int,
-                                                    int64_t samplingPeriodNs,
+status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int, int64_t samplingPeriodNs,
                                                     int64_t maxBatchReportLatencyNs) {
     ssize_t index = batchParams.indexOfKey(ident);
     if (index < 0) {
-        ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64
-              " timeout=%" PRId64 ") failed (%s)",
+        ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 " timeout=%" PRId64
+              ") failed (%s)",
               ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index));
         return BAD_INDEX;
     }
@@ -1168,12 +1153,11 @@
     return mIsDirectReportSupported;
 }
 
-void SensorDevice::convertToSensorEvent(
-        const Event &src, sensors_event_t *dst) {
+void SensorDevice::convertToSensorEvent(const Event& src, sensors_event_t* dst) {
     V2_1::implementation::convertToSensorEvent(src, dst);
 
     if (src.sensorType == V2_1::SensorType::DYNAMIC_SENSOR_META) {
-        const DynamicSensorInfo &dyn = src.u.dynamic;
+        const DynamicSensorInfo& dyn = src.u.dynamic;
 
         dst->dynamic_sensor_meta.connected = dyn.connected;
         dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
@@ -1184,56 +1168,53 @@
             // marks it as oneway.
             auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
             if (it == mConnectedDynamicSensors.end()) {
-                mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT,
-                        [&, dyn]{
-                            return mConnectedDynamicSensors.find(dyn.sensorHandle)
-                                    != mConnectedDynamicSensors.end();
+                mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, [&, dyn] {
+                    return mConnectedDynamicSensors.find(dyn.sensorHandle) !=
+                            mConnectedDynamicSensors.end();
                 });
                 it = mConnectedDynamicSensors.find(dyn.sensorHandle);
                 CHECK(it != mConnectedDynamicSensors.end());
             }
 
-            dst->dynamic_sensor_meta.sensor = it->second;
+            dst->dynamic_sensor_meta.sensor = &it->second;
 
-            memcpy(dst->dynamic_sensor_meta.uuid,
-                   dyn.uuid.data(),
+            memcpy(dst->dynamic_sensor_meta.uuid, dyn.uuid.data(),
                    sizeof(dst->dynamic_sensor_meta.uuid));
         }
     }
 }
 
-void SensorDevice::convertToSensorEventsAndQuantize(
-        const hidl_vec<Event> &src,
-        const hidl_vec<SensorInfo> &dynamicSensorsAdded,
-        sensors_event_t *dst) {
-
-    if (dynamicSensorsAdded.size() > 0) {
-        onDynamicSensorsConnected(dynamicSensorsAdded);
+void SensorDevice::convertToSensorEventsAndQuantize(const hidl_vec<Event>& src,
+                                                    const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+                                                    sensors_event_t* dst) {
+    if (dynamicSensorsAdded.size() > 0 && mCallback != nullptr) {
+        mCallback->onDynamicSensorsConnected_2_1(dynamicSensorsAdded);
     }
 
     for (size_t i = 0; i < src.size(); ++i) {
         V2_1::implementation::convertToSensorEvent(src[i], &dst[i]);
         android::SensorDeviceUtils::quantizeSensorEventValues(&dst[i],
-                getResolutionForSensor(dst[i].sensor));
+                                                              getResolutionForSensor(
+                                                                      dst[i].sensor));
     }
 }
 
 float SensorDevice::getResolutionForSensor(int sensorHandle) {
     for (size_t i = 0; i < mSensorList.size(); i++) {
-      if (sensorHandle == mSensorList[i].handle) {
-        return mSensorList[i].resolution;
-      }
+        if (sensorHandle == mSensorList[i].handle) {
+            return mSensorList[i].resolution;
+        }
     }
 
     auto it = mConnectedDynamicSensors.find(sensorHandle);
     if (it != mConnectedDynamicSensors.end()) {
-      return it->second->resolution;
+        return it->second.resolution;
     }
 
     return 0;
 }
 
-void SensorDevice::handleHidlDeath(const std::string & detail) {
+void SensorDevice::handleHidlDeath(const std::string& detail) {
     if (!mSensors->supportsMessageQueues()) {
         // restart is the only option at present.
         LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index bc8d20f..314ddb8 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -17,14 +17,14 @@
 #ifndef ANDROID_SENSOR_DEVICE_H
 #define ANDROID_SENSOR_DEVICE_H
 
+#include "ISensorsWrapper.h"
 #include "SensorDeviceUtils.h"
 #include "SensorService.h"
 #include "SensorServiceUtils.h"
-#include "ISensorsWrapper.h"
 
 #include <fmq/MessageQueue.h>
-#include <sensor/SensorEventQueue.h>
 #include <sensor/Sensor.h>
+#include <sensor/SensorEventQueue.h>
 #include <stdint.h>
 #include <sys/types.h>
 #include <utils/KeyedVector.h>
@@ -32,9 +32,10 @@
 #include <utils/String8.h>
 #include <utils/Timers.h>
 
+#include <algorithm> //std::max std::min
 #include <string>
 #include <unordered_map>
-#include <algorithm> //std::max std::min
+#include <vector>
 
 #include "RingBuffer.h"
 
@@ -42,18 +43,18 @@
 
 namespace android {
 
+using Result = ::android::hardware::sensors::V1_0::Result;
+
 // ---------------------------------------------------------------------------
 class SensorsHalDeathReceivier : public android::hardware::hidl_death_recipient {
     virtual void serviceDied(uint64_t cookie,
                              const wp<::android::hidl::base::V1_0::IBase>& service) override;
 };
 
-class SensorDevice : public Singleton<SensorDevice>,
-                     public SensorServiceUtil::Dumpable {
+class SensorDevice : public Singleton<SensorDevice>, public SensorServiceUtil::Dumpable {
 public:
     class HidlTransportErrorLog {
-     public:
-
+    public:
         HidlTransportErrorLog() {
             mTs = 0;
             mCount = 0;
@@ -66,7 +67,7 @@
 
         String8 toString() const {
             String8 result;
-            struct tm *timeInfo = localtime(&mTs);
+            struct tm* timeInfo = localtime(&mTs);
             result.appendFormat("%02d:%02d:%02d :: %d", timeInfo->tm_hour, timeInfo->tm_min,
                                 timeInfo->tm_sec, mCount);
             return result;
@@ -74,7 +75,7 @@
 
     private:
         time_t mTs; // timestamp of the error
-        int mCount;   // number of transport errors observed
+        int mCount; // number of transport errors observed
     };
 
     ~SensorDevice();
@@ -99,29 +100,24 @@
     status_t setMode(uint32_t mode);
 
     bool isDirectReportSupported() const;
-    int32_t registerDirectChannel(const sensors_direct_mem_t *memory);
+    int32_t registerDirectChannel(const sensors_direct_mem_t* memory);
     void unregisterDirectChannel(int32_t channelHandle);
-    int32_t configureDirectChannel(int32_t sensorHandle,
-            int32_t channelHandle, const struct sensors_direct_cfg_t *config);
+    int32_t configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
+                                   const struct sensors_direct_cfg_t* config);
 
     void disableAllSensors();
     void enableAllSensors();
-    void autoDisable(void *ident, int handle);
+    void autoDisable(void* ident, int handle);
 
-    status_t injectSensorData(const sensors_event_t *event);
-    void notifyConnectionDestroyed(void *ident);
+    status_t injectSensorData(const sensors_event_t* event);
+    void notifyConnectionDestroyed(void* ident);
 
-    using Result = ::android::hardware::sensors::V1_0::Result;
-    hardware::Return<void> onDynamicSensorsConnected(
-            const hardware::hidl_vec<hardware::sensors::V2_1::SensorInfo> &dynamicSensorsAdded);
-    hardware::Return<void> onDynamicSensorsDisconnected(
-            const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved);
+    void onDynamicSensorsConnected(const std::vector<sensor_t>& dynamicSensorsAdded);
+    void onDynamicSensorsDisconnected(const std::vector<int32_t>& dynamicSensorHandlesRemoved);
 
     void setUidStateForConnection(void* ident, SensorService::UidState state);
 
-    bool isReconnecting() const {
-        return mReconnecting;
-    }
+    bool isReconnecting() const { return mReconnecting; }
 
     bool isSensorActive(int handle) const;
 
@@ -132,12 +128,14 @@
     // Dumpable
     virtual std::string dump() const override;
     virtual void dump(util::ProtoOutputStream* proto) const override;
+
 private:
     friend class Singleton<SensorDevice>;
 
     sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors;
-    Vector<sensor_t> mSensorList;
-    std::unordered_map<int32_t, sensor_t*> mConnectedDynamicSensors;
+    sp<::android::hardware::sensors::V2_1::ISensorsCallback> mCallback;
+    std::vector<sensor_t> mSensorList;
+    std::unordered_map<int32_t, sensor_t> mConnectedDynamicSensors;
 
     // A bug in the Sensors HIDL spec which marks onDynamicSensorsConnected as oneway causes dynamic
     // meta events and onDynamicSensorsConnected to be received out of order. This mutex + CV are
@@ -147,26 +145,26 @@
     std::condition_variable mDynamicSensorsCv;
     static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5};
 
-    static const nsecs_t MINIMUM_EVENTS_PERIOD =   1000000; // 1000 Hz
-    mutable Mutex mLock; // protect mActivationCount[].batchParams
+    static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
+    mutable Mutex mLock;                                  // protect mActivationCount[].batchParams
     // fixed-size array after construction
 
     // Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from
     // batch call. For continous mode clients, maxBatchReportLatency is set to zero.
     struct BatchParams {
-      nsecs_t mTSample, mTBatch;
-      BatchParams() : mTSample(INT64_MAX), mTBatch(INT64_MAX) {}
-      BatchParams(nsecs_t tSample, nsecs_t tBatch): mTSample(tSample), mTBatch(tBatch) {}
-      bool operator != (const BatchParams& other) {
-          return !(mTSample == other.mTSample && mTBatch == other.mTBatch);
-      }
-      // Merge another parameter with this one. The updated mTSample will be the min of the two.
-      // The update mTBatch will be the min of original mTBatch and the apparent batch period
-      // of the other. the apparent batch is the maximum of mTBatch and mTSample,
-      void merge(const BatchParams &other) {
-          mTSample = std::min(mTSample, other.mTSample);
-          mTBatch = std::min(mTBatch, std::max(other.mTBatch, other.mTSample));
-      }
+        nsecs_t mTSample, mTBatch;
+        BatchParams() : mTSample(INT64_MAX), mTBatch(INT64_MAX) {}
+        BatchParams(nsecs_t tSample, nsecs_t tBatch) : mTSample(tSample), mTBatch(tBatch) {}
+        bool operator!=(const BatchParams& other) {
+            return !(mTSample == other.mTSample && mTBatch == other.mTBatch);
+        }
+        // Merge another parameter with this one. The updated mTSample will be the min of the two.
+        // The update mTBatch will be the min of original mTBatch and the apparent batch period
+        // of the other. the apparent batch is the maximum of mTBatch and mTSample,
+        void merge(const BatchParams& other) {
+            mTSample = std::min(mTSample, other.mTSample);
+            mTBatch = std::min(mTBatch, std::max(other.mTBatch, other.mTSample));
+        }
     };
 
     // Store batch parameters in the KeyedVector and the optimal batch_rate and timeout in
@@ -224,7 +222,7 @@
     static_assert(DisabledReason::DISABLED_REASON_MAX < sizeof(uint8_t) * CHAR_BIT);
 
     // Use this map to determine which client is activated or deactivated.
-    std::unordered_map<void *, uint8_t> mDisabledClients;
+    std::unordered_map<void*, uint8_t> mDisabledClients;
 
     void addDisabledReasonForIdentLocked(void* ident, DisabledReason reason);
     void removeDisabledReasonForIdentLocked(void* ident, DisabledReason reason);
@@ -233,13 +231,13 @@
     bool connectHidlService();
     void initializeSensorList();
     void reactivateSensors(const DefaultKeyedVector<int, Info>& previousActivations);
-    static bool sensorHandlesChanged(const Vector<sensor_t>& oldSensorList,
-                                     const Vector<sensor_t>& newSensorList);
+    static bool sensorHandlesChanged(const std::vector<sensor_t>& oldSensorList,
+                                     const std::vector<sensor_t>& newSensorList);
     static bool sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor);
 
     enum HalConnectionStatus {
-        CONNECTED, // Successfully connected to the HAL
-        DOES_NOT_EXIST, // Could not find the HAL
+        CONNECTED,         // Successfully connected to the HAL
+        DOES_NOT_EXIST,    // Could not find the HAL
         FAILED_TO_CONNECT, // Found the HAL but failed to connect/initialize
         UNKNOWN,
     };
@@ -257,32 +255,32 @@
     status_t updateBatchParamsLocked(int handle, Info& info);
     status_t doActivateHardwareLocked(int handle, bool enable);
 
-    void handleHidlDeath(const std::string &detail);
-    template<typename T>
+    void handleHidlDeath(const std::string& detail);
+    template <typename T>
     void checkReturn(const Return<T>& ret) {
         if (!ret.isOk()) {
             handleHidlDeath(ret.description());
         }
     }
+
     status_t checkReturnAndGetStatus(const Return<Result>& ret);
-    //TODO(b/67425500): remove waiter after bug is resolved.
+    // TODO(b/67425500): remove waiter after bug is resolved.
     sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
 
     bool isClientDisabled(void* ident) const;
     bool isClientDisabledLocked(void* ident) const;
-    std::vector<void *> getDisabledClientsLocked() const;
+    std::vector<void*> getDisabledClientsLocked() const;
 
     bool clientHasNoAccessLocked(void* ident) const;
 
     using Event = hardware::sensors::V2_1::Event;
     using SensorInfo = hardware::sensors::V2_1::SensorInfo;
 
-    void convertToSensorEvent(const Event &src, sensors_event_t *dst);
+    void convertToSensorEvent(const Event& src, sensors_event_t* dst);
 
-    void convertToSensorEventsAndQuantize(
-            const hardware::hidl_vec<Event> &src,
-            const hardware::hidl_vec<SensorInfo> &dynamicSensorsAdded,
-            sensors_event_t *dst);
+    void convertToSensorEventsAndQuantize(const hardware::hidl_vec<Event>& src,
+                                          const hardware::hidl_vec<SensorInfo>& dynamicSensorsAdded,
+                                          sensors_event_t* dst);
 
     float getResolutionForSensor(int sensorHandle);
 
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 32a0110..9bc7b8e 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -164,7 +164,6 @@
         sensor_t const* list;
         ssize_t count = dev.getSensorList(&list);
         if (count > 0) {
-            ssize_t orientationIndex = -1;
             bool hasGyro = false, hasAccel = false, hasMag = false;
             uint32_t virtualSensorsNeeds =
                     (1<<SENSOR_TYPE_GRAVITY) |
@@ -183,9 +182,6 @@
                     case SENSOR_TYPE_MAGNETIC_FIELD:
                         hasMag = true;
                         break;
-                    case SENSOR_TYPE_ORIENTATION:
-                        orientationIndex = i;
-                        break;
                     case SENSOR_TYPE_GYROSCOPE:
                     case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
                         hasGyro = true;
@@ -201,6 +197,8 @@
                             virtualSensorsNeeds &= ~(1<<list[i].type);
                         }
                         break;
+                    default:
+                        break;
                 }
                 if (useThisSensor) {
                     if (list[i].type == SENSOR_TYPE_PROXIMITY) {
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b059e61..9b6d01a 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -89,6 +89,52 @@
       UID_STATE_IDLE,
     };
 
+    enum Mode {
+       // The regular operating mode where any application can register/unregister/call flush on
+       // sensors.
+       NORMAL = 0,
+       // This mode is only used for testing purposes. Not all HALs support this mode. In this mode,
+       // the HAL ignores the sensor data provided by physical sensors and accepts the data that is
+       // injected from the SensorService as if it were the real sensor data. This mode is primarily
+       // used for testing various algorithms like vendor provided SensorFusion, Step Counter and
+       // Step Detector etc. Typically in this mode, there will be a client (a
+       // SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps can
+       // unregister and register for any sensor that supports injection. Registering to sensors
+       // that do not support injection will give an error.  TODO: Allow exactly one
+       // client to inject sensor data at a time.
+       DATA_INJECTION = 1,
+       // This mode is used only for testing sensors. Each sensor can be tested in isolation with
+       // the required sampling_rate and maxReportLatency parameters without having to think about
+       // the data rates requested by other applications. End user devices are always expected to be
+       // in NORMAL mode. When this mode is first activated, all active sensors from all connections
+       // are disabled. Calling flush() will return an error. In this mode, only the requests from
+       // selected apps whose package names are allowlisted are allowed (typically CTS apps).  Only
+       // these apps can register/unregister/call flush() on sensors. If SensorService switches to
+       // NORMAL mode again, all sensors that were previously registered to are activated with the
+       // corresponding parameters if the application hasn't unregistered for sensors in the mean
+       // time.  NOTE: Non allowlisted app whose sensors were previously deactivated may still
+       // receive events if a allowlisted app requests data from the same sensor.
+       RESTRICTED = 2
+
+      // State Transitions supported.
+      //     RESTRICTED   <---  NORMAL   ---> DATA_INJECTION
+      //                  --->           <---
+
+      // Shell commands to switch modes in SensorService.
+      // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in
+      // restricted mode it is treated as a NO_OP (and packageName is NOT changed).
+      //
+      //     $ adb shell dumpsys sensorservice restrict .cts.
+      //
+      // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in
+      // data_injection mode it is treated as a NO_OP (and packageName is NOT changed).
+      //
+      //     $ adb shell dumpsys sensorservice data_injection .xts.
+      //
+      // 3) Reset sensorservice back to NORMAL mode.
+      //     $ adb shell dumpsys sensorservice enable
+    };
+
     class ProximityActiveListener : public virtual RefBase {
     public:
         // Note that the callback is invoked from an async thread and can interact with the
@@ -276,52 +322,6 @@
             const int64_t mToken;
     };
 
-    enum Mode {
-       // The regular operating mode where any application can register/unregister/call flush on
-       // sensors.
-       NORMAL = 0,
-       // This mode is only used for testing purposes. Not all HALs support this mode. In this mode,
-       // the HAL ignores the sensor data provided by physical sensors and accepts the data that is
-       // injected from the SensorService as if it were the real sensor data. This mode is primarily
-       // used for testing various algorithms like vendor provided SensorFusion, Step Counter and
-       // Step Detector etc. Typically in this mode, there will be a client (a
-       // SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps can
-       // unregister and register for any sensor that supports injection. Registering to sensors
-       // that do not support injection will give an error.  TODO(aakella) : Allow exactly one
-       // client to inject sensor data at a time.
-       DATA_INJECTION = 1,
-       // This mode is used only for testing sensors. Each sensor can be tested in isolation with
-       // the required sampling_rate and maxReportLatency parameters without having to think about
-       // the data rates requested by other applications. End user devices are always expected to be
-       // in NORMAL mode. When this mode is first activated, all active sensors from all connections
-       // are disabled. Calling flush() will return an error. In this mode, only the requests from
-       // selected apps whose package names are whitelisted are allowed (typically CTS apps).  Only
-       // these apps can register/unregister/call flush() on sensors. If SensorService switches to
-       // NORMAL mode again, all sensors that were previously registered to are activated with the
-       // corresponding paramaters if the application hasn't unregistered for sensors in the mean
-       // time.  NOTE: Non whitelisted app whose sensors were previously deactivated may still
-       // receive events if a whitelisted app requests data from the same sensor.
-       RESTRICTED = 2
-
-      // State Transitions supported.
-      //     RESTRICTED   <---  NORMAL   ---> DATA_INJECTION
-      //                  --->           <---
-
-      // Shell commands to switch modes in SensorService.
-      // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in
-      // restricted mode it is treated as a NO_OP (and packageName is NOT changed).
-      //
-      //     $ adb shell dumpsys sensorservice restrict .cts.
-      //
-      // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in
-      // data_injection mode it is treated as a NO_OP (and packageName is NOT changed).
-      //
-      //     $ adb shell dumpsys sensorservice data_injection .xts.
-      //
-      // 3) Reset sensorservice back to NORMAL mode.
-      //     $ adb shell dumpsys sensorservice enable
-    };
-
     static const char* WAKE_LOCK_NAME;
     virtual ~SensorService();
 
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 56b8374..fb42cc0 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -79,6 +79,7 @@
         "libperfetto_client_experimental",
         "librenderengine",
         "libserviceutils",
+        "libtonemap",
         "libtrace_proto",
         "libaidlcommonsupport",
     ],
@@ -200,7 +201,7 @@
         "SurfaceFlinger.cpp",
         "SurfaceFlingerDefaultFactory.cpp",
         "SurfaceInterceptor.cpp",
-        "SurfaceTracing.cpp",
+        "Tracing/LayerTracing.cpp",
         "Tracing/TransactionProtoParser.cpp",
         "TransactionCallbackInvoker.cpp",
         "TunnelModeEnabledReporter.cpp",
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 28c387e..dec7cc0 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -523,7 +523,7 @@
 }
 
 sp<Layer> BufferQueueLayer::createClone() {
-    LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata());
+    LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata());
     args.textureName = mTextureName;
     sp<BufferQueueLayer> layer = mFlinger->getFactory().createBufferQueueLayer(args);
     layer->setInitialValuesForClone(this);
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index dfdb5c0..c6e0727 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -62,6 +62,11 @@
     status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format);
     sp<IGraphicBufferProducer> getProducer() const;
 
+    void setSizeForTest(uint32_t w, uint32_t h) {
+        mDrawingState.active_legacy.w = w;
+        mDrawingState.active_legacy.h = h;
+    }
+
 protected:
     void gatherBufferInfo() override;
 
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index b6cbbb6..b4ccb80 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -549,19 +549,13 @@
 }
 
 bool BufferStateLayer::setTransactionCompletedListeners(
-        const std::vector<ListenerCallbacks>& listenerCallbacks, const sp<IBinder>& layerHandle) {
+        const std::vector<sp<CallbackHandle>>& handles) {
     // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return
-    if (listenerCallbacks.empty()) {
+    if (handles.empty()) {
         mReleasePreviousBuffer = false;
         return false;
     }
 
-    std::vector<sp<CallbackHandle>> handles;
-    handles.reserve(listenerCallbacks.size());
-    for (auto& [listener, callbackIds] : listenerCallbacks) {
-        handles.emplace_back(new CallbackHandle(listener, callbackIds, layerHandle));
-    }
-
     const bool willPresent = willPresentCurrentTransaction();
 
     for (const auto& handle : handles) {
@@ -577,10 +571,9 @@
             // Store so latched time and release fence can be set
             mDrawingState.callbackHandles.push_back(handle);
 
-        } else {
-            // If this layer will NOT need to be relatched and presented this frame
+        } else { // If this layer will NOT need to be relatched and presented this frame
             // Notify the transaction completed thread this handle is done
-            mFlinger->getTransactionCallbackInvoker().addUnpresentedCallbackHandle(handle);
+            mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
         }
     }
 
@@ -890,7 +883,7 @@
 }
 
 sp<Layer> BufferStateLayer::createClone() {
-    LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata());
+    LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata());
     args.textureName = mTextureName;
     sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);
     layer->mHwcSlotGenerator = mHwcSlotGenerator;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index ceed188..eea700c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -65,8 +65,7 @@
     bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
     bool setApi(int32_t api) override;
     bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
-    bool setTransactionCompletedListeners(const std::vector<ListenerCallbacks>& handles,
-                                          const sp<IBinder>& layerHandle) override;
+    bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
     bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
                        nsecs_t requestedPresentTime) override;
     bool setPosition(float /*x*/, float /*y*/) override;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 8da2e24..0a8ebec 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -72,35 +72,28 @@
     return lbc;
 }
 
-status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
-                               uint32_t flags, const sp<IBinder>& parentHandle,
-                               LayerMetadata metadata, sp<IBinder>* handle,
-                               sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId,
-                               uint32_t* outTransformHint) {
+status_t Client::createSurface(const String8& name, uint32_t /* w */, uint32_t /* h */,
+                               PixelFormat /* format */, uint32_t flags,
+                               const sp<IBinder>& parentHandle, LayerMetadata metadata,
+                               sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* /* gbp */,
+                               int32_t* outLayerId, uint32_t* outTransformHint) {
     // We rely on createLayer to check permissions.
-    return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,
-                                 parentHandle, outLayerId, nullptr, outTransformHint);
+    LayerCreationArgs args(mFlinger.get(), this, name.c_str(), flags, std::move(metadata));
+    return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, nullptr,
+                                 outTransformHint);
 }
 
-status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
-                                         PixelFormat format, uint32_t flags,
-                                         const sp<IGraphicBufferProducer>& parent,
-                                         LayerMetadata metadata, sp<IBinder>* handle,
-                                         sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId,
-                                         uint32_t* outTransformHint) {
-    if (mFlinger->authenticateSurfaceTexture(parent) == false) {
-        ALOGE("failed to authenticate surface texture");
-        return BAD_VALUE;
-    }
-
-    const auto& layer = (static_cast<MonitoredProducer*>(parent.get()))->getLayer();
-    if (layer == nullptr) {
-        ALOGE("failed to find parent layer");
-        return BAD_VALUE;
-    }
-
-    return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,
-                                 nullptr, outLayerId, layer, outTransformHint);
+status_t Client::createWithSurfaceParent(const String8& /* name */, uint32_t /* w */,
+                                         uint32_t /* h */, PixelFormat /* format */,
+                                         uint32_t /* flags */,
+                                         const sp<IGraphicBufferProducer>& /* parent */,
+                                         LayerMetadata /* metadata */, sp<IBinder>* /* handle */,
+                                         sp<IGraphicBufferProducer>* /* gbp */,
+                                         int32_t* /* outLayerId */,
+                                         uint32_t* /* outTransformHint */) {
+    // This api does not make sense with blast since SF no longer tracks IGBP. This api should be
+    // removed.
+    return BAD_VALUE;
 }
 
 status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 83b4a25..aefc014 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -38,6 +38,7 @@
     static_libs: [
         "libmath",
         "librenderengine",
+        "libtonemap",
         "libtrace_proto",
         "libaidlcommonsupport",
     ],
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 841e79f..3ccc229 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -36,8 +36,7 @@
 
 sp<Layer> ContainerLayer::createClone() {
     sp<ContainerLayer> layer = mFlinger->getFactory().createContainerLayer(
-            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
-                              LayerMetadata()));
+            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()));
     layer->setInitialValuesForClone(this);
     return layer;
 }
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
index 86c6b21..845176c 100644
--- a/services/surfaceflinger/EffectLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -136,8 +136,7 @@
 
 sp<Layer> EffectLayer::createClone() {
     sp<EffectLayer> layer = mFlinger->getFactory().createEffectLayer(
-            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
-                              LayerMetadata()));
+            LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()));
     layer->setInitialValuesForClone(this);
     return layer;
 }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d85e843..968a49d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -87,11 +87,12 @@
 std::atomic<int32_t> Layer::sSequence{1};
 
 Layer::Layer(const LayerCreationArgs& args)
-      : mFlinger(args.flinger),
+      : sequence(args.sequence.value_or(sSequence++)),
+        mFlinger(args.flinger),
         mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
         mClientRef(args.client),
-        mWindowType(
-                static_cast<WindowInfo::Type>(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) {
+        mWindowType(static_cast<WindowInfo::Type>(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))),
+        mLayerCreationFlags(args.flags) {
     uint32_t layerFlags = 0;
     if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
     if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
@@ -99,8 +100,6 @@
     if (args.flags & ISurfaceComposerClient::eSkipScreenshot)
         layerFlags |= layer_state_t::eLayerSkipScreenshot;
 
-    mDrawingState.active_legacy.w = args.w;
-    mDrawingState.active_legacy.h = args.h;
     mDrawingState.flags = layerFlags;
     mDrawingState.active_legacy.transform.set(0, 0);
     mDrawingState.crop.makeInvalid();
@@ -185,12 +184,10 @@
 }
 
 LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, std::string name,
-                                     uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata)
+                                     uint32_t flags, LayerMetadata metadata)
       : flinger(flinger),
         client(std::move(client)),
         name(std::move(name)),
-        w(w),
-        h(h),
         flags(flags),
         metadata(std::move(metadata)) {
     IPCThreadState* ipc = IPCThreadState::self();
@@ -887,7 +884,7 @@
         uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect;
         std::string name = mName + "BackgroundColorLayer";
         mDrawingState.bgColorLayer = mFlinger->getFactory().createEffectLayer(
-                LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags,
+                LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), flags,
                                   LayerMetadata()));
 
         // add to child list
@@ -2008,7 +2005,7 @@
     writeToProtoDrawingState(layerProto, traceFlags, display);
     writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
 
-    if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) {
+    if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
         // Only populate for the primary display.
         if (display) {
             const Hwc2::IComposerClient::Composition compositionType = getCompositionType(*display);
@@ -2026,43 +2023,38 @@
 void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags,
                                      const DisplayDevice* display) {
     const ui::Transform transform = getTransform();
+    auto buffer = getBuffer();
+    if (buffer != nullptr) {
+        LayerProtoHelper::writeToProto(buffer,
+                                       [&]() { return layerInfo->mutable_active_buffer(); });
+        LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()),
+                                                 layerInfo->mutable_buffer_transform());
+    }
+    layerInfo->set_invalidate(contentDirty);
+    layerInfo->set_is_protected(isProtected());
+    layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
+    layerInfo->set_queued_frames(getQueuedFrameCount());
+    layerInfo->set_refresh_pending(isBufferLatched());
+    layerInfo->set_curr_frame(mCurrentFrameNumber);
+    layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
 
-    if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
+    layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius);
+    layerInfo->set_corner_radius(getRoundedCornerState().radius);
+    layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
+    layerInfo->set_is_trusted_overlay(isTrustedOverlay());
+    LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform());
+    LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+                                           [&]() { return layerInfo->mutable_position(); });
+    LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
+    if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
+        LayerProtoHelper::writeToProto(getVisibleRegion(display),
+                                       [&]() { return layerInfo->mutable_visible_region(); });
+    }
+    LayerProtoHelper::writeToProto(surfaceDamageRegion,
+                                   [&]() { return layerInfo->mutable_damage_region(); });
 
-        auto buffer = getBuffer();
-        if (buffer != nullptr) {
-            LayerProtoHelper::writeToProto(buffer,
-                                           [&]() { return layerInfo->mutable_active_buffer(); });
-            LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()),
-                                                     layerInfo->mutable_buffer_transform());
-        }
-        layerInfo->set_invalidate(contentDirty);
-        layerInfo->set_is_protected(isProtected());
-        layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
-        layerInfo->set_queued_frames(getQueuedFrameCount());
-        layerInfo->set_refresh_pending(isBufferLatched());
-        layerInfo->set_curr_frame(mCurrentFrameNumber);
-        layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
-
-        layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius);
-        layerInfo->set_corner_radius(getRoundedCornerState().radius);
-        layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
-        layerInfo->set_is_trusted_overlay(isTrustedOverlay());
-        LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform());
-        LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
-                                               [&]() { return layerInfo->mutable_position(); });
-        LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
-        if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) {
-            LayerProtoHelper::writeToProto(getVisibleRegion(display),
-                                           [&]() { return layerInfo->mutable_visible_region(); });
-        }
-        LayerProtoHelper::writeToProto(surfaceDamageRegion,
-                                       [&]() { return layerInfo->mutable_damage_region(); });
-
-        if (hasColorTransform()) {
-            LayerProtoHelper::writeToProto(getColorTransform(),
-                                           layerInfo->mutable_color_transform());
-        }
+    if (hasColorTransform()) {
+        LayerProtoHelper::writeToProto(getColorTransform(), layerInfo->mutable_color_transform());
     }
 
     LayerProtoHelper::writeToProto(mSourceBounds,
@@ -2082,70 +2074,66 @@
 
     ui::Transform requestedTransform = state.transform;
 
-    if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
-        layerInfo->set_id(sequence);
-        layerInfo->set_name(getName().c_str());
-        layerInfo->set_type(getType());
+    layerInfo->set_id(sequence);
+    layerInfo->set_name(getName().c_str());
+    layerInfo->set_type(getType());
 
-        for (const auto& child : children) {
-            layerInfo->add_children(child->sequence);
-        }
-
-        for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
-            sp<Layer> strongRelative = weakRelative.promote();
-            if (strongRelative != nullptr) {
-                layerInfo->add_relatives(strongRelative->sequence);
-            }
-        }
-
-        LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
-                                       [&]() { return layerInfo->mutable_transparent_region(); });
-
-        layerInfo->set_layer_stack(getLayerStack().id);
-        layerInfo->set_z(state.z);
-
-        LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(),
-                                               [&]() {
-                                                   return layerInfo->mutable_requested_position();
-                                               });
-
-        LayerProtoHelper::writeSizeToProto(state.width, state.height,
-                                           [&]() { return layerInfo->mutable_size(); });
-
-        LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); });
-
-        layerInfo->set_is_opaque(isOpaque(state));
-
-
-        layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
-        LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
-        LayerProtoHelper::writeToProto(state.color,
-                                       [&]() { return layerInfo->mutable_requested_color(); });
-        layerInfo->set_flags(state.flags);
-
-        LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
-                                                 layerInfo->mutable_requested_transform());
-
-        auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
-        if (parent != nullptr) {
-            layerInfo->set_parent(parent->sequence);
-        } else {
-            layerInfo->set_parent(-1);
-        }
-
-        auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
-        if (zOrderRelativeOf != nullptr) {
-            layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
-        } else {
-            layerInfo->set_z_order_relative_of(-1);
-        }
-
-        layerInfo->set_is_relative_of(state.isRelativeOf);
-
-        layerInfo->set_owner_uid(mOwnerUid);
+    for (const auto& child : children) {
+        layerInfo->add_children(child->sequence);
     }
 
-    if (traceFlags & SurfaceTracing::TRACE_INPUT) {
+    for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
+        sp<Layer> strongRelative = weakRelative.promote();
+        if (strongRelative != nullptr) {
+            layerInfo->add_relatives(strongRelative->sequence);
+        }
+    }
+
+    LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
+                                   [&]() { return layerInfo->mutable_transparent_region(); });
+
+    layerInfo->set_layer_stack(getLayerStack().id);
+    layerInfo->set_z(state.z);
+
+    LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
+        return layerInfo->mutable_requested_position();
+    });
+
+    LayerProtoHelper::writeSizeToProto(state.width, state.height,
+                                       [&]() { return layerInfo->mutable_size(); });
+
+    LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); });
+
+    layerInfo->set_is_opaque(isOpaque(state));
+
+    layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
+    LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
+    LayerProtoHelper::writeToProto(state.color,
+                                   [&]() { return layerInfo->mutable_requested_color(); });
+    layerInfo->set_flags(state.flags);
+
+    LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
+                                             layerInfo->mutable_requested_transform());
+
+    auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
+    if (parent != nullptr) {
+        layerInfo->set_parent(parent->sequence);
+    } else {
+        layerInfo->set_parent(-1);
+    }
+
+    auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
+    if (zOrderRelativeOf != nullptr) {
+        layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
+    } else {
+        layerInfo->set_z_order_relative_of(-1);
+    }
+
+    layerInfo->set_is_relative_of(state.isRelativeOf);
+
+    layerInfo->set_owner_uid(mOwnerUid);
+
+    if (traceFlags & LayerTracing::TRACE_INPUT) {
         WindowInfo info;
         if (useDrawing) {
             info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true);
@@ -2157,7 +2145,7 @@
                                        [&]() { return layerInfo->mutable_input_window_info(); });
     }
 
-    if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
+    if (traceFlags & LayerTracing::TRACE_EXTRA) {
         auto protoMap = layerInfo->mutable_metadata();
         for (const auto& entry : state.metadata.mMap) {
             (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
@@ -2640,17 +2628,6 @@
     return true;
 }
 
-bool Layer::setTransactionCompletedListeners(
-        const std::vector<ListenerCallbacks>& listenerCallbacks, const sp<IBinder>&) {
-    if (listenerCallbacks.empty()) {
-        return false;
-    }
-    for (auto& listener : listenerCallbacks) {
-        mFlinger->getTransactionCallbackInvoker().addEmptyCallback(listener);
-    }
-    return false;
-}
-
 // ---------------------------------------------------------------------------
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b79903d..bda1c28 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -57,7 +57,7 @@
 #include "Scheduler/LayerInfo.h"
 #include "Scheduler/Seamlessness.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceTracing.h"
+#include "Tracing/LayerTracing.h"
 #include "TransactionCallbackInvoker.h"
 
 using namespace android::surfaceflinger;
@@ -85,20 +85,18 @@
 } // namespace frametimeline
 
 struct LayerCreationArgs {
-    LayerCreationArgs(SurfaceFlinger*, sp<Client>, std::string name, uint32_t w, uint32_t h,
-                      uint32_t flags, LayerMetadata);
+    LayerCreationArgs(SurfaceFlinger*, sp<Client>, std::string name, uint32_t flags, LayerMetadata);
 
     SurfaceFlinger* flinger;
     const sp<Client> client;
     std::string name;
-    uint32_t w;
-    uint32_t h;
     uint32_t flags;
     LayerMetadata metadata;
 
     pid_t callingPid;
     uid_t callingUid;
     uint32_t textureName;
+    std::optional<uint32_t> sequence = std::nullopt;
 };
 
 class Layer : public virtual RefBase, compositionengine::LayerFE {
@@ -428,8 +426,10 @@
     virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
     virtual bool setApi(int32_t /*api*/) { return false; };
     virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
-    virtual bool setTransactionCompletedListeners(const std::vector<ListenerCallbacks>& /*handles*/,
-                                                  const sp<IBinder>& /* layerHandle */);
+    virtual bool setTransactionCompletedListeners(
+            const std::vector<sp<CallbackHandle>>& /*handles*/) {
+        return false;
+    };
     virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
                                nsecs_t /*requestedPresentTime*/) {
         return false;
@@ -693,7 +693,7 @@
     // external mStateLock. If writing drawing state, this function should be called on the
     // main or tracing thread.
     void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet,
-                                 uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
+                                 uint32_t traceFlags = LayerTracing::TRACE_ALL);
 
     gui::WindowInfo::Type getWindowType() const { return mWindowType; }
 
@@ -879,7 +879,7 @@
     // Layer serial number.  This gives layers an explicit ordering, so we
     // have a stable sort order when their layer stack and Z-order are
     // the same.
-    int32_t sequence{sSequence++};
+    const int32_t sequence;
 
     bool mPendingHWCDestroy{false};
 
@@ -1117,6 +1117,8 @@
     const std::vector<BlurRegion> getBlurRegions() const;
 
     bool mIsAtRoot = false;
+
+    uint32_t mLayerCreationFlags;
 };
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate);
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index 11fe6d0..a1e1455 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -112,12 +112,10 @@
         }
         drawLayers();
     } else {
-        uint32_t w = static_cast<uint32_t>(getWidth());
-        uint32_t h = static_cast<uint32_t>(getHeight());
         // In the "childrenOnly" case we reparent the children to a screenshot
         // layer which has no properties set and which does not draw.
         sp<ContainerLayer> screenshotParentLayer = mFlinger.getFactory().createContainerLayer(
-                {&mFlinger, nullptr, "Screenshot Parent"s, w, h, 0, LayerMetadata()});
+                {&mFlinger, nullptr, "Screenshot Parent"s, 0, LayerMetadata()});
 
         ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
         drawLayers();
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 6b2d745..df76f50 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -33,13 +33,7 @@
     mFlinger(flinger),
     mLayer(layer) {}
 
-MonitoredProducer::~MonitoredProducer() {
-    // Remove ourselves from SurfaceFlinger's list. We do this asynchronously
-    // because we don't know where this destructor is called from. It could be
-    // called with the mStateLock held, leading to a dead-lock (it actually
-    // happens).
-    mFlinger->removeGraphicBufferProducerAsync(onAsBinder());
-}
+MonitoredProducer::~MonitoredProducer() {}
 
 status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
     return mProducer->requestBuffer(slot, buf);
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 043a536..a020e2c 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -30,41 +30,30 @@
 
 namespace android::impl {
 
-void MessageQueue::Handler::dispatchComposite() {
-    if ((mEventMask.fetch_or(kComposite) & kComposite) == 0) {
-        mQueue.mLooper->sendMessage(this, Message(kComposite));
-    }
-}
-
-void MessageQueue::Handler::dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime) {
-    if ((mEventMask.fetch_or(kCommit) & kCommit) == 0) {
+void MessageQueue::Handler::dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime) {
+    if (!mFramePending.exchange(true)) {
         mVsyncId = vsyncId;
         mExpectedVsyncTime = expectedVsyncTime;
-        mQueue.mLooper->sendMessage(this, Message(kCommit));
+        mQueue.mLooper->sendMessage(this, Message());
     }
 }
 
 bool MessageQueue::Handler::isFramePending() const {
-    constexpr auto kPendingMask = kCommit | kComposite;
-    return (mEventMask.load() & kPendingMask) != 0;
+    return mFramePending.load();
 }
 
-void MessageQueue::Handler::handleMessage(const Message& message) {
+void MessageQueue::Handler::handleMessage(const Message&) {
+    mFramePending.store(false);
+
     const nsecs_t frameTime = systemTime();
-    switch (message.what) {
-        case kCommit:
-            mEventMask.fetch_and(~kCommit);
-            if (!mQueue.mCompositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {
-                return;
-            }
-            // Composite immediately, rather than after pending tasks through scheduleComposite.
-            [[fallthrough]];
-        case kComposite:
-            mEventMask.fetch_and(~kComposite);
-            mQueue.mCompositor.composite(frameTime);
-            mQueue.mCompositor.sample();
-            break;
+    auto& compositor = mQueue.mCompositor;
+
+    if (!compositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {
+        return;
     }
+
+    compositor.composite(frameTime);
+    compositor.sample();
 }
 
 MessageQueue::MessageQueue(ICompositor& compositor)
@@ -122,7 +111,7 @@
     const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions(
             {targetWakeupTime, readyTime, vsyncTime});
 
-    mHandler->dispatchCommit(vsyncId, vsyncTime);
+    mHandler->dispatchFrame(vsyncId, vsyncTime);
 }
 
 void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
@@ -176,7 +165,7 @@
     mLooper->sendMessage(handler, Message());
 }
 
-void MessageQueue::scheduleCommit() {
+void MessageQueue::scheduleFrame() {
     ATRACE_CALL();
 
     {
@@ -195,18 +184,14 @@
                                            .earliestVsync = mVsync.lastCallbackTime.count()});
 }
 
-void MessageQueue::scheduleComposite() {
-    mHandler->dispatchComposite();
-}
-
 void MessageQueue::injectorCallback() {
     ssize_t n;
     DisplayEventReceiver::Event buffer[8];
     while ((n = DisplayEventReceiver::getEvents(&mInjector.tube, buffer, 8)) > 0) {
         for (int i = 0; i < n; i++) {
             if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
-                mHandler->dispatchCommit(buffer[i].vsync.vsyncId,
-                                         buffer[i].vsync.expectedVSyncTimestamp);
+                auto& vsync = buffer[i].vsync;
+                mHandler->dispatchFrame(vsync.vsyncId, vsync.expectedVSyncTimestamp);
                 break;
             }
         }
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 2c908a6..dd69d60 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -71,8 +71,7 @@
     virtual void setInjector(sp<EventThreadConnection>) = 0;
     virtual void waitMessage() = 0;
     virtual void postMessage(sp<MessageHandler>&&) = 0;
-    virtual void scheduleCommit() = 0;
-    virtual void scheduleComposite() = 0;
+    virtual void scheduleFrame() = 0;
 
     using Clock = std::chrono::steady_clock;
     virtual std::optional<Clock::time_point> getScheduledFrameTime() const = 0;
@@ -83,11 +82,8 @@
 class MessageQueue : public android::MessageQueue {
 protected:
     class Handler : public MessageHandler {
-        static constexpr uint32_t kCommit = 0b1;
-        static constexpr uint32_t kComposite = 0b10;
-
         MessageQueue& mQueue;
-        std::atomic<uint32_t> mEventMask = 0;
+        std::atomic_bool mFramePending = false;
         std::atomic<int64_t> mVsyncId = 0;
         std::atomic<nsecs_t> mExpectedVsyncTime = 0;
 
@@ -97,8 +93,7 @@
 
         bool isFramePending() const;
 
-        virtual void dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime);
-        void dispatchComposite();
+        virtual void dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime);
     };
 
     friend class Handler;
@@ -147,8 +142,7 @@
     void waitMessage() override;
     void postMessage(sp<MessageHandler>&&) override;
 
-    void scheduleCommit() override;
-    void scheduleComposite() override;
+    void scheduleFrame() override;
 
     std::optional<Clock::time_point> getScheduledFrameTime() const override;
 };
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index aabd88a..0d17b0c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -744,7 +744,6 @@
                 [getCallback] {
                     if (const auto callback = getCallback()) callback->onExpired();
                 });
-        mIdleTimer->start();
     }
 }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 53472ef..0584024 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -355,10 +355,22 @@
                                std::function<void()> kernelTimerExpired) {
         std::scoped_lock lock(mIdleTimerCallbacksMutex);
         mIdleTimerCallbacks.emplace();
-        mIdleTimerCallbacks->platform.onReset = platformTimerReset;
-        mIdleTimerCallbacks->platform.onExpired = platformTimerExpired;
-        mIdleTimerCallbacks->kernel.onReset = kernelTimerReset;
-        mIdleTimerCallbacks->kernel.onExpired = kernelTimerExpired;
+        mIdleTimerCallbacks->platform.onReset = std::move(platformTimerReset);
+        mIdleTimerCallbacks->platform.onExpired = std::move(platformTimerExpired);
+        mIdleTimerCallbacks->kernel.onReset = std::move(kernelTimerReset);
+        mIdleTimerCallbacks->kernel.onExpired = std::move(kernelTimerExpired);
+    }
+
+    void startIdleTimer() {
+        if (mIdleTimer) {
+            mIdleTimer->start();
+        }
+    }
+
+    void stopIdleTimer() {
+        if (mIdleTimer) {
+            mIdleTimer->stop();
+        }
     }
 
     void resetIdleTimer(bool kernelOnly) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index eeea25d..4d72798 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -117,16 +117,10 @@
     }
 };
 
-Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
-                     ISchedulerCallback& callback)
-      : Scheduler(configs, callback,
-                  {.useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) {
-}
+Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, Options options)
+      : impl::MessageQueue(compositor), mOptions(options), mSchedulerCallback(callback) {}
 
-Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
-                     ISchedulerCallback& callback, Options options)
-      : Scheduler(createVsyncSchedule(configs->supportsKernelIdleTimer()), configs, callback,
-                  createLayerHistory(), options) {
+void Scheduler::startTimers() {
     using namespace sysprop;
 
     if (const int64_t millis = set_touch_timer_ms(0); millis > 0) {
@@ -147,22 +141,6 @@
     }
 }
 
-Scheduler::Scheduler(VsyncSchedule schedule,
-                     const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
-                     ISchedulerCallback& schedulerCallback,
-                     std::unique_ptr<LayerHistory> layerHistory, Options options)
-      : mOptions(options),
-        mVsyncSchedule(std::move(schedule)),
-        mLayerHistory(std::move(layerHistory)),
-        mSchedulerCallback(schedulerCallback),
-        mPredictedVsyncTracer(
-                base::GetBoolProperty("debug.sf.show_predicted_vsync", false)
-                        ? std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch)
-                        : nullptr) {
-    setRefreshRateConfigs(configs);
-    mSchedulerCallback.setVsyncEnabled(false);
-}
-
 Scheduler::~Scheduler() {
     // Ensure the OneShotTimer threads are joined before we start destroying state.
     mDisplayPowerTimer.reset();
@@ -170,7 +148,13 @@
     mRefreshRateConfigs.reset();
 }
 
-Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) {
+void Scheduler::run() {
+    while (true) {
+        waitMessage();
+    }
+}
+
+void Scheduler::createVsyncSchedule(bool supportKernelTimer) {
     auto clock = std::make_unique<scheduler::SystemClock>();
     auto tracker = createVSyncTracker();
     auto dispatch = createVSyncDispatch(*tracker);
@@ -180,11 +164,11 @@
     auto controller =
             std::make_unique<scheduler::VSyncReactor>(std::move(clock), *tracker, pendingFenceLimit,
                                                       supportKernelTimer);
-    return {std::move(controller), std::move(tracker), std::move(dispatch)};
-}
+    mVsyncSchedule = {std::move(controller), std::move(tracker), std::move(dispatch)};
 
-std::unique_ptr<LayerHistory> Scheduler::createLayerHistory() {
-    return std::make_unique<scheduler::LayerHistory>();
+    if (base::GetBoolProperty("debug.sf.show_predicted_vsync", false)) {
+        mPredictedVsyncTracer = std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch);
+    }
 }
 
 std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
@@ -594,11 +578,11 @@
     // If the content detection feature is off, we still keep the layer history,
     // since we use it for other features (like Frame Rate API), so layers
     // still need to be registered.
-    mLayerHistory->registerLayer(layer, voteType);
+    mLayerHistory.registerLayer(layer, voteType);
 }
 
 void Scheduler::deregisterLayer(Layer* layer) {
-    mLayerHistory->deregisterLayer(layer);
+    mLayerHistory.deregisterLayer(layer);
 }
 
 void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
@@ -608,11 +592,11 @@
         if (!mRefreshRateConfigs->canSwitch()) return;
     }
 
-    mLayerHistory->record(layer, presentTime, systemTime(), updateType);
+    mLayerHistory.record(layer, presentTime, systemTime(), updateType);
 }
 
 void Scheduler::setModeChangePending(bool pending) {
-    mLayerHistory->setModeChangePending(pending);
+    mLayerHistory.setModeChangePending(pending);
 }
 
 void Scheduler::chooseRefreshRateForContent() {
@@ -625,7 +609,7 @@
 
     const auto refreshRateConfigs = holdRefreshRateConfigs();
     scheduler::LayerHistory::Summary summary =
-            mLayerHistory->summarize(*refreshRateConfigs, systemTime());
+            mLayerHistory.summarize(*refreshRateConfigs, systemTime());
     scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
     DisplayModePtr newMode;
     bool frameRateChanged;
@@ -686,7 +670,7 @@
 
     // Display Power event will boost the refresh rate to performance.
     // Clear Layer History to get fresh FPS detection
-    mLayerHistory->clear();
+    mLayerHistory.clear();
 }
 
 void Scheduler::kernelIdleTimerCallback(TimerState state) {
@@ -730,7 +714,7 @@
     // NOTE: Instead of checking all the layers, we should be checking the layer
     // that is currently on top. b/142507166 will give us this capability.
     if (handleTimerStateChanged(&mFeatures.touch, touch)) {
-        mLayerHistory->clear();
+        mLayerHistory.clear();
     }
     ATRACE_INT("TouchState", static_cast<int>(touch));
 }
@@ -747,7 +731,7 @@
                   mTouchTimer ? mTouchTimer->dump().c_str() : "off");
     StringAppendF(&result, "+  Content detection: %s %s\n\n",
                   toContentDetectionString(mOptions.useContentDetection),
-                  mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)");
+                  mLayerHistory.dump().c_str());
 
     {
         std::lock_guard lock(mFrameRateOverridesLock);
@@ -911,7 +895,7 @@
 }
 
 void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) {
-    mLayerHistory->setDisplayArea(displayArea);
+    mLayerHistory.setDisplayArea(displayArea);
 }
 
 void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 8397738..2a6de54 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -18,6 +18,7 @@
 
 #include <atomic>
 #include <functional>
+#include <future>
 #include <memory>
 #include <mutex>
 #include <optional>
@@ -32,6 +33,7 @@
 
 #include "EventThread.h"
 #include "LayerHistory.h"
+#include "MessageQueue.h"
 #include "OneShotTimer.h"
 #include "RefreshRateConfigs.h"
 #include "SchedulerUtils.h"
@@ -70,14 +72,41 @@
     ~ISchedulerCallback() = default;
 };
 
-class Scheduler {
+class Scheduler : impl::MessageQueue {
+    using Impl = impl::MessageQueue;
+
 public:
     using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
     using ModeEvent = scheduler::RefreshRateConfigEvent;
 
-    Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&);
+    struct Options {
+        // Whether to use content detection at all.
+        bool useContentDetection;
+    };
+
+    Scheduler(ICompositor&, ISchedulerCallback&, Options);
     ~Scheduler();
 
+    void createVsyncSchedule(bool supportKernelIdleTimer);
+    void startTimers();
+    void run();
+
+    using Impl::initVsync;
+    using Impl::setInjector;
+
+    using Impl::getScheduledFrameTime;
+    using Impl::setDuration;
+
+    using Impl::scheduleFrame;
+
+    // Schedule an asynchronous or synchronous task on the main thread.
+    template <typename F, typename T = std::invoke_result_t<F>>
+    [[nodiscard]] std::future<T> schedule(F&& f) {
+        auto [task, future] = makeTask(std::move(f));
+        postMessage(std::move(task));
+        return std::move(future);
+    }
+
     using ConnectionHandle = scheduler::ConnectionHandle;
     ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*,
                                       std::chrono::nanoseconds workDuration,
@@ -184,17 +213,32 @@
 
     void setRefreshRateConfigs(std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs)
             EXCLUDES(mRefreshRateConfigsLock) {
-        std::scoped_lock lock(mRefreshRateConfigsLock);
-        mRefreshRateConfigs = std::move(refreshRateConfigs);
-        mRefreshRateConfigs->setIdleTimerCallbacks(
-                [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Reset); },
-                [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Expired); },
-                [this] {
-                    std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Reset);
-                },
-                [this] {
-                    std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Expired);
-                });
+        // We need to stop the idle timer on the previous RefreshRateConfigs instance
+        // and cleanup the scheduler's state before we switch to the other RefreshRateConfigs.
+        {
+            std::scoped_lock lock(mRefreshRateConfigsLock);
+            if (mRefreshRateConfigs) mRefreshRateConfigs->stopIdleTimer();
+        }
+        {
+            std::scoped_lock lock(mFeatureStateLock);
+            mFeatures = {};
+        }
+        {
+            std::scoped_lock lock(mRefreshRateConfigsLock);
+            mRefreshRateConfigs = std::move(refreshRateConfigs);
+            mRefreshRateConfigs->setIdleTimerCallbacks(
+                    [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Reset); },
+                    [this] {
+                        std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Expired);
+                    },
+                    [this] {
+                        std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Reset);
+                    },
+                    [this] {
+                        std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Expired);
+                    });
+            mRefreshRateConfigs->startIdleTimer();
+        }
     }
 
     nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) {
@@ -213,27 +257,12 @@
     enum class TimerState { Reset, Expired };
     enum class TouchState { Inactive, Active };
 
-    struct Options {
-        // Whether to use content detection at all.
-        bool useContentDetection;
-    };
-
     struct VsyncSchedule {
         std::unique_ptr<scheduler::VsyncController> controller;
         std::unique_ptr<scheduler::VSyncTracker> tracker;
         std::unique_ptr<scheduler::VSyncDispatch> dispatch;
     };
 
-    // Unlike the testing constructor, this creates the VsyncSchedule, LayerHistory, and timers.
-    Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&, Options);
-
-    // Used by tests to inject mocks.
-    Scheduler(VsyncSchedule, const std::shared_ptr<scheduler::RefreshRateConfigs>&,
-              ISchedulerCallback&, std::unique_ptr<LayerHistory>, Options);
-
-    static VsyncSchedule createVsyncSchedule(bool supportKernelIdleTimer);
-    static std::unique_ptr<LayerHistory> createLayerHistory();
-
     // Create a connection on the given EventThread.
     ConnectionHandle createConnection(std::unique_ptr<EventThread>);
     sp<EventThreadConnection> createConnectionInternal(
@@ -297,7 +326,7 @@
     VsyncSchedule mVsyncSchedule;
 
     // Used to choose refresh rate if content detection is enabled.
-    std::unique_ptr<LayerHistory> mLayerHistory;
+    LayerHistory mLayerHistory;
 
     // Timer used to monitor touch events.
     std::optional<scheduler::OneShotTimer> mTouchTimer;
@@ -338,7 +367,7 @@
             GUARDED_BY(mVsyncTimelineLock);
     static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms;
 
-    const std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer;
+    std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer;
 
     // The frame rate override lists need their own mutex as they are being read
     // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c2dcd70..45e0a3f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -125,7 +125,6 @@
 #include "Scheduler/DispSyncSource.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/LayerHistory.h"
-#include "Scheduler/MessageQueue.h"
 #include "Scheduler/Scheduler.h"
 #include "Scheduler/VsyncConfiguration.h"
 #include "Scheduler/VsyncController.h"
@@ -362,7 +361,6 @@
         mTimeStats(std::make_shared<impl::TimeStats>()),
         mFrameTracer(mFactory.createFrameTracer()),
         mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())),
-        mEventQueue(mFactory.createMessageQueue(*this)),
         mCompositionEngine(mFactory.createCompositionEngine()),
         mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
         mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
@@ -509,8 +507,8 @@
     // the window manager died on us. prepare its eulogy.
     mBootFinished = false;
 
-    // Sever the link to inputflinger since its gone as well.
-    static_cast<void>(schedule([=] { mInputFlinger = nullptr; }));
+    // Sever the link to inputflinger since it's gone as well.
+    static_cast<void>(mScheduler->schedule([=] { mInputFlinger = nullptr; }));
 
     // restore initial conditions (default device unblank, etc)
     initializeDisplays();
@@ -520,16 +518,7 @@
 }
 
 void SurfaceFlinger::run() {
-    while (true) {
-        mEventQueue->waitMessage();
-    }
-}
-
-template <typename F, typename T>
-inline std::future<T> SurfaceFlinger::schedule(F&& f) {
-    auto [task, future] = makeTask(std::move(f));
-    mEventQueue->postMessage(std::move(task));
-    return std::move(future);
+    mScheduler->run();
 }
 
 sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
@@ -730,7 +719,7 @@
 
     sp<IBinder> input(defaultServiceManager()->getService(String16("inputflinger")));
 
-    static_cast<void>(schedule([=] {
+    static_cast<void>(mScheduler->schedule([=] {
         if (input == nullptr) {
             ALOGE("Failed to link to input service");
         } else {
@@ -771,7 +760,7 @@
     if (std::this_thread::get_id() == mMainThreadId) {
         return genTextures();
     } else {
-        return schedule(genTextures).get();
+        return mScheduler->schedule(genTextures).get();
     }
 }
 
@@ -904,9 +893,8 @@
 }
 
 bool SurfaceFlinger::authenticateSurfaceTextureLocked(
-        const sp<IGraphicBufferProducer>& bufferProducer) const {
-    sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
-    return mGraphicBufferProducerList.count(surfaceTextureBinder.get()) > 0;
+        const sp<IGraphicBufferProducer>& /* bufferProducer */) const {
+    return false;
 }
 
 status_t SurfaceFlinger::getSupportedFrameTimestamps(
@@ -1121,7 +1109,7 @@
         return BAD_VALUE;
     }
 
-    auto future = schedule([=]() -> status_t {
+    auto future = mScheduler->schedule([=]() -> status_t {
         const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
         if (!display) {
             ALOGE("Attempt to set allowed display modes for invalid display token %p",
@@ -1259,7 +1247,7 @@
         const auto displayModeAllowed =
                 display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId());
         if (!displayModeAllowed) {
-            desiredActiveModeChangeDone(display);
+            clearDesiredActiveModeState(display);
             continue;
         }
 
@@ -1285,7 +1273,7 @@
 }
 
 void SurfaceFlinger::disableExpensiveRendering() {
-    schedule([=]() MAIN_THREAD {
+    auto future = mScheduler->schedule([=]() MAIN_THREAD {
         ATRACE_CALL();
         if (mPowerAdvisor.isUsingExpensiveRendering()) {
             const auto& displays = ON_MAIN_THREAD(mDisplays);
@@ -1294,7 +1282,9 @@
                 mPowerAdvisor.setExpensiveRenderingExpected(display->getId(), kDisable);
             }
         }
-    }).wait();
+    });
+
+    future.wait();
 }
 
 std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) {
@@ -1333,7 +1323,7 @@
         return BAD_VALUE;
     }
 
-    auto future = schedule([=]() MAIN_THREAD -> status_t {
+    auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
         const auto display = getDisplayDeviceLocked(displayToken);
         if (!display) {
             ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
@@ -1368,22 +1358,24 @@
 }
 
 void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
-    static_cast<void>(schedule([=]() MAIN_THREAD {
+    const char* const whence = __func__;
+    static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
         if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
             getHwComposer().setAutoLowLatencyMode(*displayId, on);
         } else {
-            ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+            ALOGE("%s: Invalid display token %p", whence, displayToken.get());
         }
     }));
 }
 
 void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) {
-    static_cast<void>(schedule([=]() MAIN_THREAD {
+    const char* const whence = __func__;
+    static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
         if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
             const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE;
             getHwComposer().setContentType(*displayId, type);
         } else {
-            ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+            ALOGE("%s: Invalid display token %p", whence, displayToken.get());
         }
     }));
 }
@@ -1442,17 +1434,18 @@
 status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken,
                                                           bool enable, uint8_t componentMask,
                                                           uint64_t maxFrames) {
-    return schedule([=]() MAIN_THREAD -> status_t {
-               if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
-                   return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
-                                                                           componentMask,
-                                                                           maxFrames);
-               } else {
-                   ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
-                   return NAME_NOT_FOUND;
-               }
-           })
-            .get();
+    const char* const whence = __func__;
+    auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+        if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
+            return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
+                                                                    componentMask, maxFrames);
+        } else {
+            ALOGE("%s: Invalid display token %p", whence, displayToken.get());
+            return NAME_NOT_FOUND;
+        }
+    });
+
+    return future.get();
 }
 
 status_t SurfaceFlinger::getDisplayedContentSample(const sp<IBinder>& displayToken,
@@ -1494,14 +1487,15 @@
 }
 
 status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
-    schedule([=] {
+    auto future = mScheduler->schedule([=] {
         Mutex::Autolock lock(mStateLock);
 
         if (const auto handle = mScheduler->enableVSyncInjection(enable)) {
-            mEventQueue->setInjector(enable ? mScheduler->getEventConnection(handle) : nullptr);
+            mScheduler->setInjector(enable ? mScheduler->getEventConnection(handle) : nullptr);
         }
-    }).wait();
+    });
 
+    future.wait();
     return NO_ERROR;
 }
 
@@ -1517,12 +1511,14 @@
 
 status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) {
     outLayers->clear();
-    schedule([=] {
+    auto future = mScheduler->schedule([=] {
         const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
         mDrawingState.traverseInZOrder([&](Layer* layer) {
             outLayers->push_back(layer->getLayerDebugInfo(display.get()));
         });
-    }).wait();
+    });
+
+    future.wait();
     return NO_ERROR;
 }
 
@@ -1617,7 +1613,8 @@
         return BAD_VALUE;
     }
 
-    return ftl::chain(schedule([=]() MAIN_THREAD {
+    const char* const whence = __func__;
+    return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD {
                if (const auto display = getDisplayDeviceLocked(displayToken)) {
                    if (enableSdrDimming) {
                        display->getCompositionDisplay()
@@ -1627,7 +1624,7 @@
                    return getHwComposer().setDisplayBrightness(display->getPhysicalId(),
                                                                brightness.displayBrightness);
                } else {
-                   ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+                   ALOGE("%s: Invalid display token %p", whence, displayToken.get());
                    return ftl::yield<status_t>(NAME_NOT_FOUND);
                }
            }))
@@ -1705,7 +1702,7 @@
         mScheduler->resetIdleTimer();
     }
     mPowerAdvisor.notifyDisplayUpdateImminent();
-    mEventQueue->scheduleCommit();
+    mScheduler->scheduleFrame();
 }
 
 void SurfaceFlinger::scheduleComposite(FrameHint hint) {
@@ -1719,7 +1716,7 @@
 }
 
 void SurfaceFlinger::scheduleSample() {
-    static_cast<void>(schedule([this] { sample(); }));
+    static_cast<void>(mScheduler->schedule([this] { sample(); }));
 }
 
 nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const {
@@ -1814,7 +1811,7 @@
     ATRACE_CALL();
 
     // On main thread to avoid race conditions with display power state.
-    static_cast<void>(schedule([=]() MAIN_THREAD {
+    static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
         mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE;
 
         if (const auto display = getDefaultDisplayDeviceLocked();
@@ -1931,7 +1928,7 @@
     // fired yet just wait for the next commit.
     if (mSetActiveModePending) {
         if (framePending) {
-            mEventQueue->scheduleCommit();
+            mScheduler->scheduleFrame();
             return false;
         }
 
@@ -1949,7 +1946,7 @@
     }
 
     if (mTracingEnabledChanged) {
-        mTracingEnabled = mTracing.isEnabled();
+        mTracingEnabled = mLayerTracing.isEnabled();
         mTracingEnabledChanged = false;
     }
 
@@ -1963,24 +1960,37 @@
     // Composite if transactions were committed, or if requested by HWC.
     bool mustComposite = mMustComposite.exchange(false);
     {
-        mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) ||
-                mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) ||
-                mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS);
-        const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
-        ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
-
         mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod));
 
-        mustComposite |= flushAndCommitTransactions();
+        bool needsTraversal = false;
+        if (clearTransactionFlags(eTransactionFlushNeeded)) {
+            needsTraversal = flushTransactionQueues();
+        }
+
+        const bool shouldCommit =
+                (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
+        if (shouldCommit) {
+            commitTransactions();
+        }
+
+        if (transactionFlushNeeded()) {
+            setTransactionFlags(eTransactionFlushNeeded);
+        }
+
+        mustComposite |= shouldCommit;
         mustComposite |= latchBuffers();
 
-        updateLayerGeometry();
-
-        if (tracePreComposition) {
-            if (mVisibleRegionsDirty) {
-                mTracing.notifyLocked("visibleRegionsDirty");
-            }
+        // This has to be called after latchBuffers because we want to include the layers that have
+        // been latched in the commit callback
+        if (!needsTraversal) {
+            // Invoke empty transaction callbacks early.
+            mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
+        } else {
+            // Invoke OnCommit callbacks.
+            mTransactionCallbackInvoker.sendCallbacks(true /* onCommitOnly */);
         }
+
+        updateLayerGeometry();
     }
 
     // Layers need to get updated (in the previous line) before we can use them for
@@ -2000,34 +2010,6 @@
     return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
 }
 
-bool SurfaceFlinger::flushAndCommitTransactions() {
-    ATRACE_CALL();
-
-    bool needsTraversal = false;
-    if (clearTransactionFlags(eTransactionFlushNeeded)) {
-        needsTraversal = flushTransactionQueues();
-    }
-
-    const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
-    if (shouldCommit) {
-        commitTransactions();
-    }
-
-    if (!needsTraversal) {
-        // Invoke empty transaction callbacks early.
-        mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
-    } else {
-        // Invoke OnCommit callbacks.
-        mTransactionCallbackInvoker.sendCallbacks(true /* onCommitOnly */);
-    }
-
-    if (transactionFlushNeeded()) {
-        setTransactionFlags(eTransactionFlushNeeded);
-    }
-
-    return shouldCommit;
-}
-
 void SurfaceFlinger::composite(nsecs_t frameTime) {
     ATRACE_CALL();
 
@@ -2074,7 +2056,7 @@
     const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
     refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
     refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
-    refreshArgs.scheduledFrameTime = mEventQueue->getScheduledFrameTime();
+    refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
 
     // Store the present time just before calling to the composition engine so we could notify
     // the scheduler.
@@ -2113,12 +2095,12 @@
     modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
 
     mLayersWithQueuedFrames.clear();
-    if (mTracingEnabled && mTracePostComposition) {
-        // This may block if SurfaceTracing is running in sync mode.
+    if (mTracingEnabled) {
+        // This will block and should only be used for debugging.
         if (mVisibleRegionsDirty) {
-            mTracing.notify("visibleRegionsDirty");
-        } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) {
-            mTracing.notify("bufferLatched");
+            mLayerTracing.notify("visibleRegionsDirty");
+        } else if (mLayerTracing.flagIsSet(LayerTracing::TRACE_BUFFERS)) {
+            mLayerTracing.notify("bufferLatched");
         }
     }
 
@@ -2801,7 +2783,7 @@
     mDisplays.erase(displayToken);
 
     if (display && display->isVirtual()) {
-        static_cast<void>(schedule([display = std::move(display)] {
+        static_cast<void>(mScheduler->schedule([display = std::move(display)] {
             // Destroy the display without holding the mStateLock.
             // This is a temporary solution until we can manage transaction queues without
             // holding the mStateLock.
@@ -3041,50 +3023,47 @@
     mInputWindowCommands.clear();
 }
 
-bool enablePerWindowInputRotation() {
-    static bool value =
-            android::base::GetBoolProperty("persist.debug.per_window_input_rotation", true);
-    return value;
-}
-
 void SurfaceFlinger::notifyWindowInfos() {
     std::vector<WindowInfo> windowInfos;
     std::vector<DisplayInfo> displayInfos;
-    std::unordered_map<uint32_t /*layerStackId*/, const ui::Transform> displayTransforms;
+    std::unordered_map<uint32_t /*layerStackId*/,
+                       std::pair<bool /* isSecure */, const ui::Transform>>
+            inputDisplayDetails;
 
-    if (enablePerWindowInputRotation()) {
-        for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
-            if (!display->receivesInput()) {
-                continue;
-            }
-            const uint32_t layerStackId = display->getLayerStack().id;
-            const auto& [info, transform] = display->getInputInfo();
-            const auto& [it, emplaced] = displayTransforms.try_emplace(layerStackId, transform);
-            if (!emplaced) {
-                ALOGE("Multiple displays claim to accept input for the same layer stack: %u",
-                      layerStackId);
-                continue;
-            }
-            displayInfos.emplace_back(info);
+    for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+        if (!display->receivesInput()) {
+            continue;
         }
+        const uint32_t layerStackId = display->getLayerStack().id;
+        const auto& [info, transform] = display->getInputInfo();
+        const auto& [it, emplaced] =
+                inputDisplayDetails.try_emplace(layerStackId, display->isSecure(), transform);
+        if (!emplaced) {
+            ALOGE("Multiple displays claim to accept input for the same layer stack: %u",
+                  layerStackId);
+            continue;
+        }
+        displayInfos.emplace_back(info);
     }
 
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
         if (!layer->needsInputInfo()) return;
 
-        const DisplayDevice* display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get();
+        bool isSecure = true;
         ui::Transform displayTransform = ui::Transform();
 
-        if (enablePerWindowInputRotation() && display != nullptr) {
-            // When calculating the screen bounds we ignore the transparent region since it may
-            // result in an unwanted offset.
-            const auto it = displayTransforms.find(display->getLayerStack().id);
-            if (it != displayTransforms.end()) {
-                displayTransform = it->second;
-            }
+        const uint32_t layerStackId = layer->getLayerStack().id;
+        const auto it = inputDisplayDetails.find(layerStackId);
+        if (it != inputDisplayDetails.end()) {
+            const auto& [secure, transform] = it->second;
+            isSecure = secure;
+            displayTransform = transform;
+        } else {
+            ALOGE("No input-enabled display found for layer `%s` on layer stack id: %d",
+                  layer->getDebugName(), layerStackId);
         }
-        const bool displayIsSecure = !display || display->isSecure();
-        windowInfos.push_back(layer->fillInputInfo(displayTransform, displayIsSecure));
+
+        windowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
     });
     mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
                                                     mInputWindowCommands.syncInputWindows);
@@ -3149,8 +3128,20 @@
     mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate);
     mVsyncModulator = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs());
 
-    // start the EventThread
-    mScheduler = getFactory().createScheduler(display->holdRefreshRateConfigs(), *this);
+    const Scheduler::Options options = {
+            .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)};
+
+    mScheduler = std::make_unique<Scheduler>(static_cast<ICompositor&>(*this),
+                                             static_cast<ISchedulerCallback&>(*this), options);
+    {
+        auto configs = display->holdRefreshRateConfigs();
+        mScheduler->createVsyncSchedule(configs->supportsKernelIdleTimer());
+        mScheduler->setRefreshRateConfigs(std::move(configs));
+    }
+
+    setVsyncEnabled(false);
+    mScheduler->startTimers();
+
     const auto configs = mVsyncConfiguration->getCurrentConfigs();
     const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs();
     mAppConnectionHandle =
@@ -3166,8 +3157,8 @@
                                              mInterceptor->saveVSyncEvent(timestamp);
                                          });
 
-    mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
-                           configs.late.sfWorkDuration);
+    mScheduler->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
+                          configs.late.sfWorkDuration);
 
     mRegionSamplingThread =
             new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables());
@@ -3201,7 +3192,7 @@
     mScheduler->setDuration(mSfConnectionHandle,
                             /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
                             /*readyDuration=*/config.sfWorkDuration);
-    mEventQueue->setDuration(config.sfWorkDuration);
+    mScheduler->setDuration(config.sfWorkDuration);
 }
 
 void SurfaceFlinger::doCommitTransactions() {
@@ -3355,20 +3346,15 @@
 }
 
 status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
-                                        const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
-                                        const wp<Layer>& parent, bool addToRoot,
-                                        uint32_t* outTransformHint) {
+                                        const sp<Layer>& lbc, const wp<Layer>& parent,
+                                        bool addToRoot, uint32_t* outTransformHint) {
     if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) {
         ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
               ISurfaceComposer::MAX_LAYERS);
         return NO_MEMORY;
     }
 
-    wp<IBinder> initialProducer;
-    if (gbc != nullptr) {
-        initialProducer = IInterface::asBinder(gbc);
-    }
-    setLayerCreatedState(handle, lbc, parent, initialProducer, addToRoot);
+    setLayerCreatedState(handle, lbc, parent, addToRoot);
 
     // Create a transaction includes the initial parent and producer.
     Vector<ComposerState> states;
@@ -3384,7 +3370,9 @@
         *outTransformHint = mActiveDisplayTransformHint;
     }
     // attach this layer to the client
-    client->attachLayer(handle, lbc);
+    if (client != nullptr) {
+        client->attachLayer(handle, lbc);
+    }
 
     return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr,
                                InputWindowCommands{}, -1 /* desiredPresentTime */,
@@ -3392,13 +3380,6 @@
                                0 /* Undefined transactionId */);
 }
 
-void SurfaceFlinger::removeGraphicBufferProducerAsync(const wp<IBinder>& binder) {
-    static_cast<void>(schedule([=] {
-        Mutex::Autolock lock(mStateLock);
-        mGraphicBufferProducerList.erase(binder);
-    }));
-}
-
 uint32_t SurfaceFlinger::getTransactionFlags() const {
     return mTransactionFlags;
 }
@@ -3576,10 +3557,13 @@
 bool SurfaceFlinger::checkTransactionCanLatchUnsignaled(const TransactionState& transaction) {
     if (transaction.states.size() == 1) {
         const auto& state = transaction.states.begin()->state;
-        return (state.flags & ~layer_state_t::eBufferChanged) == 0 &&
-                state.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) &&
-                state.bufferData.acquireFence &&
-                state.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled;
+        if ((state.flags & ~layer_state_t::eBufferChanged) == 0 &&
+            state.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) &&
+            state.bufferData.acquireFence &&
+            state.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled) {
+            ATRACE_NAME("transactionCanLatchUnsignaled");
+            return true;
+        }
     }
     return false;
 }
@@ -3803,10 +3787,11 @@
         transactionFlags |= setDisplayStateLocked(display);
     }
 
-    // Add listeners w/ surfaces so they can get their callback.  Note that listeners with
-    // SurfaceControls will start registration during setClientStateLocked below.
+    // start and end registration for listeners w/ no surface so they can get their callback.  Note
+    // that listeners with SurfaceControls will start registration during setClientStateLocked
+    // below.
     for (const auto& listener : listenerCallbacks) {
-        mTransactionCallbackInvoker.addEmptyCallback(listener);
+        mTransactionCallbackInvoker.addEmptyTransaction(listener);
     }
 
     uint32_t clientStateFlags = 0;
@@ -3978,7 +3963,7 @@
     }
     if (layer == nullptr) {
         for (auto& [listener, callbackIds] : s.listeners) {
-            mTransactionCallbackInvoker.addUnpresentedCallbackHandle(
+            mTransactionCallbackInvoker.registerUnpresentedCallbackHandle(
                     new CallbackHandle(listener, callbackIds, s.surface));
         }
         return 0;
@@ -4249,6 +4234,12 @@
             flags |= eTransactionNeeded | eTraversalNeeded;
         }
     }
+    std::vector<sp<CallbackHandle>> callbackHandles;
+    if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) {
+        for (auto& [listener, callbackIds] : filteredListeners) {
+            callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
+        }
+    }
 
     if (what & layer_state_t::eBufferChanged &&
         layer->setBuffer(s.bufferData, postTime, desiredPresentTime, isAutoTimestamp,
@@ -4258,11 +4249,7 @@
         layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime);
     }
 
-    if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) {
-        if (layer->setTransactionCompletedListeners(filteredListeners, s.surface)) {
-            flags |= eTraversalNeeded;
-        }
-    }
+    if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
     // Do not put anything that updates layer state or modifies flags after
     // setTransactionCompletedListener
     return flags;
@@ -4281,17 +4268,14 @@
 
     sp<Layer> mirrorLayer;
     sp<Layer> mirrorFrom;
-    std::string layerName = "MirrorRoot";
-
     {
         Mutex::Autolock _l(mStateLock);
         mirrorFrom = fromHandle(mirrorFromHandle).promote();
         if (!mirrorFrom) {
             return NAME_NOT_FOUND;
         }
-
-        status_t result = createContainerLayer(client, std::move(layerName), -1, -1, 0,
-                                               LayerMetadata(), outHandle, &mirrorLayer);
+        LayerCreationArgs args(this, client, "MirrorRoot", 0, LayerMetadata());
+        status_t result = createContainerLayer(args, outHandle, &mirrorLayer);
         if (result != NO_ERROR) {
             return result;
         }
@@ -4300,22 +4284,13 @@
     }
 
     *outLayerId = mirrorLayer->sequence;
-    return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, false,
-                          nullptr /* outTransformHint */);
+    return addClientLayer(client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */,
+                          false /* addAsRoot */, nullptr /* outTransformHint */);
 }
 
-status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
-                                     uint32_t h, PixelFormat format, uint32_t flags,
-                                     LayerMetadata metadata, sp<IBinder>* handle,
-                                     sp<IGraphicBufferProducer>* gbp,
+status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
                                      const sp<IBinder>& parentHandle, int32_t* outLayerId,
                                      const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
-    if (int32_t(w|h) < 0) {
-        ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
-                int(w), int(h));
-        return BAD_VALUE;
-    }
-
     ALOG_ASSERT(parentLayer == nullptr || parentHandle == nullptr,
             "Expected only one of parentLayer or parentHandle to be non-null. "
             "Programmer error?");
@@ -4324,40 +4299,22 @@
 
     sp<Layer> layer;
 
-    std::string layerName{name.string()};
-
-    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
+    switch (args.flags & ISurfaceComposerClient::eFXSurfaceMask) {
         case ISurfaceComposerClient::eFXSurfaceBufferQueue:
         case ISurfaceComposerClient::eFXSurfaceBufferState: {
-            result = createBufferStateLayer(client, std::move(layerName), w, h, flags,
-                                            std::move(metadata), handle, &layer);
+            result = createBufferStateLayer(args, outHandle, &layer);
             std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter();
             if (pendingBufferCounter) {
                 std::string counterName = layer->getPendingBufferCounterName();
-                mBufferCountTracker.add((*handle)->localBinder(), counterName,
+                mBufferCountTracker.add((*outHandle)->localBinder(), counterName,
                                         pendingBufferCounter);
             }
         } break;
         case ISurfaceComposerClient::eFXSurfaceEffect:
-            // check if buffer size is set for color layer.
-            if (w > 0 || h > 0) {
-                ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)",
-                      int(w), int(h));
-                return BAD_VALUE;
-            }
-
-            result = createEffectLayer(client, std::move(layerName), w, h, flags,
-                                       std::move(metadata), handle, &layer);
+            result = createEffectLayer(args, outHandle, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceContainer:
-            // check if buffer size is set for container layer.
-            if (w > 0 || h > 0) {
-                ALOGE("createLayer() failed, w or h cannot be set for container layer (w=%d, h=%d)",
-                      int(w), int(h));
-                return BAD_VALUE;
-            }
-            result = createContainerLayer(client, std::move(layerName), w, h, flags,
-                                          std::move(metadata), handle, &layer);
+            result = createContainerLayer(args, outHandle, &layer);
             break;
         default:
             result = BAD_VALUE;
@@ -4377,7 +4334,7 @@
     if (parentLayer != nullptr) {
         addToRoot = false;
     }
-    result = addClientLayer(client, *handle, *gbp, layer, parent, addToRoot, outTransformHint);
+    result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint);
     if (result != NO_ERROR) {
         return result;
     }
@@ -4387,9 +4344,7 @@
     return result;
 }
 
-status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::string name,
-                                                uint32_t w, uint32_t h, uint32_t flags,
-                                                LayerMetadata metadata, PixelFormat& format,
+status_t SurfaceFlinger::createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format,
                                                 sp<IBinder>* handle,
                                                 sp<IGraphicBufferProducer>* gbp,
                                                 sp<Layer>* outLayer) {
@@ -4405,7 +4360,6 @@
     }
 
     sp<BufferQueueLayer> layer;
-    LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
     args.textureName = getNewTexture();
     {
         // Grab the SF state lock during this since it's the only safe way to access
@@ -4415,7 +4369,7 @@
         layer = getFactory().createBufferQueueLayer(args);
     }
 
-    status_t err = layer->setDefaultBufferProperties(w, h, format);
+    status_t err = layer->setDefaultBufferProperties(0, 0, format);
     if (err == NO_ERROR) {
         *handle = layer->getHandle();
         *gbp = layer->getProducer();
@@ -4426,34 +4380,24 @@
     return err;
 }
 
-status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, std::string name,
-                                                uint32_t w, uint32_t h, uint32_t flags,
-                                                LayerMetadata metadata, sp<IBinder>* handle,
+status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* handle,
                                                 sp<Layer>* outLayer) {
-    LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
     args.textureName = getNewTexture();
-    sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args);
-    *handle = layer->getHandle();
-    *outLayer = layer;
-
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::createEffectLayer(const sp<Client>& client, std::string name, uint32_t w,
-                                           uint32_t h, uint32_t flags, LayerMetadata metadata,
-                                           sp<IBinder>* handle, sp<Layer>* outLayer) {
-    *outLayer = getFactory().createEffectLayer(
-            {this, client, std::move(name), w, h, flags, std::move(metadata)});
+    *outLayer = getFactory().createBufferStateLayer(args);
     *handle = (*outLayer)->getHandle();
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client, std::string name,
-                                              uint32_t w, uint32_t h, uint32_t flags,
-                                              LayerMetadata metadata, sp<IBinder>* handle,
+status_t SurfaceFlinger::createEffectLayer(LayerCreationArgs& args, sp<IBinder>* handle,
+                                           sp<Layer>* outLayer) {
+    *outLayer = getFactory().createEffectLayer(args);
+    *handle = (*outLayer)->getHandle();
+    return NO_ERROR;
+}
+
+status_t SurfaceFlinger::createContainerLayer(LayerCreationArgs& args, sp<IBinder>* handle,
                                               sp<Layer>* outLayer) {
-    *outLayer = getFactory().createContainerLayer(
-            {this, client, std::move(name), w, h, flags, std::move(metadata)});
+    *outLayer = getFactory().createContainerLayer(args);
     *handle = (*outLayer)->getHandle();
     return NO_ERROR;
 }
@@ -4522,26 +4466,7 @@
 
 void SurfaceFlinger::initializeDisplays() {
     // Async since we may be called from the main thread.
-    static_cast<void>(schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
-}
-
-sp<DisplayDevice> SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const {
-    const auto filter = layer->getOutputFilter();
-    sp<DisplayDevice> inputDisplay;
-
-    for (const auto& [_, display] : mDisplays) {
-        if (!display->receivesInput() || !display->getCompositionDisplay()->includesLayer(filter)) {
-            continue;
-        }
-        // Don't return immediately so that we can log duplicates.
-        if (inputDisplay) {
-            ALOGE("Multiple displays claim to accept input for the same layer stack: %u",
-                  filter.layerStack.id);
-            continue;
-        }
-        inputDisplay = display;
-    }
-    return inputDisplay;
+    static_cast<void>(mScheduler->schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
 }
 
 void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
@@ -4641,7 +4566,7 @@
 }
 
 void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
-    schedule([=]() MAIN_THREAD {
+    auto future = mScheduler->schedule([=]() MAIN_THREAD {
         const auto display = getDisplayDeviceLocked(displayToken);
         if (!display) {
             ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4651,7 +4576,9 @@
         } else {
             setPowerModeInternal(display, static_cast<hal::PowerMode>(mode));
         }
-    }).wait();
+    });
+
+    future.wait();
 }
 
 status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) {
@@ -4701,7 +4628,7 @@
         }
 
         if (dumpLayers) {
-            LayersTraceFileProto traceFileProto = SurfaceTracing::createLayersTraceFileProto();
+            LayersTraceFileProto traceFileProto = mLayerTracing.createTraceFileProto();
             LayersTraceProto* layersTrace = traceFileProto.add_entry();
             LayersProto layersProto = dumpProtoFromMainThread();
             layersTrace->mutable_layers()->Swap(&layersProto);
@@ -4723,8 +4650,8 @@
 }
 
 status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
-    if (asProto && mTracing.isEnabled()) {
-        mTracing.writeToFile();
+    if (asProto && mLayerTracing.isEnabled()) {
+        mLayerTracing.writeToFile();
     }
 
     return doDump(fd, DumpArgs(), asProto);
@@ -4973,21 +4900,21 @@
 }
 
 LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
-    return schedule([=] { return dumpDrawingStateProto(traceFlags); }).get();
+    return mScheduler->schedule([=] { return dumpDrawingStateProto(traceFlags); }).get();
 }
 
 void SurfaceFlinger::dumpOffscreenLayers(std::string& result) {
+    auto future = mScheduler->schedule([this] {
+        std::string result;
+        for (Layer* offscreenLayer : mOffscreenLayers) {
+            offscreenLayer->traverse(LayerVector::StateSet::Drawing,
+                                     [&](Layer* layer) { layer->dumpCallingUidPid(result); });
+        }
+        return result;
+    });
+
     result.append("Offscreen Layers:\n");
-    result.append(schedule([this] {
-                      std::string result;
-                      for (Layer* offscreenLayer : mOffscreenLayers) {
-                          offscreenLayer->traverse(LayerVector::StateSet::Drawing,
-                                                   [&](Layer* layer) {
-                                                       layer->dumpCallingUidPid(result);
-                                                   });
-                      }
-                      return result;
-                  }).get());
+    result.append(future.get());
 }
 
 void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
@@ -5039,8 +4966,6 @@
      */
     colorizer.bold(result);
     StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load());
-    StringAppendF(&result, "GraphicBufferProducers: %zu, max %zu\n",
-                  mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
     colorizer.reset(result);
 
     {
@@ -5122,7 +5047,7 @@
     /*
      * Tracing state
      */
-    mTracing.dump(result);
+    mLayerTracing.dump(result);
     result.append("\n");
 
     /*
@@ -5399,6 +5324,7 @@
                 scheduleRepaint();
                 return NO_ERROR;
             case 1004: // Force composite ahead of next VSYNC.
+            case 1006:
                 scheduleComposite(FrameHint::kActive);
                 return NO_ERROR;
             case 1005: { // Force commit ahead of next VSYNC.
@@ -5407,9 +5333,6 @@
                                     eTraversalNeeded);
                 return NO_ERROR;
             }
-            case 1006: // Force composite immediately.
-                mEventQueue->scheduleComposite();
-                return NO_ERROR;
             case 1007: // Unused.
                 return NAME_NOT_FOUND;
             case 1008: // Toggle forced GPU composition.
@@ -5520,7 +5443,8 @@
             }
             case 1021: { // Disable HWC virtual displays
                 const bool enable = data.readInt32() != 0;
-                static_cast<void>(schedule([this, enable] { enableHalVirtualDisplays(enable); }));
+                static_cast<void>(
+                        mScheduler->schedule([this, enable] { enableHalVirtualDisplays(enable); }));
                 return NO_ERROR;
             }
             case 1022: { // Set saturation boost
@@ -5549,20 +5473,21 @@
                 bool tracingEnabledChanged;
                 if (n) {
                     ALOGD("LayerTracing enabled");
-                    tracingEnabledChanged = mTracing.enable();
+                    tracingEnabledChanged = mLayerTracing.enable();
                     if (tracingEnabledChanged) {
-                        schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait();
+                        mScheduler->schedule([&]() MAIN_THREAD { mLayerTracing.notify("start"); })
+                                .wait();
                     }
                 } else {
                     ALOGD("LayerTracing disabled");
-                    tracingEnabledChanged = mTracing.disable();
+                    tracingEnabledChanged = mLayerTracing.disable();
                 }
                 mTracingEnabledChanged = tracingEnabledChanged;
                 reply->writeInt32(NO_ERROR);
                 return NO_ERROR;
             }
             case 1026: { // Get layer tracing status
-                reply->writeBool(mTracing.isEnabled());
+                reply->writeBool(mLayerTracing.isEnabled());
                 return NO_ERROR;
             }
             // Is a DisplayColorSetting supported?
@@ -5603,7 +5528,7 @@
                 }
 
                 ALOGD("Updating trace buffer to %d KB", n);
-                mTracing.setBufferSize(n * 1024);
+                mLayerTracing.setBufferSize(n * 1024);
                 reply->writeInt32(NO_ERROR);
                 return NO_ERROR;
             }
@@ -5648,12 +5573,12 @@
             case 1033: {
                 n = data.readUint32();
                 ALOGD("Updating trace flags to 0x%x", n);
-                mTracing.setTraceFlags(n);
+                mLayerTracing.setTraceFlags(n);
                 reply->writeInt32(NO_ERROR);
                 return NO_ERROR;
             }
             case 1034: {
-                schedule([&] {
+                auto future = mScheduler->schedule([&] {
                     switch (n = data.readInt32()) {
                         case 0:
                         case 1:
@@ -5663,7 +5588,9 @@
                             reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled()));
                         }
                     }
-                }).get();
+                });
+
+                future.wait();
                 return NO_ERROR;
             }
             case 1035: {
@@ -5693,32 +5620,36 @@
             // rates.
             case 1036: {
                 if (data.readInt32() > 0) { // turn on
-                    return schedule([this] {
-                               const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+                    return mScheduler
+                            ->schedule([this] {
+                                const auto display =
+                                        ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
 
-                               // This is a little racy, but not in a way that hurts anything. As we
-                               // grab the defaultMode from the display manager policy, we could be
-                               // setting a new display manager policy, leaving us using a stale
-                               // defaultMode. The defaultMode doesn't matter for the override
-                               // policy though, since we set allowGroupSwitching to true, so it's
-                               // not a problem.
-                               scheduler::RefreshRateConfigs::Policy overridePolicy;
-                               overridePolicy.defaultMode = display->refreshRateConfigs()
-                                                                    .getDisplayManagerPolicy()
-                                                                    .defaultMode;
-                               overridePolicy.allowGroupSwitching = true;
-                               constexpr bool kOverridePolicy = true;
-                               return setDesiredDisplayModeSpecsInternal(display, overridePolicy,
-                                                                         kOverridePolicy);
-                           })
+                                // This is a little racy, but not in a way that hurts anything. As
+                                // we grab the defaultMode from the display manager policy, we could
+                                // be setting a new display manager policy, leaving us using a stale
+                                // defaultMode. The defaultMode doesn't matter for the override
+                                // policy though, since we set allowGroupSwitching to true, so it's
+                                // not a problem.
+                                scheduler::RefreshRateConfigs::Policy overridePolicy;
+                                overridePolicy.defaultMode = display->refreshRateConfigs()
+                                                                     .getDisplayManagerPolicy()
+                                                                     .defaultMode;
+                                overridePolicy.allowGroupSwitching = true;
+                                constexpr bool kOverridePolicy = true;
+                                return setDesiredDisplayModeSpecsInternal(display, overridePolicy,
+                                                                          kOverridePolicy);
+                            })
                             .get();
                 } else { // turn off
-                    return schedule([this] {
-                               const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
-                               constexpr bool kOverridePolicy = true;
-                               return setDesiredDisplayModeSpecsInternal(display, {},
-                                                                         kOverridePolicy);
-                           })
+                    return mScheduler
+                            ->schedule([this] {
+                                const auto display =
+                                        ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+                                constexpr bool kOverridePolicy = true;
+                                return setDesiredDisplayModeSpecsInternal(display, {},
+                                                                          kOverridePolicy);
+                            })
                             .get();
                 }
             }
@@ -5763,31 +5694,29 @@
             // Second argument is an optional uint64 - if present, then limits enabling/disabling
             // caching to a particular physical display
             case 1040: {
-                status_t error =
-                        schedule([&] {
-                            n = data.readInt32();
-                            std::optional<PhysicalDisplayId> inputId = std::nullopt;
-                            if (uint64_t inputDisplayId;
-                                data.readUint64(&inputDisplayId) == NO_ERROR) {
-                                inputId = DisplayId::fromValue<PhysicalDisplayId>(inputDisplayId);
-                                if (!inputId || getPhysicalDisplayToken(*inputId)) {
-                                    ALOGE("No display with id: %" PRIu64, inputDisplayId);
-                                    return NAME_NOT_FOUND;
-                                }
+                auto future = mScheduler->schedule([&] {
+                    n = data.readInt32();
+                    std::optional<PhysicalDisplayId> inputId = std::nullopt;
+                    if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) {
+                        inputId = DisplayId::fromValue<PhysicalDisplayId>(inputDisplayId);
+                        if (!inputId || getPhysicalDisplayToken(*inputId)) {
+                            ALOGE("No display with id: %" PRIu64, inputDisplayId);
+                            return NAME_NOT_FOUND;
+                        }
+                    }
+                    {
+                        Mutex::Autolock lock(mStateLock);
+                        mLayerCachingEnabled = n != 0;
+                        for (const auto& [_, display] : mDisplays) {
+                            if (!inputId || *inputId == display->getPhysicalId()) {
+                                display->enableLayerCaching(mLayerCachingEnabled);
                             }
-                            {
-                                Mutex::Autolock lock(mStateLock);
-                                mLayerCachingEnabled = n != 0;
-                                for (const auto& [_, display] : mDisplays) {
-                                    if (!inputId || *inputId == display->getPhysicalId()) {
-                                        display->enableLayerCaching(mLayerCachingEnabled);
-                                    }
-                                }
-                            }
-                            return OK;
-                        }).get();
+                        }
+                    }
+                    return OK;
+                });
 
-                if (error != OK) {
+                if (const status_t error = future.get(); error != OK) {
                     return error;
                 }
                 scheduleRepaint();
@@ -5806,7 +5735,7 @@
 
     // Update the overlay on the main thread to avoid race conditions with
     // mRefreshRateConfigs->getCurrentRefreshRate()
-    static_cast<void>(schedule([=] {
+    static_cast<void>(mScheduler->schedule([=] {
         const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
         if (!display) {
             ALOGW("%s: default display is null", __func__);
@@ -5821,7 +5750,7 @@
         const bool timerExpired = mKernelIdleTimerEnabled && expired;
 
         if (display->onKernelTimerChanged(desiredModeId, timerExpired)) {
-            mEventQueue->scheduleCommit();
+            mScheduler->scheduleFrame();
         }
     }));
 }
@@ -6213,14 +6142,15 @@
     const bool supportsProtected = getRenderEngine().supportsProtectedContent();
     bool hasProtectedLayer = false;
     if (allowProtected && supportsProtected) {
-        hasProtectedLayer = schedule([=]() {
-                                bool protectedLayerFound = false;
-                                traverseLayers([&](Layer* layer) {
-                                    protectedLayerFound = protectedLayerFound ||
-                                            (layer->isVisible() && layer->isProtected());
-                                });
-                                return protectedLayerFound;
-                            }).get();
+        auto future = mScheduler->schedule([=]() {
+            bool protectedLayerFound = false;
+            traverseLayers([&](Layer* layer) {
+                protectedLayerFound =
+                        protectedLayerFound || (layer->isVisible() && layer->isProtected());
+            });
+            return protectedLayerFound;
+        });
+        hasProtectedLayer = future.get();
     }
 
     const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER |
@@ -6251,9 +6181,11 @@
 
     bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
 
-    auto scheduleResultFuture = schedule([=,
-                                          renderAreaFuture = std::move(renderAreaFuture)]() mutable
-                                         -> std::shared_future<renderengine::RenderEngineResult> {
+    auto scheduleResultFuture = mScheduler->schedule([=,
+                                                      renderAreaFuture =
+                                                              std::move(renderAreaFuture)]() mutable
+                                                     -> std::shared_future<
+                                                             renderengine::RenderEngineResult> {
         ScreenCaptureResults captureResults;
         std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
         if (!renderArea) {
@@ -6546,7 +6478,7 @@
         return BAD_VALUE;
     }
 
-    auto future = schedule([=]() -> status_t {
+    auto future = mScheduler->schedule([=]() -> status_t {
         const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
         if (!display) {
             ALOGE("Attempt to set desired display modes for invalid display token %p",
@@ -6683,7 +6615,7 @@
         return BAD_VALUE;
     }
 
-    static_cast<void>(schedule([=] {
+    static_cast<void>(mScheduler->schedule([=] {
         Mutex::Autolock lock(mStateLock);
         if (authenticateSurfaceTextureLocked(surface)) {
             sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
@@ -6802,11 +6734,10 @@
 }
 
 void SurfaceFlinger::setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer,
-                                          const wp<Layer> parent, const wp<IBinder>& producer,
-                                          bool addToRoot) {
+                                          const wp<Layer> parent, bool addToRoot) {
     Mutex::Autolock lock(mCreatedLayersLock);
     mCreatedLayers[handle->localBinder()] =
-            std::make_unique<LayerCreatedState>(layer, parent, producer, addToRoot);
+            std::make_unique<LayerCreatedState>(layer, parent, addToRoot);
 }
 
 auto SurfaceFlinger::getLayerCreatedState(const sp<IBinder>& handle) {
@@ -6867,19 +6798,6 @@
 
     layer->updateTransformHint(mActiveDisplayTransformHint);
 
-    if (state->initialProducer != nullptr) {
-        mGraphicBufferProducerList.insert(state->initialProducer);
-        LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > mMaxGraphicBufferProducerListSize,
-                            "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
-                            mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize,
-                            mNumLayers.load());
-        if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) {
-            ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
-                  mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize,
-                  mNumLayers.load());
-        }
-    }
-
     mInterceptor->saveSurfaceCreation(layer);
     return layer;
 }
@@ -6889,7 +6807,7 @@
         return;
     }
 
-    mRegionSamplingThread->onCompositionComplete(mEventQueue->getScheduledFrameTime());
+    mRegionSamplingThread->onCompositionComplete(mScheduler->getScheduledFrameTime());
 }
 
 void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bf628dc..6093be9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -56,14 +56,13 @@
 #include "Fps.h"
 #include "FrameTracker.h"
 #include "LayerVector.h"
-#include "Scheduler/MessageQueue.h"
 #include "Scheduler/RefreshRateConfigs.h"
 #include "Scheduler/RefreshRateStats.h"
 #include "Scheduler/Scheduler.h"
 #include "Scheduler/VsyncModulator.h"
 #include "SurfaceFlingerFactory.h"
-#include "SurfaceTracing.h"
 #include "TracedOrdinal.h"
+#include "Tracing/LayerTracing.h"
 #include "TransactionCallbackInvoker.h"
 #include "TransactionState.h"
 
@@ -265,10 +264,6 @@
     SurfaceFlingerBE& getBE() { return mBE; }
     const SurfaceFlingerBE& getBE() const { return mBE; }
 
-    // Schedule an asynchronous or synchronous task on the main thread.
-    template <typename F, typename T = std::invoke_result_t<F>>
-    [[nodiscard]] std::future<T> schedule(F&&);
-
     // Schedule commit of transactions on the main thread ahead of the next VSYNC.
     void scheduleCommit(FrameHint);
     // As above, but also force composite regardless if transactions were committed.
@@ -353,7 +348,7 @@
     friend class MonitoredProducer;
     friend class RefreshRateOverlay;
     friend class RegionSamplingThread;
-    friend class SurfaceTracing;
+    friend class LayerTracing;
 
     // For unit tests
     friend class TestableSurfaceFlinger;
@@ -684,9 +679,6 @@
             const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
             EXCLUDES(mStateLock);
 
-    // Returns whether transactions were committed.
-    bool flushAndCommitTransactions() EXCLUDES(mStateLock);
-
     void commitTransactions() EXCLUDES(mStateLock);
     void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
     void doCommitTransactions() REQUIRES(mStateLock);
@@ -763,29 +755,23 @@
     /*
      * Layer management
      */
-    status_t createLayer(const String8& name, const sp<Client>& client, uint32_t w, uint32_t h,
-                         PixelFormat format, uint32_t flags, LayerMetadata metadata,
-                         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp,
+    status_t createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
                          const sp<IBinder>& parentHandle, int32_t* outLayerId,
                          const sp<Layer>& parentLayer = nullptr,
                          uint32_t* outTransformHint = nullptr);
 
-    status_t createBufferQueueLayer(const sp<Client>& client, std::string name, uint32_t w,
-                                    uint32_t h, uint32_t flags, LayerMetadata metadata,
-                                    PixelFormat& format, sp<IBinder>* outHandle,
-                                    sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
+    status_t createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format,
+                                    sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
+                                    sp<Layer>* outLayer);
 
-    status_t createBufferStateLayer(const sp<Client>& client, std::string name, uint32_t w,
-                                    uint32_t h, uint32_t flags, LayerMetadata metadata,
-                                    sp<IBinder>* outHandle, sp<Layer>* outLayer);
+    status_t createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
+                                    sp<Layer>* outLayer);
 
-    status_t createEffectLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
-                               uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
+    status_t createEffectLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
                                sp<Layer>* outLayer);
 
-    status_t createContainerLayer(const sp<Client>& client, std::string name, uint32_t w,
-                                  uint32_t h, uint32_t flags, LayerMetadata metadata,
-                                  sp<IBinder>* outHandle, sp<Layer>* outLayer);
+    status_t createContainerLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
+                                  sp<Layer>* outLayer);
 
     status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
                          sp<IBinder>* outHandle, int32_t* outLayerId);
@@ -798,8 +784,7 @@
 
     // add a layer to SurfaceFlinger
     status_t addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
-                            const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
-                            const wp<Layer>& parentLayer, bool addToRoot,
+                            const sp<Layer>& lbc, const wp<Layer>& parentLayer, bool addToRoot,
                             uint32_t* outTransformHint);
 
     // Traverse through all the layers and compute and cache its bounds.
@@ -897,8 +882,6 @@
     // region of all screens presenting this layer stack.
     void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
 
-    sp<DisplayDevice> getDisplayWithInputByLayer(Layer* layer) const REQUIRES(mStateLock);
-
     bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) {
         return display->getDisplayToken() == mActiveDisplayToken;
     }
@@ -1049,12 +1032,12 @@
     void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock);
     LayersProto dumpDrawingStateProto(uint32_t traceFlags) const;
     void dumpOffscreenLayersProto(LayersProto& layersProto,
-                                  uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+                                  uint32_t traceFlags = LayerTracing::TRACE_ALL) const;
     void dumpDisplayProto(LayersTraceProto& layersTraceProto) const;
 
     // Dumps state from HW Composer
     void dumpHwc(std::string& result) const;
-    LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
+    LayersProto dumpProtoFromMainThread(uint32_t traceFlags = LayerTracing::TRACE_ALL)
             EXCLUDES(mStateLock);
     void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock);
     void dumpPlannerInfo(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
@@ -1115,16 +1098,12 @@
     float mGlobalSaturationFactor = 1.0f;
     mat4 mClientColorMatrix;
 
-    // Can't be unordered_set because wp<> isn't hashable
-    std::set<wp<IBinder>> mGraphicBufferProducerList;
     size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS;
     // If there are more GraphicBufferProducers tracked by SurfaceFlinger than
     // this threshold, then begin logging.
     size_t mGraphicBufferProducerListSizeLogThreshold =
             static_cast<size_t>(0.95 * static_cast<double>(MAX_LAYERS));
 
-    void removeGraphicBufferProducerAsync(const wp<IBinder>&);
-
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved = false;
     bool mLayersAdded = false;
@@ -1201,10 +1180,9 @@
     bool mPropagateBackpressureClientComposition = false;
     sp<SurfaceInterceptor> mInterceptor;
 
-    SurfaceTracing mTracing{*this};
+    LayerTracing mLayerTracing{*this};
     std::mutex mTracingLock;
     bool mTracingEnabled = false;
-    bool mTracePostComposition = false;
     std::atomic<bool> mTracingEnabledChanged = false;
 
     const std::shared_ptr<TimeStats> mTimeStats;
@@ -1221,14 +1199,9 @@
 
     TransactionCallbackInvoker mTransactionCallbackInvoker;
 
-    // these are thread safe
-    std::unique_ptr<MessageQueue> mEventQueue;
+    // Thread-safe.
     FrameTracker mAnimFrameTracker;
 
-    // protected by mDestroyedLayerLock;
-    mutable Mutex mDestroyedLayerLock;
-    Vector<Layer const *> mDestroyedLayers;
-
     // We maintain a pool of pre-generated texture names to hand out to avoid
     // layer creation needing to run on the main thread (which it would
     // otherwise need to do to access RenderEngine).
@@ -1339,19 +1312,12 @@
             GUARDED_BY(mStateLock);
     mutable Mutex mCreatedLayersLock;
     struct LayerCreatedState {
-        LayerCreatedState(const wp<Layer>& layer, const wp<Layer> parent,
-                          const wp<IBinder>& producer, bool addToRoot)
-              : layer(layer),
-                initialParent(parent),
-                initialProducer(producer),
-                addToRoot(addToRoot) {}
+        LayerCreatedState(const wp<Layer>& layer, const wp<Layer> parent, bool addToRoot)
+              : layer(layer), initialParent(parent), addToRoot(addToRoot) {}
         wp<Layer> layer;
         // Indicates the initial parent of the created layer, only used for creating layer in
         // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers.
         wp<Layer> initialParent;
-        // Indicates the initial graphic buffer producer of the created layer, only used for
-        // creating layer in SurfaceFlinger.
-        wp<IBinder> initialProducer;
         // Indicates whether the layer getting created should be added at root if there's no parent
         // and has permission ACCESS_SURFACE_FLINGER. If set to false and no parent, the layer will
         // be added offscreen.
@@ -1362,7 +1328,7 @@
     // thread.
     std::unordered_map<BBinder*, std::unique_ptr<LayerCreatedState>> mCreatedLayers;
     void setLayerCreatedState(const sp<IBinder>& handle, const wp<Layer>& layer,
-                              const wp<Layer> parent, const wp<IBinder>& producer, bool addToRoot);
+                              const wp<Layer> parent, bool addToRoot);
     auto getLayerCreatedState(const sp<IBinder>& handle);
     sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle) REQUIRES(mStateLock);
 
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 9a2f910..b81b445 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -38,7 +38,6 @@
 #include "SurfaceInterceptor.h"
 
 #include "DisplayHardware/ComposerHal.h"
-#include "Scheduler/MessageQueue.h"
 #include "Scheduler/Scheduler.h"
 #include "Scheduler/VsyncConfiguration.h"
 #include "Scheduler/VsyncController.h"
@@ -51,10 +50,6 @@
     return std::make_unique<android::impl::HWComposer>(serviceName);
 }
 
-std::unique_ptr<MessageQueue> DefaultFactory::createMessageQueue(ICompositor& compositor) {
-    return std::make_unique<android::impl::MessageQueue>(compositor);
-}
-
 std::unique_ptr<scheduler::VsyncConfiguration> DefaultFactory::createVsyncConfiguration(
         Fps currentRefreshRate) {
     if (property_get_bool("debug.sf.use_phase_offsets_as_durations", false)) {
@@ -64,12 +59,6 @@
     }
 }
 
-std::unique_ptr<Scheduler> DefaultFactory::createScheduler(
-        const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs,
-        ISchedulerCallback& callback) {
-    return std::make_unique<Scheduler>(std::move(refreshRateConfigs), callback);
-}
-
 sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor() {
     return new android::impl::SurfaceInterceptor();
 }
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 2be09ee..501629d 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -27,11 +27,8 @@
     virtual ~DefaultFactory();
 
     std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
-    std::unique_ptr<MessageQueue> createMessageQueue(ICompositor&) override;
     std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
             Fps currentRefreshRate) override;
-    std::unique_ptr<Scheduler> createScheduler(
-            const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) override;
     sp<SurfaceInterceptor> createSurfaceInterceptor() override;
     sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
     sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index bca533b..e670f37 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -77,11 +77,8 @@
 class Factory {
 public:
     virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
-    virtual std::unique_ptr<MessageQueue> createMessageQueue(ICompositor&) = 0;
     virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
             Fps currentRefreshRate) = 0;
-    virtual std::unique_ptr<Scheduler> createScheduler(
-            const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) = 0;
     virtual sp<SurfaceInterceptor> createSurfaceInterceptor() = 0;
 
     virtual sp<StartPropertySetThread> createStartPropertySetThread(
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
deleted file mode 100644
index 5963737..0000000
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "SurfaceTracing"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "SurfaceTracing.h"
-#include <SurfaceFlinger.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <log/log.h>
-#include <utils/SystemClock.h>
-#include <utils/Trace.h>
-
-namespace android {
-
-SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {}
-
-bool SurfaceTracing::enable() {
-    std::scoped_lock lock(mTraceLock);
-    if (mEnabled) {
-        return false;
-    }
-
-    if (flagIsSet(TRACE_SYNC)) {
-        runner = std::make_unique<SurfaceTracing::Runner>(mFlinger, mConfig);
-    } else {
-        runner = std::make_unique<SurfaceTracing::AsyncRunner>(mFlinger, mConfig,
-                                                               mFlinger.mTracingLock);
-    }
-    mEnabled = true;
-    return true;
-}
-
-bool SurfaceTracing::disable() {
-    std::scoped_lock lock(mTraceLock);
-    if (!mEnabled) {
-        return false;
-    }
-    mEnabled = false;
-    runner->stop();
-    return true;
-}
-
-bool SurfaceTracing::isEnabled() const {
-    std::scoped_lock lock(mTraceLock);
-    return mEnabled;
-}
-
-status_t SurfaceTracing::writeToFile() {
-    std::scoped_lock lock(mTraceLock);
-    if (!mEnabled) {
-        return STATUS_OK;
-    }
-    return runner->writeToFile();
-}
-
-void SurfaceTracing::notify(const char* where) {
-    std::scoped_lock lock(mTraceLock);
-    if (mEnabled) {
-        runner->notify(where);
-    }
-}
-
-void SurfaceTracing::notifyLocked(const char* where) {
-    std::scoped_lock lock(mTraceLock);
-    if (mEnabled) {
-        runner->notifyLocked(where);
-    }
-}
-
-void SurfaceTracing::dump(std::string& result) const {
-    std::scoped_lock lock(mTraceLock);
-    base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
-    if (mEnabled) {
-        runner->dump(result);
-    }
-}
-
-void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
-    // use the swap trick to make sure memory is released
-    std::queue<LayersTraceProto>().swap(mStorage);
-    mSizeInBytes = newSize;
-    mUsedInBytes = 0U;
-}
-
-void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
-    size_t protoSize = static_cast<size_t>(proto.ByteSize());
-    while (mUsedInBytes + protoSize > mSizeInBytes) {
-        if (mStorage.empty()) {
-            return;
-        }
-        mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
-        mStorage.pop();
-    }
-    mUsedInBytes += protoSize;
-    mStorage.emplace();
-    mStorage.back().Swap(&proto);
-}
-
-void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
-    fileProto->mutable_entry()->Reserve(static_cast<int>(mStorage.size()));
-
-    while (!mStorage.empty()) {
-        auto entry = fileProto->add_entry();
-        entry->Swap(&mStorage.front());
-        mStorage.pop();
-    }
-}
-
-SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config)
-      : mFlinger(flinger), mConfig(config) {
-    mBuffer.setSize(mConfig.bufferSize);
-}
-
-void SurfaceTracing::Runner::notify(const char* where) {
-    LayersTraceProto entry = traceLayers(where);
-    mBuffer.emplace(std::move(entry));
-}
-
-status_t SurfaceTracing::Runner::stop() {
-    return writeToFile();
-}
-
-LayersTraceFileProto SurfaceTracing::createLayersTraceFileProto() {
-    LayersTraceFileProto fileProto;
-    fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
-                               LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
-    return fileProto;
-}
-
-status_t SurfaceTracing::Runner::writeToFile() {
-    ATRACE_CALL();
-
-    LayersTraceFileProto fileProto = createLayersTraceFileProto();
-    std::string output;
-
-    mBuffer.flush(&fileProto);
-    mBuffer.reset(mConfig.bufferSize);
-
-    if (!fileProto.SerializeToString(&output)) {
-        ALOGE("Could not save the proto file! Permission denied");
-        return PERMISSION_DENIED;
-    }
-
-    // -rw-r--r--
-    const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
-    if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(),
-                                          true)) {
-        ALOGE("Could not save the proto file! There are missing fields");
-        return PERMISSION_DENIED;
-    }
-
-    return NO_ERROR;
-}
-
-LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) {
-    ATRACE_CALL();
-
-    LayersTraceProto entry;
-    entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
-    entry.set_where(where);
-    LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags));
-
-    if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) {
-        mFlinger.dumpOffscreenLayersProto(layers);
-    }
-    entry.mutable_layers()->Swap(&layers);
-
-    if (flagIsSet(SurfaceTracing::TRACE_HWC)) {
-        std::string hwcDump;
-        mFlinger.dumpHwc(hwcDump);
-        entry.set_hwc_blob(hwcDump);
-    }
-    if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) {
-        entry.set_excludes_composition_state(true);
-    }
-    entry.set_missed_entries(mMissedTraceEntries);
-    mFlinger.dumpDisplayProto(entry);
-    return entry;
-}
-
-void SurfaceTracing::Runner::dump(std::string& result) const {
-    base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n",
-                        mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
-                        float(mBuffer.size()) / float(1_MB));
-}
-
-SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config,
-                                         std::mutex& sfLock)
-      : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) {
-    mEnabled = true;
-    mThread = std::thread(&AsyncRunner::loop, this);
-}
-
-void SurfaceTracing::AsyncRunner::loop() {
-    while (mEnabled) {
-        LayersTraceProto entry;
-        bool entryAdded = traceWhenNotified(&entry);
-        if (entryAdded) {
-            mBuffer.emplace(std::move(entry));
-        }
-        if (mWriteToFile) {
-            Runner::writeToFile();
-            mWriteToFile = false;
-        }
-    }
-}
-
-bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) {
-    std::unique_lock<std::mutex> lock(mSfLock);
-    mCanStartTrace.wait(lock);
-    if (!mAddEntry) {
-        return false;
-    }
-    *outProto = traceLayers(mWhere);
-    mAddEntry = false;
-    mMissedTraceEntries = 0;
-    return true;
-}
-
-void SurfaceTracing::AsyncRunner::notify(const char* where) {
-    std::scoped_lock lock(mSfLock);
-    notifyLocked(where);
-}
-
-void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) {
-    mWhere = where;
-    if (mAddEntry) {
-        mMissedTraceEntries++;
-    }
-    mAddEntry = true;
-    mCanStartTrace.notify_one();
-}
-
-status_t SurfaceTracing::AsyncRunner::writeToFile() {
-    mWriteToFile = true;
-    mCanStartTrace.notify_one();
-    return STATUS_OK;
-}
-
-status_t SurfaceTracing::AsyncRunner::stop() {
-    mEnabled = false;
-    mCanStartTrace.notify_one();
-    mThread.join();
-    return Runner::writeToFile();
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
deleted file mode 100644
index 97adb20..0000000
--- a/services/surfaceflinger/SurfaceTracing.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2017 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 <android-base/thread_annotations.h>
-#include <layerproto/LayerProtoHeader.h>
-#include <utils/Errors.h>
-#include <utils/StrongPointer.h>
-
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-#include <queue>
-#include <thread>
-
-using namespace android::surfaceflinger;
-
-namespace android {
-
-class SurfaceFlinger;
-constexpr auto operator""_MB(unsigned long long const num) {
-    return num * 1024 * 1024;
-}
-/*
- * SurfaceTracing records layer states during surface flinging. Manages tracing state and
- * configuration.
- */
-class SurfaceTracing {
-public:
-    SurfaceTracing(SurfaceFlinger& flinger);
-    bool enable();
-    bool disable();
-    status_t writeToFile();
-    bool isEnabled() const;
-    /*
-     * Adds a trace entry, must be called from the drawing thread or while holding the
-     * SurfaceFlinger tracing lock.
-     */
-    void notify(const char* where);
-    /*
-     * Adds a trace entry, called while holding the SurfaceFlinger tracing lock.
-     */
-    void notifyLocked(const char* where) /* REQUIRES(mSfLock) */;
-
-    void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; }
-    void dump(std::string& result) const;
-
-    enum : uint32_t {
-        TRACE_CRITICAL = 1 << 0,
-        TRACE_INPUT = 1 << 1,
-        TRACE_COMPOSITION = 1 << 2,
-        TRACE_EXTRA = 1 << 3,
-        TRACE_HWC = 1 << 4,
-        // Add non-geometry composition changes to the trace.
-        TRACE_BUFFERS = 1 << 5,
-        // Add entries from the drawing thread post composition.
-        TRACE_SYNC = 1 << 6,
-        TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA,
-    };
-    void setTraceFlags(uint32_t flags) { mConfig.flags = flags; }
-    bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
-    static LayersTraceFileProto createLayersTraceFileProto();
-
-private:
-    class Runner;
-    static constexpr auto DEFAULT_BUFFER_SIZE = 20_MB;
-    static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope";
-
-    SurfaceFlinger& mFlinger;
-    mutable std::mutex mTraceLock;
-    bool mEnabled GUARDED_BY(mTraceLock) = false;
-    std::unique_ptr<Runner> runner GUARDED_BY(mTraceLock);
-
-    struct Config {
-        uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC;
-        size_t bufferSize = DEFAULT_BUFFER_SIZE;
-    } mConfig;
-
-    /*
-     * ring buffer.
-     */
-    class LayersTraceBuffer {
-    public:
-        size_t size() const { return mSizeInBytes; }
-        size_t used() const { return mUsedInBytes; }
-        size_t frameCount() const { return mStorage.size(); }
-
-        void setSize(size_t newSize) { mSizeInBytes = newSize; }
-        void reset(size_t newSize);
-        void emplace(LayersTraceProto&& proto);
-        void flush(LayersTraceFileProto* fileProto);
-
-    private:
-        size_t mUsedInBytes = 0U;
-        size_t mSizeInBytes = DEFAULT_BUFFER_SIZE;
-        std::queue<LayersTraceProto> mStorage;
-    };
-
-    /*
-     * Implements a synchronous way of adding trace entries. This must be called
-     * from the drawing thread.
-     */
-    class Runner {
-    public:
-        Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config);
-        virtual ~Runner() = default;
-        virtual status_t stop();
-        virtual status_t writeToFile();
-        virtual void notify(const char* where);
-        /* Cannot be called with a synchronous runner. */
-        virtual void notifyLocked(const char* /* where */) {}
-        void dump(std::string& result) const;
-
-    protected:
-        bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
-        SurfaceFlinger& mFlinger;
-        SurfaceTracing::Config mConfig;
-        SurfaceTracing::LayersTraceBuffer mBuffer;
-        uint32_t mMissedTraceEntries = 0;
-        LayersTraceProto traceLayers(const char* where);
-    };
-
-    /*
-     * Implements asynchronous way to add trace entries called from a separate thread while holding
-     * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not
-     * scheduled in time.
-     */
-    class AsyncRunner : public Runner {
-    public:
-        AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock);
-        virtual ~AsyncRunner() = default;
-        status_t stop() override;
-        status_t writeToFile() override;
-        void notify(const char* where) override;
-        void notifyLocked(const char* where);
-
-    private:
-        std::mutex& mSfLock;
-        std::condition_variable mCanStartTrace;
-        std::thread mThread;
-        const char* mWhere = "";
-        bool mWriteToFile = false;
-        bool mEnabled = false;
-        bool mAddEntry = false;
-        void loop();
-        bool traceWhenNotified(LayersTraceProto* outProto);
-    };
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
new file mode 100644
index 0000000..84890ee
--- /dev/null
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerTracing"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <SurfaceFlinger.h>
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+#include <utils/Trace.h>
+
+#include "LayerTracing.h"
+#include "RingBuffer.h"
+
+namespace android {
+
+LayerTracing::LayerTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {
+    mBuffer = std::make_unique<RingBuffer<LayersTraceFileProto, LayersTraceProto>>();
+}
+
+LayerTracing::~LayerTracing() = default;
+
+bool LayerTracing::enable() {
+    std::scoped_lock lock(mTraceLock);
+    if (mEnabled) {
+        return false;
+    }
+    mBuffer->setSize(mBufferSizeInBytes);
+    mEnabled = true;
+    return true;
+}
+
+bool LayerTracing::disable() {
+    std::scoped_lock lock(mTraceLock);
+    if (!mEnabled) {
+        return false;
+    }
+    mEnabled = false;
+    LayersTraceFileProto fileProto = createTraceFileProto();
+    mBuffer->writeToFile(fileProto, FILE_NAME);
+    return true;
+}
+
+bool LayerTracing::isEnabled() const {
+    std::scoped_lock lock(mTraceLock);
+    return mEnabled;
+}
+
+status_t LayerTracing::writeToFile() {
+    std::scoped_lock lock(mTraceLock);
+    if (!mEnabled) {
+        return STATUS_OK;
+    }
+    LayersTraceFileProto fileProto = createTraceFileProto();
+    return mBuffer->writeToFile(fileProto, FILE_NAME);
+}
+
+void LayerTracing::setTraceFlags(uint32_t flags) {
+    std::scoped_lock lock(mTraceLock);
+    mFlags = flags;
+}
+
+void LayerTracing::setBufferSize(size_t bufferSizeInBytes) {
+    std::scoped_lock lock(mTraceLock);
+    mBufferSizeInBytes = bufferSizeInBytes;
+}
+
+bool LayerTracing::flagIsSet(uint32_t flags) const {
+    return (mFlags & flags) == flags;
+}
+
+LayersTraceFileProto LayerTracing::createTraceFileProto() const {
+    LayersTraceFileProto fileProto;
+    fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
+                               LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
+    return fileProto;
+}
+
+void LayerTracing::dump(std::string& result) const {
+    std::scoped_lock lock(mTraceLock);
+    base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
+    mBuffer->dump(result);
+}
+
+void LayerTracing::notify(const char* where) {
+    ATRACE_CALL();
+    std::scoped_lock lock(mTraceLock);
+    if (!mEnabled) {
+        return;
+    }
+
+    ATRACE_CALL();
+    LayersTraceProto entry;
+    entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
+    entry.set_where(where);
+    LayersProto layers(mFlinger.dumpDrawingStateProto(mFlags));
+
+    if (flagIsSet(LayerTracing::TRACE_EXTRA)) {
+        mFlinger.dumpOffscreenLayersProto(layers);
+    }
+    entry.mutable_layers()->Swap(&layers);
+
+    if (flagIsSet(LayerTracing::TRACE_HWC)) {
+        std::string hwcDump;
+        mFlinger.dumpHwc(hwcDump);
+        entry.set_hwc_blob(hwcDump);
+    }
+    if (!flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
+        entry.set_excludes_composition_state(true);
+    }
+    mFlinger.dumpDisplayProto(entry);
+    mBuffer->emplace(std::move(entry));
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h
new file mode 100644
index 0000000..8ca3587
--- /dev/null
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -0,0 +1,77 @@
+/*
+ * 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 <android-base/thread_annotations.h>
+#include <layerproto/LayerProtoHeader.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+#include <memory>
+#include <mutex>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+template <typename FileProto, typename EntryProto>
+class RingBuffer;
+
+class SurfaceFlinger;
+
+/*
+ * LayerTracing records layer states during surface flinging. Manages tracing state and
+ * configuration.
+ */
+class LayerTracing {
+public:
+    LayerTracing(SurfaceFlinger& flinger);
+    ~LayerTracing();
+    bool enable();
+    bool disable();
+    bool isEnabled() const;
+    status_t writeToFile();
+    LayersTraceFileProto createTraceFileProto() const;
+    void notify(const char* where);
+
+    enum : uint32_t {
+        TRACE_INPUT = 1 << 1,
+        TRACE_COMPOSITION = 1 << 2,
+        TRACE_EXTRA = 1 << 3,
+        TRACE_HWC = 1 << 4,
+        TRACE_BUFFERS = 1 << 5,
+        TRACE_ALL = TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA,
+    };
+    void setTraceFlags(uint32_t flags);
+    bool flagIsSet(uint32_t flags) const;
+    void setBufferSize(size_t bufferSizeInBytes);
+    void dump(std::string&) const;
+
+private:
+    static constexpr auto FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope";
+
+    SurfaceFlinger& mFlinger;
+    uint32_t mFlags = TRACE_INPUT;
+    mutable std::mutex mTraceLock;
+    bool mEnabled GUARDED_BY(mTraceLock) = false;
+    std::unique_ptr<RingBuffer<LayersTraceFileProto, LayersTraceProto>> mBuffer
+            GUARDED_BY(mTraceLock);
+    size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = 20 * 1024 * 1024;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h
new file mode 100644
index 0000000..d0fb3f2
--- /dev/null
+++ b/services/surfaceflinger/Tracing/RingBuffer.h
@@ -0,0 +1,112 @@
+/*
+ * 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 <android-base/file.h>
+#include <android-base/stringprintf.h>
+
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/SystemClock.h>
+#include <utils/Trace.h>
+#include <queue>
+
+namespace android {
+
+class SurfaceFlinger;
+
+template <typename FileProto, typename EntryProto>
+class RingBuffer {
+public:
+    size_t size() const { return mSizeInBytes; }
+    size_t used() const { return mUsedInBytes; }
+    size_t frameCount() const { return mStorage.size(); }
+    void setSize(size_t newSize) { mSizeInBytes = newSize; }
+    EntryProto& front() { return mStorage.front(); }
+    const EntryProto& front() const { return mStorage.front(); }
+
+    void reset(size_t newSize) {
+        // use the swap trick to make sure memory is released
+        std::queue<EntryProto>().swap(mStorage);
+        mSizeInBytes = newSize;
+        mUsedInBytes = 0U;
+    }
+    void flush(FileProto& fileProto) {
+        fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()));
+        while (!mStorage.empty()) {
+            auto entry = fileProto.add_entry();
+            entry->Swap(&mStorage.front());
+            mStorage.pop();
+        }
+    }
+
+    status_t writeToFile(FileProto& fileProto, std::string filename) {
+        ATRACE_CALL();
+        std::string output;
+        flush(fileProto);
+        reset(mSizeInBytes);
+        if (!fileProto.SerializeToString(&output)) {
+            ALOGE("Could not serialize proto.");
+            return UNKNOWN_ERROR;
+        }
+
+        // -rw-r--r--
+        const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+        if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) {
+            ALOGE("Could not save the proto file.");
+            return PERMISSION_DENIED;
+        }
+        return NO_ERROR;
+    }
+
+    std::vector<EntryProto> emplace(EntryProto&& proto) {
+        std::vector<EntryProto> replacedEntries;
+        size_t protoSize = static_cast<size_t>(proto.ByteSize());
+        while (mUsedInBytes + protoSize > mSizeInBytes) {
+            if (mStorage.empty()) {
+                return {};
+            }
+            mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
+            replacedEntries.emplace_back(mStorage.front());
+            mStorage.pop();
+        }
+        mUsedInBytes += protoSize;
+        mStorage.emplace();
+        mStorage.back().Swap(&proto);
+        return replacedEntries;
+    }
+
+    void dump(std::string& result) const {
+        std::chrono::milliseconds duration(0);
+        if (frameCount() > 0) {
+            duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+                    std::chrono::nanoseconds(systemTime() - front().elapsed_realtime_nanos()));
+        }
+        const int64_t durationCount = duration.count();
+        base::StringAppendF(&result,
+                            "  number of entries: %zu (%.2fMB / %.2fMB) duration: %" PRIi64 "ms\n",
+                            frameCount(), float(used()) / 1024.f * 1024.f,
+                            float(size()) / 1024.f * 1024.f, durationCount);
+    }
+
+private:
+    size_t mUsedInBytes = 0U;
+    size_t mSizeInBytes = 0U;
+    std::queue<EntryProto> mStorage;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index fb1d43b..d1dc076 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -22,9 +22,9 @@
 
 namespace android::surfaceflinger {
 
-proto::TransactionState TransactionProtoParser::toProto(
-        const TransactionState& t, std::function<int32_t(const sp<IBinder>&)> getLayerId,
-        std::function<int32_t(const sp<IBinder>&)> getDisplayId) {
+proto::TransactionState TransactionProtoParser::toProto(const TransactionState& t,
+                                                        LayerHandleToIdFn getLayerId,
+                                                        DisplayHandleToIdFn getDisplayId) {
     proto::TransactionState proto;
     proto.set_pid(t.originPid);
     proto.set_uid(t.originUid);
@@ -42,10 +42,38 @@
     return proto;
 }
 
-proto::LayerState TransactionProtoParser::toProto(
-        const layer_state_t& layer, std::function<int32_t(const sp<IBinder>&)> getLayerId) {
+proto::TransactionState TransactionProtoParser::toProto(
+        std::vector<std::pair<int32_t /* layerId */, TracingLayerState>> states) {
+    proto::TransactionState proto;
+    for (auto& [layerId, state] : states) {
+        proto::LayerState layerProto = toProto(state, nullptr);
+        if (layerProto.has_buffer_data()) {
+            proto::LayerState_BufferData* bufferProto = layerProto.mutable_buffer_data();
+            bufferProto->set_buffer_id(state.bufferId);
+            bufferProto->set_width(state.bufferWidth);
+            bufferProto->set_height(state.bufferHeight);
+        }
+        layerProto.set_has_sideband_stream(state.hasSidebandStream);
+        layerProto.set_layer_id(state.layerId);
+        layerProto.set_parent_id(state.parentId);
+        layerProto.set_relative_parent_id(state.relativeParentId);
+        if (layerProto.has_window_info_handle()) {
+            layerProto.mutable_window_info_handle()->set_crop_layer_id(state.inputCropId);
+        }
+        proto.mutable_layer_changes()->Add(std::move(layerProto));
+    }
+    return proto;
+}
+
+proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer,
+                                                  LayerHandleToIdFn getLayerId) {
     proto::LayerState proto;
-    proto.set_layer_id(layer.layerId);
+    if (getLayerId != nullptr) {
+        proto.set_layer_id(getLayerId(layer.surface));
+    } else {
+        proto.set_layer_id(layer.layerId);
+    }
+
     proto.set_what(layer.what);
 
     if (layer.what & layer_state_t::ePositionChanged) {
@@ -130,13 +158,13 @@
         }
     }
 
-    if (layer.what & layer_state_t::eReparent) {
+    if ((layer.what & layer_state_t::eReparent) && getLayerId != nullptr) {
         int32_t layerId = layer.parentSurfaceControlForChild
                 ? getLayerId(layer.parentSurfaceControlForChild->getHandle())
                 : -1;
         proto.set_parent_id(layerId);
     }
-    if (layer.what & layer_state_t::eRelativeLayerChanged) {
+    if ((layer.what & layer_state_t::eRelativeLayerChanged) && getLayerId != nullptr) {
         int32_t layerId = layer.relativeLayerSurfaceControl
                 ? getLayerId(layer.relativeLayerSurfaceControl->getHandle())
                 : -1;
@@ -164,8 +192,12 @@
             transformProto->set_ty(inputInfo->transform.ty());
             windowInfoProto->set_replace_touchable_region_with_crop(
                     inputInfo->replaceTouchableRegionWithCrop);
-            windowInfoProto->set_crop_layer_id(
-                    getLayerId(inputInfo->touchableRegionCropHandle.promote()));
+            if (getLayerId != nullptr) {
+                windowInfoProto->set_crop_layer_id(
+                        getLayerId(inputInfo->touchableRegionCropHandle.promote()));
+            } else {
+                windowInfoProto->set_crop_layer_id(-1);
+            }
         }
     }
     if (layer.what & layer_state_t::eBackgroundColorChanged) {
@@ -212,11 +244,13 @@
     return proto;
 }
 
-proto::DisplayState TransactionProtoParser::toProto(
-        const DisplayState& display, std::function<int32_t(const sp<IBinder>&)> getDisplayId) {
+proto::DisplayState TransactionProtoParser::toProto(const DisplayState& display,
+                                                    DisplayHandleToIdFn getDisplayId) {
     proto::DisplayState proto;
     proto.set_what(display.what);
-    proto.set_id(getDisplayId(display.token));
+    if (getDisplayId != nullptr) {
+        proto.set_id(getDisplayId(display.token));
+    }
 
     if (display.what & DisplayState::eLayerStackChanged) {
         proto.set_layer_stack(display.layerStack.id);
@@ -238,9 +272,18 @@
     return proto;
 }
 
-TransactionState TransactionProtoParser::fromProto(
-        const proto::TransactionState& proto, std::function<sp<IBinder>(int32_t)> getLayerHandle,
-        std::function<sp<IBinder>(int32_t)> getDisplayHandle) {
+proto::LayerCreationArgs TransactionProtoParser::toProto(const TracingLayerCreationArgs& args) {
+    proto::LayerCreationArgs proto;
+    proto.set_layer_id(args.layerId);
+    proto.set_name(args.name);
+    proto.set_flags(args.flags);
+    proto.set_parent_id(args.parentId);
+    return proto;
+}
+
+TransactionState TransactionProtoParser::fromProto(const proto::TransactionState& proto,
+                                                   LayerIdToHandleFn getLayerHandle,
+                                                   DisplayIdToHandleFn getDisplayHandle) {
     TransactionState t;
     t.originPid = proto.pid();
     t.originUid = proto.uid();
@@ -251,7 +294,7 @@
     t.states.reserve(static_cast<size_t>(layerCount));
     for (int i = 0; i < layerCount; i++) {
         ComposerState s;
-        s.state = std::move(fromProto(proto.layer_changes(i), getLayerHandle));
+        fromProto(proto.layer_changes(i), getLayerHandle, s.state);
         t.states.add(s);
     }
 
@@ -263,88 +306,116 @@
     return t;
 }
 
-layer_state_t TransactionProtoParser::fromProto(
-        const proto::LayerState& proto, std::function<sp<IBinder>(int32_t)> getLayerHandle) {
-    layer_state_t layer;
-    layer.layerId = proto.layer_id();
-    layer.what = proto.what();
+void TransactionProtoParser::fromProto(const proto::LayerCreationArgs& proto,
+                                       TracingLayerCreationArgs& outArgs) {
+    outArgs.layerId = proto.layer_id();
+    outArgs.name = proto.name();
+    outArgs.flags = proto.flags();
+    outArgs.parentId = proto.parent_id();
+}
 
-    if (layer.what & layer_state_t::ePositionChanged) {
+void TransactionProtoParser::fromProto(const proto::LayerState& proto,
+                                       LayerIdToHandleFn getLayerHandle,
+                                       TracingLayerState& outState) {
+    fromProto(proto, getLayerHandle, static_cast<layer_state_t&>(outState));
+    if (proto.what() & layer_state_t::eReparent) {
+        outState.parentId = proto.parent_id();
+    }
+    if (proto.what() & layer_state_t::eRelativeLayerChanged) {
+        outState.relativeParentId = proto.relative_parent_id();
+    }
+    if (proto.what() & layer_state_t::eInputInfoChanged) {
+        outState.inputCropId = proto.window_info_handle().crop_layer_id();
+    }
+    if (proto.what() & layer_state_t::eBufferChanged) {
+        const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
+        outState.bufferId = bufferProto.buffer_id();
+        outState.bufferWidth = bufferProto.width();
+        outState.bufferHeight = bufferProto.height();
+    }
+    if (proto.what() & layer_state_t::eSidebandStreamChanged) {
+        outState.hasSidebandStream = proto.has_sideband_stream();
+    }
+}
+
+void TransactionProtoParser::fromProto(const proto::LayerState& proto,
+                                       LayerIdToHandleFn getLayerHandle, layer_state_t& layer) {
+    layer.layerId = proto.layer_id();
+    layer.what |= proto.what();
+
+    if (getLayerHandle != nullptr) {
+        layer.surface = getLayerHandle(layer.layerId);
+    }
+
+    if (proto.what() & layer_state_t::ePositionChanged) {
         layer.x = proto.x();
         layer.y = proto.y();
     }
-    if (layer.what & layer_state_t::eLayerChanged) {
+    if (proto.what() & layer_state_t::eLayerChanged) {
         layer.z = proto.z();
     }
-    if (layer.what & layer_state_t::eSizeChanged) {
+    if (proto.what() & layer_state_t::eSizeChanged) {
         layer.w = proto.w();
         layer.h = proto.h();
     }
-    if (layer.what & layer_state_t::eLayerStackChanged) {
+    if (proto.what() & layer_state_t::eLayerStackChanged) {
         layer.layerStack.id = proto.layer_stack();
     }
-    if (layer.what & layer_state_t::eFlagsChanged) {
+    if (proto.what() & layer_state_t::eFlagsChanged) {
         layer.flags = proto.flags();
         layer.mask = proto.mask();
     }
-    if (layer.what & layer_state_t::eMatrixChanged) {
+    if (proto.what() & layer_state_t::eMatrixChanged) {
         const proto::LayerState_Matrix22& matrixProto = proto.matrix();
         layer.matrix.dsdx = matrixProto.dsdx();
         layer.matrix.dsdy = matrixProto.dsdy();
         layer.matrix.dtdx = matrixProto.dtdx();
         layer.matrix.dtdy = matrixProto.dtdy();
     }
-    if (layer.what & layer_state_t::eCornerRadiusChanged) {
+    if (proto.what() & layer_state_t::eCornerRadiusChanged) {
         layer.cornerRadius = proto.corner_radius();
     }
-    if (layer.what & layer_state_t::eBackgroundBlurRadiusChanged) {
+    if (proto.what() & layer_state_t::eBackgroundBlurRadiusChanged) {
         layer.backgroundBlurRadius = proto.background_blur_radius();
     }
 
-    if (layer.what & layer_state_t::eAlphaChanged) {
+    if (proto.what() & layer_state_t::eAlphaChanged) {
         layer.alpha = proto.alpha();
     }
 
-    if (layer.what & layer_state_t::eColorChanged) {
+    if (proto.what() & layer_state_t::eColorChanged) {
         const proto::LayerState_Color3& colorProto = proto.color();
         layer.color.r = colorProto.r();
         layer.color.g = colorProto.g();
         layer.color.b = colorProto.b();
     }
-    if (layer.what & layer_state_t::eTransparentRegionChanged) {
+    if (proto.what() & layer_state_t::eTransparentRegionChanged) {
         LayerProtoHelper::readFromProto(proto.transparent_region(), layer.transparentRegion);
     }
-    if (layer.what & layer_state_t::eTransformChanged) {
+    if (proto.what() & layer_state_t::eTransformChanged) {
         layer.transform = proto.transform();
     }
-    if (layer.what & layer_state_t::eTransformToDisplayInverseChanged) {
+    if (proto.what() & layer_state_t::eTransformToDisplayInverseChanged) {
         layer.transformToDisplayInverse = proto.transform_to_display_inverse();
     }
-    if (layer.what & layer_state_t::eCropChanged) {
+    if (proto.what() & layer_state_t::eCropChanged) {
         LayerProtoHelper::readFromProto(proto.crop(), layer.crop);
     }
-    if (layer.what & layer_state_t::eBufferChanged) {
+    if (proto.what() & layer_state_t::eBufferChanged) {
         const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
-        layer.bufferData.buffer = new GraphicBuffer(bufferProto.width(), bufferProto.height(),
-                                                    HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
         layer.bufferData.frameNumber = bufferProto.frame_number();
         layer.bufferData.flags = Flags<BufferData::BufferDataChange>(bufferProto.flags());
         layer.bufferData.cachedBuffer.id = bufferProto.cached_buffer_id();
     }
-    if (layer.what & layer_state_t::eSidebandStreamChanged) {
-        native_handle_t* handle = native_handle_create(0, 0);
-        layer.sidebandStream =
-                proto.has_sideband_stream() ? NativeHandle::create(handle, true) : nullptr;
-    }
 
-    if (layer.what & layer_state_t::eApiChanged) {
+    if (proto.what() & layer_state_t::eApiChanged) {
         layer.api = proto.api();
     }
 
-    if (layer.what & layer_state_t::eColorTransformChanged) {
+    if (proto.what() & layer_state_t::eColorTransformChanged) {
         LayerProtoHelper::readFromProto(proto.color_transform(), layer.colorTransform);
     }
-    if (layer.what & layer_state_t::eBlurRegionsChanged) {
+    if (proto.what() & layer_state_t::eBlurRegionsChanged) {
         layer.blurRegions.reserve(static_cast<size_t>(proto.blur_regions_size()));
         for (int i = 0; i < proto.blur_regions_size(); i++) {
             android::BlurRegion region;
@@ -353,20 +424,20 @@
         }
     }
 
-    if (layer.what & layer_state_t::eReparent) {
+    if ((proto.what() & layer_state_t::eReparent) && (getLayerHandle != nullptr)) {
         int32_t layerId = proto.parent_id();
         layer.parentSurfaceControlForChild =
                 new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
                                    nullptr, layerId);
     }
-    if (layer.what & layer_state_t::eRelativeLayerChanged) {
+    if ((proto.what() & layer_state_t::eRelativeLayerChanged) && (getLayerHandle != nullptr)) {
         int32_t layerId = proto.relative_parent_id();
         layer.relativeLayerSurfaceControl =
                 new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
                                    nullptr, layerId);
     }
 
-    if ((layer.what & layer_state_t::eInputInfoChanged) && proto.has_window_info_handle()) {
+    if ((proto.what() & layer_state_t::eInputInfoChanged) && proto.has_window_info_handle()) {
         gui::WindowInfo inputInfo;
         const proto::LayerState_WindowInfo& windowInfoProto = proto.window_info_handle();
 
@@ -385,10 +456,12 @@
         inputInfo.replaceTouchableRegionWithCrop =
                 windowInfoProto.replace_touchable_region_with_crop();
         int32_t layerId = windowInfoProto.crop_layer_id();
-        inputInfo.touchableRegionCropHandle = getLayerHandle(layerId);
+        if (getLayerHandle != nullptr) {
+            inputInfo.touchableRegionCropHandle = getLayerHandle(layerId);
+        }
         layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
     }
-    if (layer.what & layer_state_t::eBackgroundColorChanged) {
+    if (proto.what() & layer_state_t::eBackgroundColorChanged) {
         layer.bgColorAlpha = proto.bg_color_alpha();
         layer.bgColorDataspace = static_cast<ui::Dataspace>(proto.bg_color_dataspace());
         const proto::LayerState_Color3& colorProto = proto.color();
@@ -396,44 +469,43 @@
         layer.color.g = colorProto.g();
         layer.color.b = colorProto.b();
     }
-    if (layer.what & layer_state_t::eColorSpaceAgnosticChanged) {
+    if (proto.what() & layer_state_t::eColorSpaceAgnosticChanged) {
         layer.colorSpaceAgnostic = proto.color_space_agnostic();
     }
-    if (layer.what & layer_state_t::eShadowRadiusChanged) {
+    if (proto.what() & layer_state_t::eShadowRadiusChanged) {
         layer.shadowRadius = proto.shadow_radius();
     }
-    if (layer.what & layer_state_t::eFrameRateSelectionPriority) {
+    if (proto.what() & layer_state_t::eFrameRateSelectionPriority) {
         layer.frameRateSelectionPriority = proto.frame_rate_selection_priority();
     }
-    if (layer.what & layer_state_t::eFrameRateChanged) {
+    if (proto.what() & layer_state_t::eFrameRateChanged) {
         layer.frameRate = proto.frame_rate();
         layer.frameRateCompatibility = static_cast<int8_t>(proto.frame_rate_compatibility());
         layer.changeFrameRateStrategy = static_cast<int8_t>(proto.change_frame_rate_strategy());
     }
-    if (layer.what & layer_state_t::eFixedTransformHintChanged) {
+    if (proto.what() & layer_state_t::eFixedTransformHintChanged) {
         layer.fixedTransformHint =
                 static_cast<ui::Transform::RotationFlags>(proto.fixed_transform_hint());
     }
-    if (layer.what & layer_state_t::eAutoRefreshChanged) {
+    if (proto.what() & layer_state_t::eAutoRefreshChanged) {
         layer.autoRefresh = proto.auto_refresh();
     }
-    if (layer.what & layer_state_t::eTrustedOverlayChanged) {
+    if (proto.what() & layer_state_t::eTrustedOverlayChanged) {
         layer.isTrustedOverlay = proto.is_trusted_overlay();
     }
-    if (layer.what & layer_state_t::eBufferCropChanged) {
+    if (proto.what() & layer_state_t::eBufferCropChanged) {
         LayerProtoHelper::readFromProto(proto.buffer_crop(), layer.bufferCrop);
     }
-    if (layer.what & layer_state_t::eDestinationFrameChanged) {
+    if (proto.what() & layer_state_t::eDestinationFrameChanged) {
         LayerProtoHelper::readFromProto(proto.destination_frame(), layer.destinationFrame);
     }
-    if (layer.what & layer_state_t::eDropInputModeChanged) {
+    if (proto.what() & layer_state_t::eDropInputModeChanged) {
         layer.dropInputMode = static_cast<gui::DropInputMode>(proto.drop_input_mode());
     }
-    return layer;
 }
 
-DisplayState TransactionProtoParser::fromProto(
-        const proto::DisplayState& proto, std::function<sp<IBinder>(int32_t)> getDisplayHandle) {
+DisplayState TransactionProtoParser::fromProto(const proto::DisplayState& proto,
+                                               DisplayIdToHandleFn getDisplayHandle) {
     DisplayState display;
     display.what = proto.what();
     display.token = getDisplayHandle(proto.id());
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index a2b8889..e8a139f 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -21,24 +21,53 @@
 #include "TransactionState.h"
 
 namespace android::surfaceflinger {
+
+struct TracingLayerCreationArgs {
+    int32_t layerId;
+    std::string name;
+    uint32_t flags;
+    int32_t parentId;
+};
+
+struct TracingLayerState : layer_state_t {
+    uint64_t bufferId;
+    uint32_t bufferHeight;
+    uint32_t bufferWidth;
+    bool hasSidebandStream;
+    int32_t parentId;
+    int32_t relativeParentId;
+    int32_t inputCropId;
+    std::string name;
+    uint32_t layerCreationFlags;
+};
+
 class TransactionProtoParser {
 public:
+    typedef std::function<sp<IBinder>(int32_t)> LayerIdToHandleFn;
+    typedef std::function<sp<IBinder>(int32_t)> DisplayIdToHandleFn;
+    typedef std::function<int32_t(const sp<IBinder>&)> LayerHandleToIdFn;
+    typedef std::function<int32_t(const sp<IBinder>&)> DisplayHandleToIdFn;
+
+    static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn,
+                                           DisplayHandleToIdFn getDisplayIdFn);
     static proto::TransactionState toProto(
-            const TransactionState&, std::function<int32_t(const sp<IBinder>&)> getLayerIdFn,
-            std::function<int32_t(const sp<IBinder>&)> getDisplayIdFn);
+            std::vector<std::pair<int32_t /* layerId */, TracingLayerState>>);
+
+    static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
+
     static TransactionState fromProto(const proto::TransactionState&,
-                                      std::function<sp<IBinder>(int32_t)> getLayerHandleFn,
-                                      std::function<sp<IBinder>(int32_t)> getDisplayHandleFn);
+                                      LayerIdToHandleFn getLayerHandleFn,
+                                      DisplayIdToHandleFn getDisplayHandleFn);
+    static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn,
+                          TracingLayerState& outState);
+    static void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
 
 private:
-    static proto::LayerState toProto(const layer_state_t&,
-                                     std::function<int32_t(const sp<IBinder>&)> getLayerId);
-    static proto::DisplayState toProto(const DisplayState&,
-                                       std::function<int32_t(const sp<IBinder>&)> getDisplayId);
-    static layer_state_t fromProto(const proto::LayerState&,
-                                   std::function<sp<IBinder>(int32_t)> getLayerHandle);
-    static DisplayState fromProto(const proto::DisplayState&,
-                                  std::function<sp<IBinder>(int32_t)> getDisplayHandle);
+    static proto::LayerState toProto(const layer_state_t&, LayerHandleToIdFn getLayerId);
+    static proto::DisplayState toProto(const DisplayState&, DisplayHandleToIdFn getDisplayId);
+    static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandle,
+                          layer_state_t& out);
+    static DisplayState fromProto(const proto::DisplayState&, DisplayIdToHandleFn getDisplayHandle);
 };
 
 } // namespace android::surfaceflinger
\ No newline at end of file
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 418fbc5..f3d46ea 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -74,10 +74,10 @@
     }
 }
 
-void TransactionCallbackInvoker::addEmptyCallback(const ListenerCallbacks& listenerCallbacks) {
+void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) {
     auto& [listener, callbackIds] = listenerCallbacks;
-    TransactionStats* transactionStats;
-    findOrCreateTransactionStats(listener, callbackIds, &transactionStats);
+    auto& transactionStatsDeque = mCompletedTransactions[listener];
+    transactionStatsDeque.emplace_back(callbackIds);
 }
 
 status_t TransactionCallbackInvoker::addOnCommitCallbackHandles(
@@ -116,7 +116,7 @@
     return NO_ERROR;
 }
 
-status_t TransactionCallbackInvoker::addUnpresentedCallbackHandle(
+status_t TransactionCallbackInvoker::registerUnpresentedCallbackHandle(
         const sp<CallbackHandle>& handle) {
     return addCallbackHandle(handle, std::vector<JankData>());
 }
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 6f67947..e203d41 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -71,10 +71,8 @@
 
     // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
     // presented this frame.
-    status_t addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
-    // Adds the callback handles for empty transactions or for non-buffer layer updates which do not
-    // include layer stats.
-    void addEmptyCallback(const ListenerCallbacks& listenerCallbacks);
+    status_t registerUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
+    void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks);
 
     void addPresentFence(const sp<Fence>& presentFence);
 
@@ -83,12 +81,14 @@
         mCompletedTransactions.clear();
     }
 
+    status_t addCallbackHandle(const sp<CallbackHandle>& handle,
+                               const std::vector<JankData>& jankData);
+
+
 private:
     status_t findOrCreateTransactionStats(const sp<IBinder>& listener,
                                           const std::vector<CallbackId>& callbackIds,
                                           TransactionStats** outTransactionStats);
-    status_t addCallbackHandle(const sp<CallbackHandle>& handle,
-                               const std::vector<JankData>& jankData);
 
     std::unordered_map<sp<IBinder>, std::deque<TransactionStats>, IListenerHash>
         mCompletedTransactions;
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index e7fb180..edeacfa 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -39,21 +39,28 @@
 }
 
 message TransactionTraceEntry {
-    int64 elapsed_time = 1;
+    int64 elapsed_realtime_nanos = 1;
     int64 vsync_id = 2;
     repeated TransactionState transactions = 3;
+    repeated LayerCreationArgs new_layers = 4;
+    repeated DisplayState new_displays = 5;
+}
+
+message LayerCreationArgs {
+    int32 layer_id = 1;
+    string name = 2;
+    uint32 flags = 3;
+    int32 parent_id = 4;
 }
 
 message TransactionState {
-    string tag = 2;
-    int32 pid = 3;
-    int32 uid = 4;
-    int64 vsync_id = 5;
-    int32 input_event_id = 6;
-    int64 post_time = 7;
-    repeated LayerState layer_changes = 9;
-    repeated DisplayState new_displays = 10;
-    repeated DisplayState display_changes = 11;
+    int32 pid = 1;
+    int32 uid = 2;
+    int64 vsync_id = 3;
+    int32 input_event_id = 4;
+    int64 post_time = 5;
+    repeated LayerState layer_changes = 6;
+    repeated DisplayState display_changes = 7;
 }
 
 // Keep insync with layer_state_t
@@ -130,8 +137,8 @@
         eLayerSecure = 0x80;
         eEnableBackpressure = 0x100;
     };
-    uint32 flags = 10;
-    uint32 mask = 11;
+    uint32 flags = 9;
+    uint32 mask = 10;
 
     message Matrix22 {
         float dsdx = 1;
@@ -139,29 +146,29 @@
         float dtdy = 3;
         float dsdy = 4;
     };
-    Matrix22 matrix = 12;
-    float corner_radius = 13;
-    uint32 background_blur_radius = 14;
-    int32 parent_id = 15;
-    int32 relative_parent_id = 16;
+    Matrix22 matrix = 11;
+    float corner_radius = 12;
+    uint32 background_blur_radius = 13;
+    int32 parent_id = 14;
+    int32 relative_parent_id = 15;
 
-    float alpha = 50;
+    float alpha = 16;
     message Color3 {
         float r = 1;
         float g = 2;
         float b = 3;
     }
-    Color3 color = 18;
-    RegionProto transparent_region = 19;
-    uint32 transform = 20;
-    bool transform_to_display_inverse = 21;
-    RectProto crop = 49;
+    Color3 color = 17;
+    RegionProto transparent_region = 18;
+    uint32 transform = 19;
+    bool transform_to_display_inverse = 20;
+    RectProto crop = 21;
 
     message BufferData {
         uint64 buffer_id = 1;
         uint32 width = 2;
         uint32 height = 3;
-        uint64 frame_number = 5;
+        uint64 frame_number = 4;
 
         enum BufferDataChange {
             BufferDataChangeNone = 0;
@@ -169,14 +176,14 @@
             frameNumberChanged = 0x02;
             cachedBufferChanged = 0x04;
         }
-        uint32 flags = 6;
-        uint64 cached_buffer_id = 7;
+        uint32 flags = 5;
+        uint64 cached_buffer_id = 6;
     }
-    BufferData buffer_data = 23;
-    int32 api = 24;
-    bool has_sideband_stream = 25;
-    ColorTransformProto color_transform = 26;
-    repeated BlurRegion blur_regions = 27;
+    BufferData buffer_data = 22;
+    int32 api = 23;
+    bool has_sideband_stream = 24;
+    ColorTransformProto color_transform = 25;
+    repeated BlurRegion blur_regions = 26;
 
     message Transform {
         float dsdx = 1;
@@ -189,38 +196,38 @@
     message WindowInfo {
         uint32 layout_params_flags = 1;
         int32 layout_params_type = 2;
-        RegionProto touchable_region = 4;
-        int32 surface_inset = 5;
-        bool focusable = 8;
-        bool has_wallpaper = 9;
-        float global_scale_factor = 10;
-        int32 crop_layer_id = 13;
-        bool replace_touchable_region_with_crop = 14;
-        RectProto touchable_region_crop = 15;
-        Transform transform = 16;
+        RegionProto touchable_region = 3;
+        int32 surface_inset = 4;
+        bool focusable = 5;
+        bool has_wallpaper = 6;
+        float global_scale_factor = 7;
+        int32 crop_layer_id = 8;
+        bool replace_touchable_region_with_crop = 9;
+        RectProto touchable_region_crop = 10;
+        Transform transform = 11;
     }
-    WindowInfo window_info_handle = 28;
-    float bg_color_alpha = 31;
-    int32 bg_color_dataspace = 32;
-    bool color_space_agnostic = 33;
-    float shadow_radius = 34;
-    int32 frame_rate_selection_priority = 35;
-    float frame_rate = 36;
-    int32 frame_rate_compatibility = 37;
-    int32 change_frame_rate_strategy = 38;
-    uint32 fixed_transform_hint = 39;
-    uint64 frame_number = 40;
-    bool auto_refresh = 41;
-    bool is_trusted_overlay = 42;
-    RectProto buffer_crop = 44;
-    RectProto destination_frame = 45;
+    WindowInfo window_info_handle = 27;
+    float bg_color_alpha = 28;
+    int32 bg_color_dataspace = 29;
+    bool color_space_agnostic = 30;
+    float shadow_radius = 31;
+    int32 frame_rate_selection_priority = 32;
+    float frame_rate = 33;
+    int32 frame_rate_compatibility = 34;
+    int32 change_frame_rate_strategy = 35;
+    uint32 fixed_transform_hint = 36;
+    uint64 frame_number = 37;
+    bool auto_refresh = 38;
+    bool is_trusted_overlay = 39;
+    RectProto buffer_crop = 40;
+    RectProto destination_frame = 41;
 
     enum DropInputMode {
         NONE = 0;
         ALL = 1;
         OBSCURED = 2;
     };
-    DropInputMode drop_input_mode = 48;
+    DropInputMode drop_input_mode = 42;
 }
 
 message DisplayState {
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 7beba15..5c16fee 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -26,6 +26,7 @@
 namespace android {
 
 using android::hardware::graphics::common::V1_1::BufferUsage;
+using SCHash = SurfaceComposerClient::SCHash;
 
 ::testing::Environment* const binderEnv =
         ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
@@ -102,6 +103,24 @@
         }
     }
 
+    static void waitForCommitCallback(
+            CallbackHelper& helper,
+            const std::unordered_set<sp<SurfaceControl>, SCHash>& committedSc) {
+        CallbackData callbackData;
+        ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
+
+        const auto& surfaceControlStats = callbackData.surfaceControlStats;
+
+        ASSERT_EQ(surfaceControlStats.size(), committedSc.size()) << "wrong number of surfaces";
+
+        for (const auto& stats : surfaceControlStats) {
+            ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
+
+            const auto& expectedSc = committedSc.find(stats.surfaceControl);
+            ASSERT_NE(expectedSc, committedSc.end()) << "unexpected surface control";
+        }
+    }
+
     DisplayEventReceiver mDisplayEventReceiver;
     int mEpollFd;
 
@@ -1067,7 +1086,7 @@
 }
 
 // b202394221
-TEST_F(LayerCallbackTest, NonBufferLayerStateChanges) {
+TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED));
 
@@ -1085,47 +1104,29 @@
     EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
 }
 
-class TimedCallbackHelper {
-public:
-    static void function(void* callbackContext, nsecs_t, const sp<Fence>&,
-                         const std::vector<SurfaceControlStats>&) {
-        if (!callbackContext) {
-            ALOGE("failed to get callback context");
-        }
-        TimedCallbackHelper* helper = static_cast<TimedCallbackHelper*>(callbackContext);
-        std::lock_guard lock(helper->mMutex);
-        helper->mInvokedTime = systemTime();
-        helper->mCv.notify_all();
+TEST_F(LayerCallbackTest, CommitCallbackOffscreenLayer) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+    sp<SurfaceControl> offscreenLayer =
+            createSurface(mClient, "Offscreen Layer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                          ISurfaceComposerClient::eFXSurfaceBufferState, layer.get());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer, true);
+    err |= fillTransaction(transaction, &callback, offscreenLayer, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
     }
 
-    void waitForCallback() {
-        std::unique_lock lock(mMutex);
-        ASSERT_TRUE(mCv.wait_for(lock, std::chrono::seconds(3), [&] { return mInvokedTime != -1; }))
-                << "did not receive callback";
-    }
-    void* getContext() { return static_cast<void*>(this); }
+    transaction.reparent(offscreenLayer, nullptr)
+            .addTransactionCommittedCallback(callback.function, callback.getContext());
+    transaction.apply();
 
-    std::mutex mMutex;
-    std::condition_variable mCv;
-    nsecs_t mInvokedTime = -1;
-};
-
-TEST_F(LayerCallbackTest, EmptyTransactionCallbackOrder) {
-    TimedCallbackHelper onCommitCallback;
-    TimedCallbackHelper onCompleteCallback;
-
-    // Add transaction callback before on commit callback
-    Transaction()
-            .addTransactionCompletedCallback(onCompleteCallback.function,
-                                             onCompleteCallback.getContext())
-            .addTransactionCommittedCallback(onCommitCallback.function,
-                                             onCommitCallback.getContext())
-            .apply();
-
-    EXPECT_NO_FATAL_FAILURE(onCompleteCallback.waitForCallback());
-    EXPECT_NO_FATAL_FAILURE(onCommitCallback.waitForCallback());
-    // verify we get the oncomplete at the same time or after the oncommit callback.
-    EXPECT_GE(onCompleteCallback.mInvokedTime, onCommitCallback.mInvokedTime);
+    std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+    committedSc.insert(layer);
+    committedSc.insert(offscreenLayer);
+    EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
 }
-
 } // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 2082c42..28e8b8c 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -754,9 +754,7 @@
 }
 
 bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) {
-    bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment) &&
-                 increment.surface_creation().w() == SIZE_UPDATE &&
-                 increment.surface_creation().h() == SIZE_UPDATE);
+    bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment));
     if (isMatch && !foundSurface) {
         foundSurface = true;
     } else if (isMatch && foundSurface) {
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f152ced..3dc6d8b 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -107,7 +107,6 @@
         "mock/MockEventThread.cpp",
         "mock/MockFrameTimeline.cpp",
         "mock/MockFrameTracer.cpp",
-        "mock/MockMessageQueue.cpp",
         "mock/MockNativeWindowSurface.cpp",
         "mock/MockSurfaceInterceptor.cpp",
         "mock/MockTimeStats.cpp",
@@ -142,6 +141,7 @@
         "libtimestats",
         "libtimestats_atoms_proto",
         "libtimestats_proto",
+        "libtonemap",
         "libtrace_proto",
         "perfetto_trace_protos",
     ],
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 40ef6e7..8d2c078 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -45,7 +45,6 @@
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/DisplayHardware/MockPowerAdvisor.h"
 #include "mock/MockEventThread.h"
-#include "mock/MockMessageQueue.h"
 #include "mock/MockTimeStats.h"
 #include "mock/MockVsyncController.h"
 #include "mock/system/window/MockNativeWindow.h"
@@ -95,7 +94,6 @@
                 ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
 
-        mFlinger.mutableEventQueue().reset(mMessageQueue);
         setupScheduler();
 
         EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
@@ -145,9 +143,6 @@
         mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
                                 std::move(eventThread), std::move(sfEventThread), kCallback,
                                 kHasMultipleConfigs);
-
-        // Layer history should be created if there are multiple configs.
-        ASSERT_TRUE(mFlinger.scheduler()->hasLayerHistory());
     }
 
     void setupForceGeometryDirty() {
@@ -186,7 +181,6 @@
     Hwc2::mock::Composer* mComposer = nullptr;
     renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
     mock::TimeStats* mTimeStats = new mock::TimeStats();
-    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
     Hwc2::mock::PowerAdvisor mPowerAdvisor;
 
     sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -535,15 +529,16 @@
 
     static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) {
         // TODO: Eliminate the complexity of actually creating a buffer
+        layer->setSizeForTest(LayerProperties::WIDTH, LayerProperties::HEIGHT);
         status_t err =
                 layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT,
                                                   LayerProperties::FORMAT);
         ASSERT_EQ(NO_ERROR, err);
         Mock::VerifyAndClear(test->mRenderEngine);
 
-        EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1);
+        EXPECT_CALL(*test->mFlinger.scheduler(), scheduleFrame()).Times(1);
         enqueueBuffer(test, layer);
-        Mock::VerifyAndClearExpectations(test->mMessageQueue);
+        Mock::VerifyAndClearExpectations(test->mFlinger.scheduler());
 
         bool ignoredRecomputeVisibleRegions;
         layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0);
@@ -838,16 +833,16 @@
 struct BaseLayerVariant {
     template <typename L, typename F>
     static sp<L> createLayerWithFactory(CompositionTest* test, F factory) {
-        EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(0);
+        EXPECT_CALL(*test->mFlinger.scheduler(), postMessage(_)).Times(0);
 
         sp<L> layer = factory();
 
         // Layer should be registered with scheduler.
-        EXPECT_EQ(1, test->mFlinger.scheduler()->layerHistorySize());
+        EXPECT_EQ(1u, test->mFlinger.scheduler()->layerHistorySize());
 
         Mock::VerifyAndClear(test->mComposer);
         Mock::VerifyAndClear(test->mRenderEngine);
-        Mock::VerifyAndClearExpectations(test->mMessageQueue);
+        Mock::VerifyAndClearExpectations(test->mFlinger.scheduler());
 
         initLayerDrawingStateAndComputeBounds(test, layer);
 
@@ -888,7 +883,7 @@
 
         // Layer should be unregistered with scheduler.
         test->mFlinger.commit();
-        EXPECT_EQ(0, test->mFlinger.scheduler()->layerHistorySize());
+        EXPECT_EQ(0u, test->mFlinger.scheduler()->layerHistorySize());
     }
 };
 
@@ -901,7 +896,6 @@
         FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() {
             return new EffectLayer(
                     LayerCreationArgs(test->mFlinger.flinger(), sp<Client>(), "test-layer",
-                                      LayerProperties::WIDTH, LayerProperties::HEIGHT,
                                       LayerProperties::LAYER_FLAGS, LayerMetadata()));
         });
 
@@ -940,7 +934,6 @@
         FlingerLayerType layer =
                 Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
                     LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-layer",
-                                           LayerProperties::WIDTH, LayerProperties::HEIGHT,
                                            LayerProperties::LAYER_FLAGS, LayerMetadata());
                     args.textureName = test->mFlinger.mutableTexturePool().back();
                     return new BufferQueueLayer(args);
@@ -952,7 +945,6 @@
     }
 
     static void cleanupInjectedLayers(CompositionTest* test) {
-        EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(1);
         Base::cleanupInjectedLayers(test);
     }
 
@@ -990,7 +982,6 @@
 
     static FlingerLayerType createLayer(CompositionTest* test) {
         LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-container-layer",
-                               LayerProperties::WIDTH, LayerProperties::HEIGHT,
                                LayerProperties::LAYER_FLAGS, LayerMetadata());
         FlingerLayerType layer = new ContainerLayer(args);
         Base::template initLayerDrawingStateAndComputeBounds(test, layer);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 6cb3052..b1f704a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -50,7 +50,6 @@
     });
 
     injectMockScheduler();
-    mFlinger.mutableEventQueue().reset(mMessageQueue);
     mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
     mFlinger.mutableInterceptor() = mSurfaceInterceptor;
 
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 7746e73..de5e9df 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -47,7 +47,6 @@
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/DisplayHardware/MockPowerAdvisor.h"
 #include "mock/MockEventThread.h"
-#include "mock/MockMessageQueue.h"
 #include "mock/MockNativeWindowSurface.h"
 #include "mock/MockSchedulerCallback.h"
 #include "mock/MockSurfaceInterceptor.h"
@@ -118,7 +117,6 @@
     // to keep a reference to them for use in setting up call expectations.
     renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
     Hwc2::mock::Composer* mComposer = nullptr;
-    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
     sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
 
     mock::VsyncController* mVsyncController = new mock::VsyncController;
diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
index 010c675..cd2fc74 100644
--- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
@@ -114,8 +114,7 @@
 
 sp<BufferStateLayer> FpsReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) {
     sp<Client> client;
-    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT,
-                           LAYER_FLAGS, metadata);
+    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata);
     return new BufferStateLayer(args);
 }
 
diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
index 3fa1a2c..d645942 100644
--- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
@@ -53,7 +53,7 @@
 
     sp<BufferStateLayer> createBufferStateLayer() {
         sp<Client> client;
-        LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0,
+        LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0,
                                LayerMetadata());
         return new BufferStateLayer(args);
     }
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index e8795fe..4993a2d 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -59,10 +59,8 @@
 
     LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
 
-    void SetUp() override { ASSERT_TRUE(mScheduler->hasLayerHistory()); }
-
-    LayerHistory& history() { return *mScheduler->mutableLayerHistory(); }
-    const LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); }
+    LayerHistory& history() { return mScheduler->mutableLayerHistory(); }
+    const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); }
 
     LayerHistory::Summary summarizeLayerHistory(nsecs_t now) {
         return history().summarize(*mScheduler->refreshRateConfigs(), now);
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 17d1dd6..bd4dc59 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -41,7 +41,7 @@
     struct MockHandler : MessageQueue::Handler {
         using MessageQueue::Handler::Handler;
 
-        MOCK_METHOD(void, dispatchCommit, (int64_t, nsecs_t), (override));
+        MOCK_METHOD(void, dispatchFrame, (int64_t, nsecs_t), (override));
     };
 
     explicit TestableMessageQueue(sp<MockHandler> handler)
@@ -96,7 +96,7 @@
     EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
 
     ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
     EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
@@ -109,13 +109,13 @@
                                                                  .earliestVsync = 0};
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
 
     ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
     EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(4567));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
 
     ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
     EXPECT_EQ(4567, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
@@ -128,7 +128,7 @@
                                                                  .earliestVsync = 0};
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
 
     ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
     EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
@@ -141,7 +141,7 @@
                 generateTokenForPredictions(
                         frametimeline::TimelineItem(startTime, endTime, presentTime)))
             .WillOnce(Return(vsyncId));
-    EXPECT_CALL(*mEventQueue.mHandler, dispatchCommit(vsyncId, presentTime)).Times(1);
+    EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, presentTime)).Times(1);
     EXPECT_NO_FATAL_FAILURE(mEventQueue.vsyncCallback(presentTime, startTime, endTime));
 
     EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
@@ -152,7 +152,7 @@
                                                      .earliestVsync = presentTime};
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
 }
 
 TEST_F(MessageQueueTest, commitWithDurationChange) {
@@ -164,7 +164,7 @@
                                                      .earliestVsync = 0};
 
     EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0));
-    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit());
+    EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index e388a6f..1e6e336 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -91,15 +91,14 @@
 
 sp<BufferStateLayer> RefreshRateSelectionTest::createBufferStateLayer() {
     sp<Client> client;
-    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
-                           LAYER_FLAGS, LayerMetadata());
+    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", LAYER_FLAGS,
+                           LayerMetadata());
     return new BufferStateLayer(args);
 }
 
 sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() {
     sp<Client> client;
-    LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
-                           LayerMetadata());
+    LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata());
     return new EffectLayer(args);
 }
 
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 599b235..e558f3b 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -68,14 +68,6 @@
             std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60}, mode60->getId());
 
     mock::SchedulerCallback mSchedulerCallback;
-
-    // The scheduler should initially disable VSYNC.
-    struct ExpectDisableVsync {
-        ExpectDisableVsync(mock::SchedulerCallback& callback) {
-            EXPECT_CALL(callback, setVsyncEnabled(false)).Times(1);
-        }
-    } mExpectDisableVsync{mSchedulerCallback};
-
     TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback};
 
     Scheduler::ConnectionHandle mConnectionHandle;
@@ -166,9 +158,9 @@
     sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger());
 
     // recordLayerHistory should be a noop
-    ASSERT_EQ(static_cast<size_t>(0), mScheduler->getNumActiveLayers());
+    ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
     mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
-    ASSERT_EQ(static_cast<size_t>(0), mScheduler->getNumActiveLayers());
+    ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
 
     constexpr bool kPowerStateNormal = true;
     mScheduler->setDisplayPowerState(kPowerStateNormal);
@@ -181,17 +173,17 @@
 }
 
 TEST_F(SchedulerTest, updateDisplayModes) {
-    ASSERT_EQ(static_cast<size_t>(0), mScheduler->layerHistorySize());
+    ASSERT_EQ(0u, mScheduler->layerHistorySize());
     sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger());
-    ASSERT_EQ(static_cast<size_t>(1), mScheduler->layerHistorySize());
+    ASSERT_EQ(1u, mScheduler->layerHistorySize());
 
     mScheduler->setRefreshRateConfigs(
             std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60, mode120},
                                                             mode60->getId()));
 
-    ASSERT_EQ(static_cast<size_t>(0), mScheduler->getNumActiveLayers());
+    ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
     mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
-    ASSERT_EQ(static_cast<size_t>(1), mScheduler->getNumActiveLayers());
+    ASSERT_EQ(1u, mScheduler->getNumActiveLayers());
 }
 
 TEST_F(SchedulerTest, testDispatchCachedReportedMode) {
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index d021178..eed62a7 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -33,7 +33,6 @@
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/MockEventThread.h"
-#include "mock/MockMessageQueue.h"
 #include "mock/MockVsyncController.h"
 
 namespace android {
@@ -70,8 +69,8 @@
     std::string name() override { return "BufferStateLayer"; }
     sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
         sp<Client> client;
-        LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT,
-                               LAYER_FLAGS, LayerMetadata());
+        LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS,
+                               LayerMetadata());
         return new BufferStateLayer(args);
     }
 };
@@ -81,7 +80,7 @@
     std::string name() override { return "EffectLayer"; }
     sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
         sp<Client> client;
-        LayerCreationArgs args(flinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
+        LayerCreationArgs args(flinger.flinger(), client, "color-layer", LAYER_FLAGS,
                                LayerMetadata());
         return new EffectLayer(args);
     }
@@ -112,7 +111,6 @@
     void commitTransaction();
 
     TestableSurfaceFlinger mFlinger;
-    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
 
     std::vector<sp<Layer>> mLayers;
 };
@@ -125,7 +123,6 @@
     setupScheduler();
 
     mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
-    mFlinger.mutableEventQueue().reset(mMessageQueue);
 }
 
 void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) {
@@ -172,7 +169,7 @@
 namespace {
 
 TEST_P(SetFrameRateTest, SetAndGet) {
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -183,7 +180,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetParent) {
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -208,7 +205,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetParentAllVote) {
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -247,7 +244,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetChild) {
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -272,7 +269,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetChildAllVote) {
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -311,7 +308,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) {
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -341,7 +338,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) {
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -372,7 +369,7 @@
 }
 
 TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) {
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     const auto& layerFactory = GetParam();
 
@@ -454,24 +451,20 @@
     parent->setFrameRate(FRAME_RATE_VOTE1);
     commitTransaction();
 
-    mFlinger.mutableScheduler()
-            .mutableLayerHistory()
-            ->record(parent.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer);
-    mFlinger.mutableScheduler()
-            .mutableLayerHistory()
-            ->record(child.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer);
+    auto& history = mFlinger.mutableScheduler().mutableLayerHistory();
+    history.record(parent.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer);
+    history.record(child.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer);
 
-    const auto layerHistorySummary =
-            mFlinger.mutableScheduler()
-                    .mutableLayerHistory()
-                    ->summarize(*mFlinger.mutableScheduler().refreshRateConfigs(), 0);
-    ASSERT_EQ(2u, layerHistorySummary.size());
-    EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[0].desiredRefreshRate);
-    EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[1].desiredRefreshRate);
+    const auto configs = mFlinger.mutableScheduler().refreshRateConfigs();
+    const auto summary = history.summarize(*configs, 0);
+
+    ASSERT_EQ(2u, summary.size());
+    EXPECT_EQ(FRAME_RATE_VOTE1.rate, summary[0].desiredRefreshRate);
+    EXPECT_EQ(FRAME_RATE_VOTE1.rate, summary[1].desiredRefreshRate);
 }
 
 TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) {
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     const auto& layerFactory = GetParam();
 
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index 8c30341..f7d34ac 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -52,7 +52,7 @@
     // Cleanup conditions
 
     // Creating the display commits a display transaction.
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 }
 
 TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) {
@@ -87,7 +87,7 @@
     // Cleanup conditions
 
     // Creating the display commits a display transaction.
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
index 7087fb6..c7e61c9 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
@@ -41,7 +41,7 @@
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
 
     // Destroying the display commits a display transaction.
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
index 29ff0cd..c9a2b00 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
@@ -39,7 +39,7 @@
     // Call Expectations
 
     // We expect a scheduled commit for the display transaction.
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
@@ -86,7 +86,7 @@
     // Call Expectations
 
     // We expect a scheduled commit for the display transaction.
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index e1b44cf..37cf05e 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -47,7 +47,7 @@
     Case::Display::setupHwcGetActiveConfigCallExpectations(this);
 
     // We expect a scheduled commit for the display transaction.
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
 
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 6edebd4..b57feff 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -273,7 +273,7 @@
     }
 
     static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1);
+        EXPECT_CALL(*test->mFlinger.scheduler(), scheduleFrame()).Times(1);
     }
 
     static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 1d21bd4..9d1fc98 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -30,21 +30,30 @@
 
 namespace android {
 
-class TestableScheduler : public Scheduler {
+class TestableScheduler : public Scheduler, private ICompositor {
 public:
-    TestableScheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs,
+    TestableScheduler(std::shared_ptr<scheduler::RefreshRateConfigs> configs,
                       ISchedulerCallback& callback)
           : TestableScheduler(std::make_unique<mock::VsyncController>(),
-                              std::make_unique<mock::VSyncTracker>(), refreshRateConfigs,
+                              std::make_unique<mock::VSyncTracker>(), std::move(configs),
                               callback) {}
 
     TestableScheduler(std::unique_ptr<scheduler::VsyncController> vsyncController,
                       std::unique_ptr<scheduler::VSyncTracker> vsyncTracker,
-                      const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs,
+                      std::shared_ptr<scheduler::RefreshRateConfigs> configs,
                       ISchedulerCallback& callback)
-          : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr},
-                      refreshRateConfigs, callback, createLayerHistory(),
-                      {.useContentDetection = true}) {}
+          : Scheduler(*this, callback, {.useContentDetection = true}) {
+        mVsyncSchedule = {std::move(vsyncController), std::move(vsyncTracker), nullptr};
+        setRefreshRateConfigs(std::move(configs));
+
+        ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
+            // Execute task to prevent broken promise exception on destruction.
+            handler->handleMessage(Message());
+        });
+    }
+
+    MOCK_METHOD(void, scheduleFrame, (), (override));
+    MOCK_METHOD(void, postMessage, (sp<MessageHandler>&&), (override));
 
     // Used to inject mock event thread.
     ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
@@ -58,22 +67,13 @@
     auto& mutablePrimaryHWVsyncEnabled() { return mPrimaryHWVsyncEnabled; }
     auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
 
-    bool hasLayerHistory() const { return static_cast<bool>(mLayerHistory); }
+    auto& mutableLayerHistory() { return mLayerHistory; }
 
-    auto* mutableLayerHistory() { return mLayerHistory.get(); }
-
-    size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS {
-        if (!mLayerHistory) return 0;
-        return mutableLayerHistory()->mLayerInfos.size();
-    }
+    size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mLayerInfos.size(); }
+    size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayersEnd; }
 
     auto refreshRateConfigs() { return holdRefreshRateConfigs(); }
 
-    size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS {
-        if (!mLayerHistory) return 0;
-        return mutableLayerHistory()->mActiveLayersEnd;
-    }
-
     void replaceTouchTimer(int64_t millis) {
         if (mTouchTimer) {
             mTouchTimer.reset();
@@ -112,6 +112,12 @@
         mVsyncSchedule.controller.reset();
         mConnections.clear();
     }
+
+private:
+    // ICompositor overrides:
+    bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
+    void composite(nsecs_t) override {}
+    void sample() override {}
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 8cca6af..4c5789e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -73,20 +73,11 @@
         return nullptr;
     }
 
-    std::unique_ptr<MessageQueue> createMessageQueue(ICompositor& compositor) override {
-        return std::make_unique<android::impl::MessageQueue>(compositor);
-    }
-
     std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
             Fps /*currentRefreshRate*/) override {
         return std::make_unique<scheduler::FakePhaseOffsets>();
     }
 
-    std::unique_ptr<Scheduler> createScheduler(
-            const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) override {
-        return nullptr;
-    }
-
     sp<SurfaceInterceptor> createSurfaceInterceptor() override {
         return new android::impl::SurfaceInterceptor();
     }
@@ -431,7 +422,6 @@
     auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
     auto& mutableDisplays() { return mFlinger->mDisplays; }
     auto& mutableDrawingState() { return mFlinger->mDrawingState; }
-    auto& mutableEventQueue() { return mFlinger->mEventQueue; }
     auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; }
     auto& mutableInterceptor() { return mFlinger->mInterceptor; }
     auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
@@ -460,7 +450,6 @@
         mutableDisplays().clear();
         mutableCurrentState().displays.clear();
         mutableDrawingState().displays.clear();
-        mutableEventQueue().reset();
         mutableInterceptor().clear();
         mFlinger->mScheduler.reset();
         mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 8caadfb..ec19100 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -29,7 +29,6 @@
 #include "TestableScheduler.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/MockEventThread.h"
-#include "mock/MockMessageQueue.h"
 #include "mock/MockVsyncController.h"
 
 namespace android {
@@ -46,7 +45,6 @@
                 ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
 
-        mFlinger.mutableEventQueue().reset(mMessageQueue);
         setupScheduler();
     }
 
@@ -92,7 +90,6 @@
 
     std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
 
-    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
     mock::VsyncController* mVsyncController = new mock::VsyncController();
     mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker();
     mock::MockFence* mFenceUnsignaled = new mock::MockFence();
@@ -146,7 +143,7 @@
 
     void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-        EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+        EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
         TransactionInfo transaction;
         setupSingle(transaction, flags, syncInputWindows,
                     /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
@@ -176,7 +173,7 @@
 
     void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-        EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+        EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
         // first check will see desired present time has not passed,
         // but afterwards it will look like the desired present time has passed
@@ -207,9 +204,9 @@
         ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
         nsecs_t time = systemTime();
         if (!syncInputWindows) {
-            EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(2);
+            EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2);
         } else {
-            EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+            EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
         }
         // transaction that should go on the pending thread
         TransactionInfo transactionA;
@@ -454,7 +451,7 @@
 
 TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
     ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
-    EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1);
+    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
 
     TransactionInfo transactionA; // transaction to go on pending queue
     setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index bd6a780..deeb785 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -57,7 +57,7 @@
 
     sp<BufferStateLayer> createBufferStateLayer() {
         sp<Client> client;
-        LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0,
+        LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0,
                                LayerMetadata());
         return new BufferStateLayer(args);
     }
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index cebd451..6e00748 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -69,16 +69,16 @@
         t1.displays.add(display);
     }
 
-    std::function<int32_t(const sp<IBinder>&)> getLayerIdFn = [&](const sp<IBinder>& handle) {
+    TransactionProtoParser::LayerHandleToIdFn getLayerIdFn = [&](const sp<IBinder>& handle) {
         return (handle == layerHandle) ? 42 : -1;
     };
-    std::function<int32_t(const sp<IBinder>&)> getDisplayIdFn = [&](const sp<IBinder>& handle) {
+    TransactionProtoParser::DisplayHandleToIdFn getDisplayIdFn = [&](const sp<IBinder>& handle) {
         return (handle == displayHandle) ? 43 : -1;
     };
-    std::function<sp<IBinder>(int32_t)> getLayerHandleFn = [&](int32_t id) {
+    TransactionProtoParser::LayerIdToHandleFn getLayerHandleFn = [&](int32_t id) {
         return (id == 42) ? layerHandle : nullptr;
     };
-    std::function<sp<IBinder>(int32_t)> getDisplayHandleFn = [&](int32_t id) {
+    TransactionProtoParser::DisplayIdToHandleFn getDisplayHandleFn = [&](int32_t id) {
         return (id == 43) ? displayHandle : nullptr;
     };
 
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index bf69704..704340d 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -57,7 +57,7 @@
 
     sp<BufferStateLayer> createBufferStateLayer() {
         sp<Client> client;
-        LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0,
+        LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0,
                                LayerMetadata());
         return new BufferStateLayer(args);
     }
diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
index e4f7469..15fea9c 100644
--- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
@@ -27,7 +27,6 @@
 #include "TunnelModeEnabledReporter.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/MockEventThread.h"
-#include "mock/MockMessageQueue.h"
 
 namespace android {
 
@@ -69,12 +68,12 @@
 
     TestableSurfaceFlinger mFlinger;
     Hwc2::mock::Composer* mComposer = nullptr;
-    sp<TestableTunnelModeEnabledListener> mTunnelModeEnabledListener =
-            new TestableTunnelModeEnabledListener();
-    sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter =
-            new TunnelModeEnabledReporter();
 
-    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+    sp<TestableTunnelModeEnabledListener> mTunnelModeEnabledListener =
+            sp<TestableTunnelModeEnabledListener>::make();
+
+    sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter =
+            sp<TunnelModeEnabledReporter>::make();
 };
 
 TunnelModeEnabledReporterTest::TunnelModeEnabledReporterTest() {
@@ -82,7 +81,6 @@
             ::testing::UnitTest::GetInstance()->current_test_info();
     ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
 
-    mFlinger.mutableEventQueue().reset(mMessageQueue);
     setupScheduler();
     mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
     mFlinger.flinger()->mTunnelModeEnabledReporter = mTunnelModeEnabledReporter;
@@ -100,8 +98,7 @@
 sp<BufferStateLayer> TunnelModeEnabledReporterTest::createBufferStateLayer(
         LayerMetadata metadata = {}) {
     sp<Client> client;
-    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT,
-                           LAYER_FLAGS, metadata);
+    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata);
     return new BufferStateLayer(args);
 }
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index ba2e4db..8b48e1c 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -25,7 +25,7 @@
 class MockLayer : public Layer {
 public:
     MockLayer(SurfaceFlinger* flinger, std::string name)
-          : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 800, 600, 0, {})) {}
+          : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {}
     explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}
 
     MOCK_CONST_METHOD0(getType, const char*());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
deleted file mode 100644
index 5fb06fd..0000000
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "mock/MockMessageQueue.h"
-
-namespace android::mock {
-
-MessageQueue::MessageQueue() {
-    ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
-        // Execute task to prevent broken promise exception on destruction.
-        handler->handleMessage(Message());
-    });
-}
-
-MessageQueue::~MessageQueue() = default;
-
-} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
deleted file mode 100644
index d684337..0000000
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2018 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 <gmock/gmock.h>
-
-#include "FrameTimeline.h"
-#include "Scheduler/EventThread.h"
-#include "Scheduler/MessageQueue.h"
-
-namespace android::mock {
-
-class MessageQueue : public android::MessageQueue {
-public:
-    MessageQueue();
-    ~MessageQueue() override;
-
-    MOCK_METHOD1(setInjector, void(sp<EventThreadConnection>));
-    MOCK_METHOD0(waitMessage, void());
-    MOCK_METHOD1(postMessage, void(sp<MessageHandler>&&));
-    MOCK_METHOD3(initVsync,
-                 void(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
-                      std::chrono::nanoseconds));
-    MOCK_METHOD1(setDuration, void(std::chrono::nanoseconds workDuration));
-
-    MOCK_METHOD(void, scheduleCommit, (), (override));
-    MOCK_METHOD(void, scheduleComposite, (), (override));
-
-    MOCK_METHOD(std::optional<Clock::time_point>, getScheduledFrameTime, (), (const, override));
-};
-
-} // namespace android::mock