Merge "SF: Split Scheduler initialization"
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 54c7114..7cc595a 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -801,8 +801,11 @@
 
     static std::string actionToString(int32_t action);
 
+    // MotionEvent will transform various axes in different ways, based on the source. For
+    // example, the x and y axes will not have any offsets/translations applied if it comes from a
+    // relative mouse device (since SOURCE_RELATIVE_MOUSE is a non-pointer source). These methods
+    // are used to apply these transformations for different axes.
     static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy);
-
     static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&,
                                                const PointerCoords&);
 
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/src/binder.rs b/libs/binder/rust/src/binder.rs
index 4e048d7..bd2e695 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.
@@ -177,25 +177,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 +206,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 +475,8 @@
 ///     fn on_transact(
 ///         &self,
 ///         code: TransactionCode,
-///         data: &Parcel,
-///         reply: &mut Parcel,
+///         data: &BorrowedParcel,
+///         reply: &mut BorrowedParcel,
 ///     ) -> Result<()> {
 ///         // ...
 ///     }
@@ -655,13 +655,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 +676,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 +692,8 @@
 /// fn on_transact(
 ///     service: &dyn IServiceManager,
 ///     code: TransactionCode,
-///     data: &Parcel,
-///     reply: &mut Parcel,
+///     data: &BorrowedParcel,
+///     reply: &mut BorrowedParcel,
 /// ) -> binder::Result<()> {
 ///     // ...
 ///     Ok(())
@@ -847,7 +847,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 +922,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 +988,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 +1040,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..f5d7187 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(())
     ///        # }
@@ -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..83553d7 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)
         }
     }
 
@@ -415,13 +414,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 +428,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 +437,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/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/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 3881620..4a63544 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -88,10 +88,10 @@
     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);
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/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index b2d5048..8607e1d 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 {
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index d018800..24a7720 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -66,11 +66,21 @@
     return transformedXy - transformedOrigin;
 }
 
-bool shouldDisregardTranslation(uint32_t source) {
+bool isFromSource(uint32_t source, uint32_t test) {
+    return (source & test) == test;
+}
+
+bool shouldDisregardTransformation(uint32_t source) {
+    // Do not apply any transformations to axes from joysticks or touchpads.
+    return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) ||
+            isFromSource(source, AINPUT_SOURCE_CLASS_POSITION);
+}
+
+bool shouldDisregardOffset(uint32_t source) {
     // Pointer events are the only type of events that refer to absolute coordinates on the display,
     // so we should apply the entire window transform. For other types of events, we should make
     // sure to not apply the window translation/offset.
-    return (source & AINPUT_SOURCE_CLASS_POINTER) == 0;
+    return !isFromSource(source, AINPUT_SOURCE_CLASS_POINTER);
 }
 
 } // namespace
@@ -707,7 +717,7 @@
 #endif
 
 bool MotionEvent::isTouchEvent(uint32_t source, int32_t action) {
-    if (source & AINPUT_SOURCE_CLASS_POINTER) {
+    if (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER)) {
         // Specifically excludes HOVER_MOVE and SCROLL.
         switch (action & AMOTION_EVENT_ACTION_MASK) {
         case AMOTION_EVENT_ACTION_DOWN:
@@ -764,17 +774,31 @@
     return android::base::StringPrintf("%" PRId32, action);
 }
 
+// Apply the given transformation to the point without checking whether the entire transform
+// should be disregarded altogether for the provided source.
+static inline vec2 calculateTransformedXYUnchecked(uint32_t source, const ui::Transform& transform,
+                                                   const vec2& xy) {
+    return shouldDisregardOffset(source) ? transformWithoutTranslation(transform, xy)
+                                         : transform.transform(xy);
+}
+
 vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& transform,
                                          const vec2& xy) {
-    return shouldDisregardTranslation(source) ? transformWithoutTranslation(transform, xy)
-                                              : transform.transform(xy);
+    if (shouldDisregardTransformation(source)) {
+        return xy;
+    }
+    return calculateTransformedXYUnchecked(source, transform, xy);
 }
 
 float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source,
                                                  const ui::Transform& transform,
                                                  const PointerCoords& coords) {
+    if (shouldDisregardTransformation(source)) {
+        return coords.getAxisValue(axis);
+    }
+
     if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
-        const vec2 xy = calculateTransformedXY(source, transform, coords.getXYValue());
+        const vec2 xy = calculateTransformedXYUnchecked(source, transform, coords.getXYValue());
         static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
         return xy[axis];
     }
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 1b594f1..a92016b 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -647,9 +647,8 @@
     ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
 }
 
-MotionEvent createTouchDownEvent(float x, float y, float dx, float dy,
-                                 const ui::Transform& transform,
-                                 const ui::Transform& rawTransform) {
+MotionEvent createMotionEvent(int32_t source, uint32_t action, float x, float y, float dx, float dy,
+                              const ui::Transform& transform, const ui::Transform& rawTransform) {
     std::vector<PointerProperties> pointerProperties;
     pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER});
     std::vector<PointerCoords> pointerCoords;
@@ -660,8 +659,8 @@
     pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy);
     nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
     MotionEvent event;
-    event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN,
-                     /* displayId */ 0, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN,
+    event.initialize(InputEvent::nextId(), /* deviceId */ 1, source,
+                     /* displayId */ 0, INVALID_HMAC, action,
                      /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE,
                      /* buttonState */ 0, MotionClassification::NONE, transform,
                      /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
@@ -670,6 +669,13 @@
     return event;
 }
 
+MotionEvent createTouchDownEvent(float x, float y, float dx, float dy,
+                                 const ui::Transform& transform,
+                                 const ui::Transform& rawTransform) {
+    return createMotionEvent(AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_DOWN, x, y, dx, dy,
+                             transform, rawTransform);
+}
+
 TEST_F(MotionEventTest, ApplyTransform) {
     // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
     ui::Transform identity;
@@ -708,16 +714,39 @@
                 changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), 0.001);
 }
 
+TEST_F(MotionEventTest, JoystickAndTouchpadAreNotTransformed) {
+    constexpr static std::array kNonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD,
+                                                                    AMOTION_EVENT_ACTION_DOWN),
+                                                          std::pair(AINPUT_SOURCE_JOYSTICK,
+                                                                    AMOTION_EVENT_ACTION_MOVE)};
+    // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
+    ui::Transform transform(ui::Transform::ROT_90, 800, 400);
+    transform.set(transform.tx() + 20, transform.ty() + 40);
+
+    for (const auto& [source, action] : kNonTransformedSources) {
+        const MotionEvent event =
+                createMotionEvent(source, action, 60, 100, 0, 0, transform, transform);
+
+        // These events should not be transformed in any way.
+        ASSERT_EQ(60, event.getX(0));
+        ASSERT_EQ(100, event.getY(0));
+        ASSERT_EQ(event.getRawX(0), event.getX(0));
+        ASSERT_EQ(event.getRawY(0), event.getY(0));
+    }
+}
+
 TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) {
-    constexpr static auto NON_POINTER_SOURCES = {AINPUT_SOURCE_TRACKBALL,
-                                                 AINPUT_SOURCE_MOUSE_RELATIVE,
-                                                 AINPUT_SOURCE_JOYSTICK};
-    for (uint32_t source : NON_POINTER_SOURCES) {
-        // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
-        ui::Transform transform(ui::Transform::ROT_90, 800, 400);
-        transform.set(transform.tx() + 20, transform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, transform);
-        event.setSource(source);
+    constexpr static std::array kNonPointerSources = {std::pair(AINPUT_SOURCE_TRACKBALL,
+                                                                AMOTION_EVENT_ACTION_DOWN),
+                                                      std::pair(AINPUT_SOURCE_MOUSE_RELATIVE,
+                                                                AMOTION_EVENT_ACTION_MOVE)};
+    // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
+    ui::Transform transform(ui::Transform::ROT_90, 800, 400);
+    transform.set(transform.tx() + 20, transform.ty() + 40);
+
+    for (const auto& [source, action] : kNonPointerSources) {
+        const MotionEvent event =
+                createMotionEvent(source, action, 60, 100, 42, 96, transform, transform);
 
         // Since this event comes from a non-pointer source, it should include rotation but not
         // translation/offset.
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/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 719b855..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);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -111,8 +111,7 @@
     return RenderEngine::create(args);
 }
 
-static std::shared_ptr<ExternalTexture> allocateBuffer(RenderEngine& re,
-                                                       uint32_t width,
+static std::shared_ptr<ExternalTexture> allocateBuffer(RenderEngine& re, uint32_t width,
                                                        uint32_t height,
                                                        uint64_t extraUsageFlags = 0,
                                                        std::string name = "output") {
@@ -160,11 +159,21 @@
 
     auto [status, drawFence] =
             re.drawLayers(display, layers, texture, kUseFrameBufferCache, base::unique_fd()).get();
-    sp<Fence> waitFence = new Fence(std::move(drawFence));
+    sp<Fence> waitFence = sp<Fence>::make(std::move(drawFence));
     waitFence->waitForever(LOG_TAG);
     return texture;
 }
 
+/**
+ * Helper for timing calls to drawLayers.
+ *
+ * Caller needs to create RenderEngine and the LayerSettings, and this takes
+ * care of setting up the display, starting and stopping the timer, calling
+ * drawLayers, and saving (if --save is used).
+ *
+ * This times both the CPU and GPU work initiated by drawLayers. All work done
+ * outside of the for loop is excluded from the timing measurements.
+ */
 static void benchDrawLayers(RenderEngine& re, const std::vector<LayerSettings>& layers,
                             benchmark::State& benchState, const char* saveFileName) {
     auto [width, height] = getDisplaySize();
@@ -177,18 +186,16 @@
             .maxLuminance = 500,
     };
 
-    base::unique_fd fence;
+    // This loop starts and stops the timer.
     for (auto _ : benchState) {
-        auto [status, drawFence] =
-                re.drawLayers(display, layers, outputBuffer, kUseFrameBufferCache, std::move(fence))
-                        .get();
-        fence = std::move(drawFence);
+        auto [status, drawFence] = re.drawLayers(display, layers, outputBuffer,
+                                                 kUseFrameBufferCache, base::unique_fd())
+                                           .get();
+        sp<Fence> waitFence = sp<Fence>::make(std::move(drawFence));
+        waitFence->waitForever(LOG_TAG);
     }
 
     if (renderenginebench::save() && saveFileName) {
-        sp<Fence> waitFence = new Fence(std::move(fence));
-        waitFence->waitForever(LOG_TAG);
-
         // Copy to a CPU-accessible buffer so we can encode it.
         outputBuffer = copyBuffer(re, outputBuffer, GRALLOC_USAGE_SW_READ_OFTEN, "to_encode");
 
@@ -209,8 +216,8 @@
 
     // Initially use cpu access so we can decode into it with AImageDecoder.
     auto [width, height] = getDisplaySize();
-    auto srcBuffer = allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN,
-                                    "decoded_source");
+    auto srcBuffer =
+            allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source");
     {
         std::string srcImage = base::GetExecutableDirectory();
         srcImage.append("/resources/homescreen.png");
@@ -249,4 +256,4 @@
     benchDrawLayers(*re, layers, benchState, "blurred");
 }
 
-BENCHMARK(BM_blur)->Apply(RunSkiaGL);
+BENCHMARK(BM_blur)->Apply(RunSkiaGLThreaded);
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 73dadef..53136e4 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:
@@ -127,159 +133,13 @@
         default:
             shader.append(R"(
                     float3 ScaleLuminance(float3 xyz) {
-                        return xyz * in_inputMaxLuminance;
+                        return xyz * in_libtonemap_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.
-                    shader.append(R"(
-                            float3 ToneMap(float3 xyz) {
-                                return clamp(xyz, 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.
-                    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;
-                                    }
-                                }
-
-                                // 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;
-    }
-}
-
 // Normalizes from absolute light back to relative light (maps from [0, maxNits] back to [0, 1])
 static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, SkString& shader) {
     switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
@@ -300,7 +160,7 @@
         default:
             shader.append(R"(
                     float3 NormalizeLuminance(float3 xyz) {
-                        return xyz / in_displayMaxLuminance;
+                        return xyz / in_libtonemap_displayMaxLuminance;
                     }
                 )");
             break;
@@ -309,19 +169,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);
     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 +262,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 +330,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..350bca4
--- /dev/null
+++ b/libs/tonemap/tonemap.cpp
@@ -0,0 +1,256 @@
+/*
+ * 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,
+};
+
+static const constexpr auto kToneMapAlgorithm = ToneMapAlgorithm::AndroidO;
+
+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;
+    }
+};
+
+} // 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;
+        }
+    });
+
+    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 176cf89..6952587 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(
@@ -342,18 +332,6 @@
 std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
                                                    std::shared_ptr<EventEntry> eventEntry,
                                                    int32_t inputTargetFlags) {
-    if (eventEntry->type == EventEntry::Type::MOTION) {
-        const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
-        if ((motionEntry.source & AINPUT_SOURCE_CLASS_JOYSTICK) ||
-            (motionEntry.source & AINPUT_SOURCE_CLASS_POSITION)) {
-            const ui::Transform identityTransform;
-            // Use identity transform for joystick and position-based (touchpad) events because they
-            // don't depend on the window transform.
-            return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, identityTransform,
-                                                   identityTransform, 1.0f /*globalScaleFactor*/);
-        }
-    }
-
     if (inputTarget.useDefaultPointerTransform()) {
         const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
         return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
@@ -2531,8 +2509,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;
@@ -4737,21 +4714,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 ba0ce95..d8fd16c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -3012,59 +3012,6 @@
     EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
 }
 
-TEST_F(InputDispatcherTest, NonPointerMotionEvent_JoystickAndTouchpadNotTransformed) {
-    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window =
-            new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
-    const std::string name = window->getName();
-
-    // Window gets transformed by offset values.
-    window->setWindowOffset(500.0f, 500.0f);
-
-    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
-    window->setFocusable(true);
-
-    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
-
-    // First, we set focused window so that focusedWindowHandle is not null.
-    setFocusedWindow(window);
-
-    // Second, we consume focus event if it is right or wrong according to onFocusChangedLocked.
-    window->consumeFocusEvent(true);
-
-    constexpr const std::array nonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD,
-                                                                  AMOTION_EVENT_ACTION_DOWN),
-                                                        std::pair(AINPUT_SOURCE_JOYSTICK,
-                                                                  AMOTION_EVENT_ACTION_MOVE)};
-    for (const auto& [source, action] : nonTransformedSources) {
-        const NotifyMotionArgs motionArgs = generateMotionArgs(action, source, ADISPLAY_ID_DEFAULT);
-        mDispatcher->notifyMotion(&motionArgs);
-
-        MotionEvent* event = window->consumeMotion();
-        ASSERT_NE(event, nullptr);
-
-        const MotionEvent& motionEvent = *event;
-        EXPECT_EQ(action, motionEvent.getAction());
-        EXPECT_EQ(motionArgs.pointerCount, motionEvent.getPointerCount());
-
-        float expectedX = motionArgs.pointerCoords[0].getX();
-        float expectedY = motionArgs.pointerCoords[0].getY();
-
-        // Ensure the axis values from the final motion event are not transformed.
-        EXPECT_EQ(expectedX, motionEvent.getX(0))
-                << "expected " << expectedX << " for x coord of " << name.c_str() << ", got "
-                << motionEvent.getX(0);
-        EXPECT_EQ(expectedY, motionEvent.getY(0))
-                << "expected " << expectedY << " for y coord of " << name.c_str() << ", got "
-                << motionEvent.getY(0);
-        // Ensure the raw and transformed axis values for the motion event are the same.
-        EXPECT_EQ(motionEvent.getRawX(0), motionEvent.getX(0))
-                << "expected raw and transformed X-axis values to be equal";
-        EXPECT_EQ(motionEvent.getRawY(0), motionEvent.getY(0))
-                << "expected raw and transformed Y-axis values to be equal";
-    }
-}
-
 /**
  * Ensure that separate calls to sign the same data are generating the same key.
  * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
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/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/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 8c4c8b7..a4c21f4 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -171,7 +171,7 @@
     // the mStateLock.
     ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
 
-    bool getAutoRefresh() const { return mAutoRefresh; }
+    bool getAutoRefresh() const { return mDrawingState.autoRefresh; }
     bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
 
     // Returns true if the next buffer should be presented at the expected present time
@@ -182,7 +182,6 @@
     // specific logic
     virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0;
 
-    std::atomic<bool> mAutoRefresh{false};
     std::atomic<bool> mSidebandStreamChanged{false};
 
 private:
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 8aecec1..dec7cc0 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -216,7 +216,7 @@
     bool autoRefresh;
     status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &autoRefresh,
                                                       &queuedBuffer, maxFrameNumberToAcquire);
-    mAutoRefresh = autoRefresh;
+    mDrawingState.autoRefresh = autoRefresh;
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
         // layer update so we check again at the next opportunity.
@@ -300,7 +300,7 @@
 
     // Decrement the queued-frames count.  Signal another event if we
     // have more frames pending.
-    if ((queuedBuffer && more_frames_pending) || mAutoRefresh) {
+    if ((queuedBuffer && more_frames_pending) || mDrawingState.autoRefresh) {
         mFlinger->onLayerUpdate();
     }
 
@@ -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 b6bea97..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);
         }
     }
 
@@ -667,9 +660,7 @@
 }
 
 void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
-    if (!mAutoRefresh.exchange(autoRefresh)) {
-        mFlinger->onLayerUpdate();
-    }
+    mDrawingState.autoRefresh = autoRefresh;
 }
 
 bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
@@ -892,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 d36b816..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 {
@@ -280,6 +278,8 @@
         sp<IBinder> releaseBufferEndpoint;
 
         gui::DropInputMode dropInputMode;
+
+        bool autoRefresh = false;
     };
 
     /*
@@ -426,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;
@@ -691,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; }
 
@@ -877,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};
 
@@ -1115,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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 34629a2..d1e24d9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -904,9 +904,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(
@@ -1949,7 +1948,7 @@
     }
 
     if (mTracingEnabledChanged) {
-        mTracingEnabled = mTracing.isEnabled();
+        mTracingEnabled = mLayerTracing.isEnabled();
         mTracingEnabledChanged = false;
     }
 
@@ -1963,24 +1962,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 +2012,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();
 
@@ -2113,12 +2097,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");
         }
     }
 
@@ -3041,32 +3025,24 @@
     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;
 
-    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] = 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);
     }
 
     mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3075,7 +3051,7 @@
         const DisplayDevice* display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get();
         ui::Transform displayTransform = ui::Transform();
 
-        if (enablePerWindowInputRotation() && display != nullptr) {
+        if (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);
@@ -3366,20 +3342,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;
@@ -3395,7 +3366,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 */,
@@ -3403,13 +3376,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;
 }
@@ -3814,10 +3780,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;
@@ -3989,7 +3956,7 @@
     }
     if (layer == nullptr) {
         for (auto& [listener, callbackIds] : s.listeners) {
-            mTransactionCallbackInvoker.addUnpresentedCallbackHandle(
+            mTransactionCallbackInvoker.registerUnpresentedCallbackHandle(
                     new CallbackHandle(listener, callbackIds, s.surface));
         }
         return 0;
@@ -4260,6 +4227,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,
@@ -4269,11 +4242,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;
@@ -4292,17 +4261,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;
         }
@@ -4311,22 +4277,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?");
@@ -4335,40 +4292,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;
@@ -4388,7 +4327,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;
     }
@@ -4398,9 +4337,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) {
@@ -4416,7 +4353,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
@@ -4426,7 +4362,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();
@@ -4437,34 +4373,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;
 }
@@ -4712,7 +4638,7 @@
         }
 
         if (dumpLayers) {
-            LayersTraceFileProto traceFileProto = SurfaceTracing::createLayersTraceFileProto();
+            LayersTraceFileProto traceFileProto = mLayerTracing.createTraceFileProto();
             LayersTraceProto* layersTrace = traceFileProto.add_entry();
             LayersProto layersProto = dumpProtoFromMainThread();
             layersTrace->mutable_layers()->Swap(&layersProto);
@@ -4734,8 +4660,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);
@@ -5050,8 +4976,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);
 
     {
@@ -5133,7 +5057,7 @@
     /*
      * Tracing state
      */
-    mTracing.dump(result);
+    mLayerTracing.dump(result);
     result.append("\n");
 
     /*
@@ -5560,20 +5484,20 @@
                 bool tracingEnabledChanged;
                 if (n) {
                     ALOGD("LayerTracing enabled");
-                    tracingEnabledChanged = mTracing.enable();
+                    tracingEnabledChanged = mLayerTracing.enable();
                     if (tracingEnabledChanged) {
-                        schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait();
+                        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?
@@ -5614,7 +5538,7 @@
                 }
 
                 ALOGD("Updating trace buffer to %d KB", n);
-                mTracing.setBufferSize(n * 1024);
+                mLayerTracing.setBufferSize(n * 1024);
                 reply->writeInt32(NO_ERROR);
                 return NO_ERROR;
             }
@@ -5659,7 +5583,7 @@
             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;
             }
@@ -6813,11 +6737,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) {
@@ -6878,19 +6801,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;
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bf628dc..8897858 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -62,8 +62,8 @@
 #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"
 
@@ -353,7 +353,7 @@
     friend class MonitoredProducer;
     friend class RefreshRateOverlay;
     friend class RegionSamplingThread;
-    friend class SurfaceTracing;
+    friend class LayerTracing;
 
     // For unit tests
     friend class TestableSurfaceFlinger;
@@ -684,9 +684,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 +760,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 +789,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.
@@ -1049,12 +1039,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 +1105,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 +1187,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;
@@ -1339,19 +1324,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 +1340,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/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/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/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..1ac5680 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -142,6 +142,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 daa6543..dffc6c6 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -532,6 +532,7 @@
 
     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);
@@ -898,7 +899,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()));
         });
 
@@ -937,7 +937,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);
@@ -949,7 +948,6 @@
     }
 
     static void cleanupInjectedLayers(CompositionTest* test) {
-        EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(1);
         Base::cleanupInjectedLayers(test);
     }
 
@@ -987,7 +985,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/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/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/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index d9c6bfb..84c845d 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -70,8 +70,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 +81,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);
     }
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/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..ade4fbb 100644
--- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
@@ -100,8 +100,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*());