Merge "Log the cmd when the binder driver fails to consume buffer" into main
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 319716e..cbba711 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -40,6 +40,7 @@
 
 cc_library_headers {
     name: "libarect_headers",
+    host_supported: true,
     vendor_available: true,
     min_sdk_version: "29",
     // TODO(b/153609531): remove when no longer needed.
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index 455a433..7263e23 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -82,7 +82,9 @@
 
     int ret = TEMP_FAILURE_RETRY(poll(pfd, countof(pfd), -1));
     if (ret < 0) {
-        return -errno;
+        int saved_errno = errno;
+        ALOGE("FdTrigger poll returned error: %d, with error: %s", ret, strerror(saved_errno));
+        return -saved_errno;
     }
     LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", transportFd.fd.get());
 
@@ -106,6 +108,7 @@
 
     // POLLNVAL: invalid FD number, e.g. not opened.
     if (pfd[0].revents & POLLNVAL) {
+        LOG_ALWAYS_FATAL("Invalid FD number (%d) in FdTrigger (POLLNVAL)", pfd[0].fd);
         return BAD_VALUE;
     }
 
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 6273804..af56bf0 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -225,6 +225,8 @@
 
     SpAIBinder asBinder() override final;
 
+    const SpAIBinder& asBinderReference() { return mBinder; }
+
     bool isRemote() override final { return AIBinder_isRemote(mBinder.get()); }
 
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override {
diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp
index 92dab19..482d197 100644
--- a/libs/binder/tests/binderCacheUnitTest.cpp
+++ b/libs/binder/tests/binderCacheUnitTest.cpp
@@ -137,9 +137,9 @@
     ASSERT_EQ(binder1, result);
 
     // Kill the server, this should remove from cache.
-    foo.killServer(binder1);
     pid_t pid;
     ASSERT_EQ(OK, binder1->getDebugPid(&pid));
+    foo.killServer(binder1);
     system(("kill -9 " + std::to_string(pid)).c_str());
 
     sp<IBinder> binder2 = sp<BBinder>::make();
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index fbca35e..0ef200b 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -454,7 +454,7 @@
         GTEST_SKIP() << "This test requires multiple threads";
     }
 
-    constexpr size_t kNumThreads = 10;
+    constexpr size_t kNumThreads = 5;
 
     auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
 
@@ -499,11 +499,11 @@
 
     EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs);
 
-    // Potential flake, but make sure calls are handled in parallel. Due
-    // to past flakes, this only checks that the amount of time taken has
-    // some parallelism. Other tests such as ThreadPoolGreaterThanEqualRequested
-    // check this more exactly.
-    EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs);
+    // b/272429574, b/365294257
+    // This flakes too much to test. Parallelization is tested
+    // in ThreadPoolGreaterThanEqualRequested and other tests.
+    // Test to make sure calls are handled in parallel.
+    // EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs);
 }
 
 TEST_P(BinderRpc, ThreadPoolOverSaturated) {
@@ -515,8 +515,7 @@
     constexpr size_t kNumCalls = kNumThreads + 3;
     auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
 
-    // b/272429574 - below 500ms, the test fails
-    testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/);
+    testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/);
 }
 
 TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
@@ -530,8 +529,7 @@
     auto proc = createRpcTestSocketServerProcess(
             {.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections});
 
-    // b/272429574 - below 500ms, the test fails
-    testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/);
+    testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/);
 }
 
 TEST_P(BinderRpc, ThreadingStressTest) {
diff --git a/libs/bufferstreams/rust/src/stream_config.rs b/libs/bufferstreams/rust/src/stream_config.rs
index 454bdf1..8288f9f 100644
--- a/libs/bufferstreams/rust/src/stream_config.rs
+++ b/libs/bufferstreams/rust/src/stream_config.rs
@@ -32,10 +32,23 @@
     pub stride: u32,
 }
 
+impl From<StreamConfig> for HardwareBufferDescription {
+    fn from(config: StreamConfig) -> Self {
+        HardwareBufferDescription::new(
+            config.width,
+            config.height,
+            config.layers,
+            config.format,
+            config.usage,
+            config.stride,
+        )
+    }
+}
+
 impl StreamConfig {
     /// Tries to create a new HardwareBuffer from settings in a [StreamConfig].
     pub fn create_hardware_buffer(&self) -> Option<HardwareBuffer> {
-        HardwareBuffer::new(self.width, self.height, self.layers, self.format, self.usage)
+        HardwareBuffer::new(&(*self).into())
     }
 }
 
@@ -59,9 +72,10 @@
         assert!(maybe_buffer.is_some());
 
         let buffer = maybe_buffer.unwrap();
-        assert_eq!(config.width, buffer.width());
-        assert_eq!(config.height, buffer.height());
-        assert_eq!(config.format, buffer.format());
-        assert_eq!(config.usage, buffer.usage());
+        let description = buffer.description();
+        assert_eq!(config.width, description.width());
+        assert_eq!(config.height, description.height());
+        assert_eq!(config.format, description.format());
+        assert_eq!(config.usage, description.usage());
     }
 }
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index e9d799e..9c0a41e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -91,6 +91,7 @@
             },
         },
     },
+    native_coverage: false,
 }
 
 // NOTE: This is a compile time test, and does not need to be
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
index 97740db..d68d6ba 100644
--- a/libs/nativewindow/rust/Android.bp
+++ b/libs/nativewindow/rust/Android.bp
@@ -29,6 +29,8 @@
         "--bitfield-enum=AHardwareBuffer_UsageFlags",
 
         "--allowlist-file=.*/nativewindow/include/.*\\.h",
+        "--allowlist-file=.*/include/cutils/.*\\.h",
+        "--allowlist-file=.*/include_outside_system/cutils/.*\\.h",
         "--blocklist-type",
         "AParcel",
         "--raw-line",
@@ -39,6 +41,7 @@
     ],
     shared_libs: [
         "libbinder_ndk",
+        "libcutils",
         "libnativewindow",
     ],
     rustlibs: [
@@ -66,6 +69,7 @@
     srcs: [":libnativewindow_bindgen_internal"],
     shared_libs: [
         "libbinder_ndk",
+        "libcutils",
         "libnativewindow",
     ],
     rustlibs: [
diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs
new file mode 100644
index 0000000..c41ab8d
--- /dev/null
+++ b/libs/nativewindow/rust/src/handle.rs
@@ -0,0 +1,243 @@
+// Copyright (C) 2024 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.
+
+use std::{
+    ffi::c_int,
+    mem::forget,
+    os::fd::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
+    ptr::NonNull,
+};
+
+/// Rust wrapper around `native_handle_t`.
+///
+/// This owns the `native_handle_t` and its file descriptors, and will close them and free it when
+/// it is dropped.
+#[derive(Debug)]
+pub struct NativeHandle(NonNull<ffi::native_handle_t>);
+
+impl NativeHandle {
+    /// Creates a new `NativeHandle` with the given file descriptors and integer values.
+    ///
+    /// The `NativeHandle` will take ownership of the file descriptors and close them when it is
+    /// dropped.
+    pub fn new(fds: Vec<OwnedFd>, ints: &[c_int]) -> Option<Self> {
+        let fd_count = fds.len();
+        // SAFETY: native_handle_create doesn't have any safety requirements.
+        let handle = unsafe {
+            ffi::native_handle_create(fd_count.try_into().unwrap(), ints.len().try_into().unwrap())
+        };
+        let handle = NonNull::new(handle)?;
+        for (i, fd) in fds.into_iter().enumerate() {
+            // SAFETY: `handle` must be valid because it was just created, and the array offset is
+            // within the bounds of what we allocated above.
+            unsafe {
+                *(*handle.as_ptr()).data.as_mut_ptr().add(i) = fd.into_raw_fd();
+            }
+        }
+        for (i, value) in ints.iter().enumerate() {
+            // SAFETY: `handle` must be valid because it was just created, and the array offset is
+            // within the bounds of what we allocated above. Note that `data` is uninitialized
+            // until after this so we can't use `slice::from_raw_parts_mut` or similar to create a
+            // reference to it so we use raw pointers arithmetic instead.
+            unsafe {
+                *(*handle.as_ptr()).data.as_mut_ptr().add(fd_count + i) = *value;
+            }
+        }
+        // SAFETY: `handle` must be valid because it was just created.
+        unsafe {
+            ffi::native_handle_set_fdsan_tag(handle.as_ptr());
+        }
+        Some(Self(handle))
+    }
+
+    /// Returns a borrowed view of all the file descriptors in this native handle.
+    pub fn fds(&self) -> Vec<BorrowedFd> {
+        self.data()[..self.fd_count()]
+            .iter()
+            .map(|fd| {
+                // SAFETY: The `native_handle_t` maintains ownership of the file descriptor so it
+                // won't be closed until this `NativeHandle` is destroyed. The `BorrowedFd` will
+                // have a lifetime constrained to that of `&self`, so it can't outlive it.
+                unsafe { BorrowedFd::borrow_raw(*fd) }
+            })
+            .collect()
+    }
+
+    /// Returns the integer values in this native handle.
+    pub fn ints(&self) -> &[c_int] {
+        &self.data()[self.fd_count()..]
+    }
+
+    /// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained.
+    pub fn into_fds(self) -> Vec<OwnedFd> {
+        let fds = self.data()[..self.fd_count()]
+            .iter()
+            .map(|fd| {
+                // SAFETY: The `native_handle_t` has ownership of the file descriptor, and
+                // after this we destroy it without closing the file descriptor so we can take over
+                // ownership of it.
+                unsafe { OwnedFd::from_raw_fd(*fd) }
+            })
+            .collect();
+
+        // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
+        // after this because we own it and forget it.
+        unsafe {
+            assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
+        }
+        // Don't drop self, as that would cause `native_handle_close` to be called and close the
+        // file descriptors.
+        forget(self);
+        fds
+    }
+
+    /// Returns a reference to the underlying `native_handle_t`.
+    fn as_ref(&self) -> &ffi::native_handle_t {
+        // SAFETY: All the ways of creating a `NativeHandle` ensure that the `native_handle_t` is
+        // valid and initialised, and lives as long as the `NativeHandle`. We enforce Rust's
+        // aliasing rules by giving the reference a lifetime matching that of `&self`.
+        unsafe { self.0.as_ref() }
+    }
+
+    /// Returns the number of file descriptors included in the native handle.
+    fn fd_count(&self) -> usize {
+        self.as_ref().numFds.try_into().unwrap()
+    }
+
+    /// Returns the number of integer values included in the native handle.
+    fn int_count(&self) -> usize {
+        self.as_ref().numInts.try_into().unwrap()
+    }
+
+    /// Returns a slice reference for all the used `data` field of the native handle, including both
+    /// file descriptors and integers.
+    fn data(&self) -> &[c_int] {
+        let total_count = self.fd_count() + self.int_count();
+        // SAFETY: The data must have been initialised with this number of elements when the
+        // `NativeHandle` was created.
+        unsafe { self.as_ref().data.as_slice(total_count) }
+    }
+
+    /// Wraps a raw `native_handle_t` pointer, taking ownership of it.
+    ///
+    /// # Safety
+    ///
+    /// `native_handle` must be a valid pointer to a `native_handle_t`, and must not be used
+    ///  anywhere else after calling this method.
+    pub unsafe fn from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self {
+        Self(native_handle)
+    }
+
+    /// Creates a new `NativeHandle` wrapping a clone of the given `native_handle_t` pointer.
+    ///
+    /// Unlike [`from_raw`](Self::from_raw) this doesn't take ownership of the pointer passed in, so
+    /// the caller remains responsible for closing and freeing it.
+    ///
+    /// # Safety
+    ///
+    /// `native_handle` must be a valid pointer to a `native_handle_t`.
+    pub unsafe fn clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self> {
+        // SAFETY: The caller promised that `native_handle` was valid.
+        let cloned = unsafe { ffi::native_handle_clone(native_handle.as_ptr()) };
+        NonNull::new(cloned).map(Self)
+    }
+
+    /// Returns a raw pointer to the wrapped `native_handle_t`.
+    ///
+    /// This is only valid as long as this `NativeHandle` exists, so shouldn't be stored. It mustn't
+    /// be closed or deleted.
+    pub fn as_raw(&self) -> NonNull<ffi::native_handle_t> {
+        self.0
+    }
+
+    /// Turns the `NativeHandle` into a raw `native_handle_t`.
+    ///
+    /// The caller takes ownership of the `native_handle_t` and its file descriptors, so is
+    /// responsible for closing and freeing it.
+    pub fn into_raw(self) -> NonNull<ffi::native_handle_t> {
+        let raw = self.0;
+        forget(self);
+        raw
+    }
+}
+
+impl Clone for NativeHandle {
+    fn clone(&self) -> Self {
+        // SAFETY: Our wrapped `native_handle_t` pointer is always valid.
+        unsafe { Self::clone_from_raw(self.0) }.expect("native_handle_clone returned null")
+    }
+}
+
+impl Drop for NativeHandle {
+    fn drop(&mut self) {
+        // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
+        // after this because we own it and are being dropped.
+        unsafe {
+            assert_eq!(ffi::native_handle_close(self.0.as_ptr()), 0);
+            assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
+        }
+    }
+}
+
+// SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file
+// descriptors, which aren't tied to any particular thread.
+unsafe impl Send for NativeHandle {}
+
+// SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just
+// integers and file descriptors.
+unsafe impl Sync for NativeHandle {}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::fs::File;
+
+    #[test]
+    fn create_empty() {
+        let handle = NativeHandle::new(vec![], &[]).unwrap();
+        assert_eq!(handle.fds().len(), 0);
+        assert_eq!(handle.ints(), &[]);
+    }
+
+    #[test]
+    fn create_with_ints() {
+        let handle = NativeHandle::new(vec![], &[1, 2, 42]).unwrap();
+        assert_eq!(handle.fds().len(), 0);
+        assert_eq!(handle.ints(), &[1, 2, 42]);
+    }
+
+    #[test]
+    fn create_with_fd() {
+        let file = File::open("/dev/null").unwrap();
+        let handle = NativeHandle::new(vec![file.into()], &[]).unwrap();
+        assert_eq!(handle.fds().len(), 1);
+        assert_eq!(handle.ints(), &[]);
+    }
+
+    #[test]
+    fn clone() {
+        let file = File::open("/dev/null").unwrap();
+        let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
+        assert_eq!(original.ints(), &[42]);
+        assert_eq!(original.fds().len(), 1);
+
+        let cloned = original.clone();
+        drop(original);
+
+        assert_eq!(cloned.ints(), &[42]);
+        assert_eq!(cloned.fds().len(), 1);
+
+        drop(cloned);
+    }
+}
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
index dc3f51f..931c311 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -16,7 +16,10 @@
 
 extern crate nativewindow_bindgen as ffi;
 
+mod handle;
 mod surface;
+
+pub use handle::NativeHandle;
 pub use surface::Surface;
 
 pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
@@ -27,11 +30,86 @@
     unstable_api::{status_result, AsNative},
     StatusCode,
 };
-use ffi::{AHardwareBuffer, AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel};
+use ffi::{
+    AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_readFromParcel,
+    AHardwareBuffer_writeToParcel,
+};
 use std::fmt::{self, Debug, Formatter};
 use std::mem::ManuallyDrop;
 use std::ptr::{self, null_mut, NonNull};
 
+/// Wrapper around a C `AHardwareBuffer_Desc`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct HardwareBufferDescription(AHardwareBuffer_Desc);
+
+impl HardwareBufferDescription {
+    /// Creates a new `HardwareBufferDescription` with the given parameters.
+    pub fn new(
+        width: u32,
+        height: u32,
+        layers: u32,
+        format: AHardwareBuffer_Format::Type,
+        usage: AHardwareBuffer_UsageFlags,
+        stride: u32,
+    ) -> Self {
+        Self(AHardwareBuffer_Desc {
+            width,
+            height,
+            layers,
+            format,
+            usage: usage.0,
+            stride,
+            rfu0: 0,
+            rfu1: 0,
+        })
+    }
+
+    /// Returns the width from the buffer description.
+    pub fn width(&self) -> u32 {
+        self.0.width
+    }
+
+    /// Returns the height from the buffer description.
+    pub fn height(&self) -> u32 {
+        self.0.height
+    }
+
+    /// Returns the number from layers from the buffer description.
+    pub fn layers(&self) -> u32 {
+        self.0.layers
+    }
+
+    /// Returns the format from the buffer description.
+    pub fn format(&self) -> AHardwareBuffer_Format::Type {
+        self.0.format
+    }
+
+    /// Returns the usage bitvector from the buffer description.
+    pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
+        AHardwareBuffer_UsageFlags(self.0.usage)
+    }
+
+    /// Returns the stride from the buffer description.
+    pub fn stride(&self) -> u32 {
+        self.0.stride
+    }
+}
+
+impl Default for HardwareBufferDescription {
+    fn default() -> Self {
+        Self(AHardwareBuffer_Desc {
+            width: 0,
+            height: 0,
+            layers: 0,
+            format: 0,
+            usage: 0,
+            stride: 0,
+            rfu0: 0,
+            rfu1: 0,
+        })
+    }
+}
+
 /// Wrapper around an opaque C `AHardwareBuffer`.
 #[derive(PartialEq, Eq)]
 pub struct HardwareBuffer(NonNull<AHardwareBuffer>);
@@ -43,26 +121,9 @@
     /// that the allocation of the given description will never succeed.
     ///
     /// Available since API 29
-    pub fn is_supported(
-        width: u32,
-        height: u32,
-        layers: u32,
-        format: AHardwareBuffer_Format::Type,
-        usage: AHardwareBuffer_UsageFlags,
-        stride: u32,
-    ) -> bool {
-        let buffer_desc = ffi::AHardwareBuffer_Desc {
-            width,
-            height,
-            layers,
-            format,
-            usage: usage.0,
-            stride,
-            rfu0: 0,
-            rfu1: 0,
-        };
-        // SAFETY: *buffer_desc will never be null.
-        let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
+    pub fn is_supported(buffer_description: &HardwareBufferDescription) -> bool {
+        // SAFETY: The pointer comes from a reference so must be valid.
+        let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_description.0) };
 
         status == 1
     }
@@ -74,27 +135,11 @@
     ///
     /// Available since API level 26.
     #[inline]
-    pub fn new(
-        width: u32,
-        height: u32,
-        layers: u32,
-        format: AHardwareBuffer_Format::Type,
-        usage: AHardwareBuffer_UsageFlags,
-    ) -> Option<Self> {
-        let buffer_desc = ffi::AHardwareBuffer_Desc {
-            width,
-            height,
-            layers,
-            format,
-            usage: usage.0,
-            stride: 0,
-            rfu0: 0,
-            rfu1: 0,
-        };
+    pub fn new(buffer_description: &HardwareBufferDescription) -> Option<Self> {
         let mut ptr = ptr::null_mut();
         // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
         // and return a status, but we check it later.
-        let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) };
+        let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_description.0, &mut ptr) };
 
         if status == 0 {
             Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null")))
@@ -103,6 +148,50 @@
         }
     }
 
+    /// Creates a `HardwareBuffer` from a native handle.
+    ///
+    /// The native handle is cloned, so this doesn't take ownership of the original handle passed
+    /// in.
+    pub fn create_from_handle(
+        handle: &NativeHandle,
+        buffer_description: &HardwareBufferDescription,
+    ) -> Result<Self, StatusCode> {
+        let mut buffer = ptr::null_mut();
+        // SAFETY: The caller guarantees that `handle` is valid, and the buffer pointer is valid
+        // because it comes from a reference. The method we pass means that
+        // `AHardwareBuffer_createFromHandle` will clone the handle rather than taking ownership of
+        // it.
+        let status = unsafe {
+            ffi::AHardwareBuffer_createFromHandle(
+                &buffer_description.0,
+                handle.as_raw().as_ptr(),
+                ffi::CreateFromHandleMethod_AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE
+                    .try_into()
+                    .unwrap(),
+                &mut buffer,
+            )
+        };
+        status_result(status)?;
+        Ok(Self(NonNull::new(buffer).expect("Allocated AHardwareBuffer was null")))
+    }
+
+    /// Returns a clone of the native handle of the buffer.
+    ///
+    /// Returns `None` if the operation fails for any reason.
+    pub fn cloned_native_handle(&self) -> Option<NativeHandle> {
+        // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid
+        // because it must have been allocated by `AHardwareBuffer_allocate`,
+        // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet
+        // released it.
+        let native_handle = unsafe { ffi::AHardwareBuffer_getNativeHandle(self.0.as_ptr()) };
+        NonNull::new(native_handle.cast_mut()).and_then(|native_handle| {
+            // SAFETY: `AHardwareBuffer_getNativeHandle` should have returned a valid pointer which
+            // is valid at least as long as the buffer is, and `clone_from_raw` clones it rather
+            // than taking ownership of it so the original `native_handle` isn't stored.
+            unsafe { NativeHandle::clone_from_raw(native_handle) }
+        })
+    }
+
     /// Adopts the given raw pointer and wraps it in a Rust HardwareBuffer.
     ///
     /// # Safety
@@ -155,37 +244,8 @@
         out_id
     }
 
-    /// Get the width of this buffer
-    pub fn width(&self) -> u32 {
-        self.description().width
-    }
-
-    /// Get the height of this buffer
-    pub fn height(&self) -> u32 {
-        self.description().height
-    }
-
-    /// Get the number of layers of this buffer
-    pub fn layers(&self) -> u32 {
-        self.description().layers
-    }
-
-    /// Get the format of this buffer
-    pub fn format(&self) -> AHardwareBuffer_Format::Type {
-        self.description().format
-    }
-
-    /// Get the usage bitvector of this buffer
-    pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
-        AHardwareBuffer_UsageFlags(self.description().usage)
-    }
-
-    /// Get the stride of this buffer
-    pub fn stride(&self) -> u32 {
-        self.description().stride
-    }
-
-    fn description(&self) -> ffi::AHardwareBuffer_Desc {
+    /// Returns the description of this buffer.
+    pub fn description(&self) -> HardwareBufferDescription {
         let mut buffer_desc = ffi::AHardwareBuffer_Desc {
             width: 0,
             height: 0,
@@ -198,7 +258,7 @@
         };
         // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
         unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) };
-        buffer_desc
+        HardwareBufferDescription(buffer_desc)
     }
 }
 
@@ -281,19 +341,27 @@
 
     #[test]
     fn create_valid_buffer_returns_ok() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             512,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        );
+            0,
+        ));
         assert!(buffer.is_some());
     }
 
     #[test]
     fn create_invalid_buffer_returns_err() {
-        let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
+            512,
+            512,
+            1,
+            0,
+            AHardwareBuffer_UsageFlags(0),
+            0,
+        ));
         assert!(buffer.is_none());
     }
 
@@ -319,39 +387,45 @@
         // SAFETY: The pointer must be valid because it was just allocated successfully, and we
         // don't use it after calling this.
         let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) };
-        assert_eq!(buffer.width(), 1024);
+        assert_eq!(buffer.description().width(), 1024);
     }
 
     #[test]
     fn basic_getters() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             1024,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        )
+            0,
+        ))
         .expect("Buffer with some basic parameters was not created successfully");
 
-        assert_eq!(buffer.width(), 1024);
-        assert_eq!(buffer.height(), 512);
-        assert_eq!(buffer.layers(), 1);
-        assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
+        let description = buffer.description();
+        assert_eq!(description.width(), 1024);
+        assert_eq!(description.height(), 512);
+        assert_eq!(description.layers(), 1);
         assert_eq!(
-            buffer.usage(),
+            description.format(),
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
+        );
+        assert_eq!(
+            description.usage(),
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
         );
     }
 
     #[test]
     fn id_getter() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             1024,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        )
+            0,
+        ))
         .expect("Buffer with some basic parameters was not created successfully");
 
         assert_ne!(0, buffer.id());
@@ -359,13 +433,14 @@
 
     #[test]
     fn clone() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             1024,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        )
+            0,
+        ))
         .expect("Buffer with some basic parameters was not created successfully");
         let buffer2 = buffer.clone();
 
@@ -374,13 +449,14 @@
 
     #[test]
     fn into_raw() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             1024,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        )
+            0,
+        ))
         .expect("Buffer with some basic parameters was not created successfully");
         let buffer2 = buffer.clone();
 
@@ -390,4 +466,26 @@
 
         assert_eq!(remade_buffer, buffer2);
     }
+
+    #[test]
+    fn native_handle_and_back() {
+        let buffer_description = HardwareBufferDescription::new(
+            1024,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+            1024,
+        );
+        let buffer = HardwareBuffer::new(&buffer_description)
+            .expect("Buffer with some basic parameters was not created successfully");
+
+        let native_handle =
+            buffer.cloned_native_handle().expect("Failed to get native handle for buffer");
+        let buffer2 = HardwareBuffer::create_from_handle(&native_handle, &buffer_description)
+            .expect("Failed to create buffer from native handle");
+
+        assert_eq!(buffer.description(), buffer_description);
+        assert_eq!(buffer2.description(), buffer_description);
+    }
 }
diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h
index 5689f7d..5046a80 100644
--- a/libs/nativewindow/rust/sys/nativewindow_bindings.h
+++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h
@@ -20,3 +20,5 @@
 #include <android/hdr_metadata.h>
 #include <android/native_window.h>
 #include <android/native_window_aidl.h>
+#include <cutils/native_handle.h>
+#include <vndk/hardware_buffer.h>
diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
index 876f6c8..73a7e95 100644
--- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
+++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
@@ -22,13 +22,14 @@
 
 #[inline]
 fn create_720p_buffer() -> HardwareBuffer {
-    HardwareBuffer::new(
+    HardwareBuffer::new(&HardwareBufferDescription::new(
         1280,
         720,
         1,
         AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
         AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-    )
+        0,
+    ))
     .unwrap()
 }
 
@@ -51,7 +52,7 @@
     // underlying call to AHardwareBuffer_describe.
     c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| {
         b.iter(|| {
-            buffer.width();
+            buffer.description().width();
         })
     });
 }
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index ffb6cdb..b0c6e44 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -388,8 +388,8 @@
         }
     }
 
-    const uint64_t usage = static_cast<uint64_t>(
-            android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage));
+    const uint64_t usage = static_cast<uint64_t>(ANDROID_NATIVE_UNSIGNED_CAST(
+            android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage)));
 
     auto result = getBufferMapper().lock(handle, usage, rect, base::unique_fd{fenceFd});
 
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index b6ab2f5..7b5a27d 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -208,8 +208,10 @@
 status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage,
                                         uint64_t consumerUsage, const Rect& bounds, void** vaddr,
                                         int fenceFd) {
-    return lockAsync(handle, android_convertGralloc1To0Usage(producerUsage, consumerUsage), bounds,
-                     vaddr, fenceFd);
+    return lockAsync(handle,
+                     ANDROID_NATIVE_UNSIGNED_CAST(
+                             android_convertGralloc1To0Usage(producerUsage, consumerUsage)),
+                     bounds, vaddr, fenceFd);
 }
 
 status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle, uint32_t usage,
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index 2af51a7..d3b3a73 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -24,6 +24,10 @@
 cc_defaults {
     name: "libvibrator_defaults",
 
+    defaults: [
+        "aconfig_lib_cc_shared_link.defaults",
+    ],
+
     cflags: [
         "-Wall",
         "-Werror",
@@ -50,9 +54,11 @@
         "libbinder",
         "liblog",
         "libutils",
+        "server_configurable_flags",
     ],
 
     whole_static_libs: [
+        "android.os.vibrator.flags-aconfig-cc",
         "libvibratorutils",
     ],
 
@@ -79,8 +85,14 @@
     vendor_available: true,
     double_loadable: true,
 
+    static_libs: [
+        "android.os.vibrator.flags-aconfig-cc",
+    ],
+
     shared_libs: [
+        "liblog",
         "libutils",
+        "server_configurable_flags",
     ],
 
     srcs: [
@@ -89,6 +101,7 @@
 
     visibility: [
         "//frameworks/native/libs/vibrator",
+        "//frameworks/native/libs/vibrator/tests",
         "//frameworks/av/media/libeffects/hapticgenerator",
     ],
 }
diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp
index 761ac1b..706f3d7 100644
--- a/libs/vibrator/ExternalVibrationUtils.cpp
+++ b/libs/vibrator/ExternalVibrationUtils.cpp
@@ -15,6 +15,9 @@
  */
 #include <cstring>
 
+#include <android_os_vibrator.h>
+
+#include <algorithm>
 #include <math.h>
 
 #include <vibrator/ExternalVibrationUtils.h>
@@ -25,8 +28,9 @@
 static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2.0f / 3.0f;
 static constexpr float HAPTIC_SCALE_LOW_RATIO = 3.0f / 4.0f;
 static constexpr float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;
+static constexpr float SCALE_GAMMA = 0.65f; // Same as VibrationEffect.SCALE_GAMMA
 
-float getHapticScaleGamma(HapticLevel level) {
+float getOldHapticScaleGamma(HapticLevel level) {
     switch (level) {
     case HapticLevel::VERY_LOW:
         return 2.0f;
@@ -41,7 +45,7 @@
     }
 }
 
-float getHapticMaxAmplitudeRatio(HapticLevel level) {
+float getOldHapticMaxAmplitudeRatio(HapticLevel level) {
     switch (level) {
     case HapticLevel::VERY_LOW:
         return HAPTIC_SCALE_VERY_LOW_RATIO;
@@ -56,6 +60,52 @@
     }
 }
 
+/* Same as VibrationScaler.SCALE_LEVEL_* */
+float getHapticScaleFactor(HapticLevel level) {
+    switch (level) {
+        case HapticLevel::VERY_LOW:
+            return 0.6f;
+        case HapticLevel::LOW:
+            return 0.8f;
+        case HapticLevel::HIGH:
+            return 1.2f;
+        case HapticLevel::VERY_HIGH:
+            return 1.4f;
+        default:
+            return 1.0f;
+    }
+}
+
+float applyOldHapticScale(float value, float gamma, float maxAmplitudeRatio) {
+    float sign = value >= 0 ? 1.0 : -1.0;
+    return powf(fabsf(value / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
+                * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign;
+}
+
+float applyNewHapticScale(float value, float scaleFactor) {
+    float scale = powf(scaleFactor, 1.0f / SCALE_GAMMA);
+    if (scaleFactor <= 1) {
+        // Scale down is simply a gamma corrected application of scaleFactor to the intensity.
+        // Scale up requires a different curve to ensure the intensity will not become > 1.
+        return value * scale;
+    }
+
+    float sign = value >= 0 ? 1.0f : -1.0f;
+    float extraScale = powf(scaleFactor, 4.0f - scaleFactor);
+    float x = fabsf(value) * scale * extraScale;
+    float maxX = scale * extraScale; // scaled x for intensity == 1
+
+    float expX = expf(x);
+    float expMaxX = expf(maxX);
+
+    // Using f = tanh as the scale up function so the max value will converge.
+    // a = 1/f(maxX), used to scale f so that a*f(maxX) = 1 (the value will converge to 1).
+    float a = (expMaxX + 1.0f) / (expMaxX - 1.0f);
+    float fx = (expX - 1.0f) / (expX + 1.0f);
+
+    return sign * std::clamp(a * fx, 0.0f, 1.0f);
+}
+
 void applyHapticScale(float* buffer, size_t length, HapticScale scale) {
     if (scale.isScaleMute()) {
         memset(buffer, 0, length * sizeof(float));
@@ -65,15 +115,18 @@
         return;
     }
     HapticLevel hapticLevel = scale.getLevel();
+    float scaleFactor = getHapticScaleFactor(hapticLevel);
     float adaptiveScaleFactor = scale.getAdaptiveScaleFactor();
-    float gamma = getHapticScaleGamma(hapticLevel);
-    float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(hapticLevel);
+    float oldGamma = getOldHapticScaleGamma(hapticLevel);
+    float oldMaxAmplitudeRatio = getOldHapticMaxAmplitudeRatio(hapticLevel);
 
     for (size_t i = 0; i < length; i++) {
         if (hapticLevel != HapticLevel::NONE) {
-            float sign = buffer[i] >= 0 ? 1.0 : -1.0;
-            buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
-                        * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign;
+            if (android_os_vibrator_fix_audio_coupled_haptics_scaling()) {
+                buffer[i] = applyNewHapticScale(buffer[i], scaleFactor);
+            } else {
+                buffer[i] = applyOldHapticScale(buffer[i], oldGamma, oldMaxAmplitudeRatio);
+            }
         }
 
         if (adaptiveScaleFactor != 1.0f) {
diff --git a/libs/vibrator/TEST_MAPPING b/libs/vibrator/TEST_MAPPING
new file mode 100644
index 0000000..d782b43
--- /dev/null
+++ b/libs/vibrator/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "postsubmit": [
+    {
+      "name": "libvibrator_test"
+    }
+  ]
+}
diff --git a/libs/vibrator/tests/Android.bp b/libs/vibrator/tests/Android.bp
new file mode 100644
index 0000000..2921a62
--- /dev/null
+++ b/libs/vibrator/tests/Android.bp
@@ -0,0 +1,53 @@
+// Copyright (C) 2024 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 {
+    default_team: "trendy_team_haptics_framework",
+    // 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: "libvibrator_test",
+    test_suites: ["general-tests"],
+    defaults: [
+        "aconfig_lib_cc_shared_link.defaults",
+    ],
+    srcs: [
+        "ExternalVibrationTest.cpp",
+        "ExternalVibrationUtilsTest.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    static_libs: [
+        "android.os.vibrator.flags-aconfig-cc",
+        "libflagtest",
+        "libgtest",
+        "liblog",
+        "libvibrator",
+        "libvibratorutils",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libutils",
+        "server_configurable_flags",
+    ],
+}
diff --git a/libs/vibrator/tests/ExternalVibrationTest.cpp b/libs/vibrator/tests/ExternalVibrationTest.cpp
new file mode 100644
index 0000000..3141380
--- /dev/null
+++ b/libs/vibrator/tests/ExternalVibrationTest.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 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 <binder/Parcel.h>
+#include <gtest/gtest.h>
+#include <vibrator/ExternalVibration.h>
+
+using namespace android;
+using namespace testing;
+
+using HapticLevel = os::HapticLevel;
+using ScaleLevel = os::ExternalVibrationScale::ScaleLevel;
+
+class TestVibrationController : public os::IExternalVibrationController {
+public:
+    explicit TestVibrationController() {}
+    IBinder *onAsBinder() override { return nullptr; }
+    binder::Status mute(/*out*/ bool *ret) override {
+        *ret = false;
+        return binder::Status::ok();
+    };
+    binder::Status unmute(/*out*/ bool *ret) override {
+        *ret = false;
+        return binder::Status::ok();
+    };
+};
+
+class ExternalVibrationTest : public Test {
+protected:
+    HapticLevel toHapticLevel(ScaleLevel level) {
+        os::ExternalVibrationScale externalVibrationScale;
+        externalVibrationScale.scaleLevel = level;
+        os::HapticScale hapticScale =
+                os::ExternalVibration::externalVibrationScaleToHapticScale(externalVibrationScale);
+        return hapticScale.getLevel();
+    }
+};
+
+TEST_F(ExternalVibrationTest, TestReadAndWriteToParcel) {
+    int32_t uid = 1;
+    std::string pkg("package.name");
+    audio_attributes_t originalAttrs;
+    originalAttrs.content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
+    originalAttrs.usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+    originalAttrs.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
+    originalAttrs.flags = AUDIO_FLAG_BYPASS_MUTE;
+    sp<TestVibrationController> vibrationController = new TestVibrationController();
+    ASSERT_NE(vibrationController, nullptr);
+    sp<os::ExternalVibration> original =
+            new os::ExternalVibration(uid, pkg, originalAttrs, vibrationController);
+    ASSERT_NE(original, nullptr);
+    EXPECT_EQ(original->getUid(), uid);
+    EXPECT_EQ(original->getPackage(), pkg);
+    EXPECT_EQ(original->getAudioAttributes().content_type, originalAttrs.content_type);
+    EXPECT_EQ(original->getAudioAttributes().usage, originalAttrs.usage);
+    EXPECT_EQ(original->getAudioAttributes().source, originalAttrs.source);
+    EXPECT_EQ(original->getAudioAttributes().flags, originalAttrs.flags);
+    EXPECT_EQ(original->getController(), vibrationController);
+    audio_attributes_t defaultAttrs;
+    defaultAttrs.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
+    defaultAttrs.usage = AUDIO_USAGE_UNKNOWN;
+    defaultAttrs.source = AUDIO_SOURCE_DEFAULT;
+    defaultAttrs.flags = AUDIO_FLAG_NONE;
+    sp<os::ExternalVibration> parceled =
+            new os::ExternalVibration(0, std::string(""), defaultAttrs, nullptr);
+    ASSERT_NE(parceled, nullptr);
+    Parcel parcel;
+    original->writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    parceled->readFromParcel(&parcel);
+    EXPECT_EQ(parceled->getUid(), uid);
+    EXPECT_EQ(parceled->getPackage(), pkg);
+    EXPECT_EQ(parceled->getAudioAttributes().content_type, originalAttrs.content_type);
+    EXPECT_EQ(parceled->getAudioAttributes().usage, originalAttrs.usage);
+    EXPECT_EQ(parceled->getAudioAttributes().source, originalAttrs.source);
+    EXPECT_EQ(parceled->getAudioAttributes().flags, originalAttrs.flags);
+    // TestVibrationController does not implement onAsBinder, skip controller parcel in this test.
+}
+
+TEST_F(ExternalVibrationTest, TestExternalVibrationScaleToHapticScale) {
+    os::ExternalVibrationScale externalVibrationScale;
+    externalVibrationScale.scaleLevel = ScaleLevel::SCALE_HIGH;
+    externalVibrationScale.adaptiveHapticsScale = 0.8f;
+    os::HapticScale hapticScale =
+            os::ExternalVibration::externalVibrationScaleToHapticScale(externalVibrationScale);
+    // Check scale factor is forwarded.
+    EXPECT_EQ(hapticScale.getLevel(), HapticLevel::HIGH);
+    EXPECT_EQ(hapticScale.getAdaptiveScaleFactor(), 0.8f);
+    // Check conversion for all levels.
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_MUTE), HapticLevel::MUTE);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_VERY_LOW), HapticLevel::VERY_LOW);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_LOW), HapticLevel::LOW);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_NONE), HapticLevel::NONE);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_HIGH), HapticLevel::HIGH);
+    EXPECT_EQ(toHapticLevel(ScaleLevel::SCALE_VERY_HIGH), HapticLevel::VERY_HIGH);
+}
diff --git a/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp
new file mode 100644
index 0000000..3d8dd9c
--- /dev/null
+++ b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2024 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 <android_os_vibrator.h>
+#include <flag_macros.h>
+#include <gtest/gtest.h>
+#include <vibrator/ExternalVibrationUtils.h>
+
+#include "test_utils.h"
+
+#define FLAG_NS android::os::vibrator
+
+using namespace android;
+using namespace testing;
+
+using HapticScale = os::HapticScale;
+using HapticLevel = os::HapticLevel;
+
+static constexpr float TEST_TOLERANCE = 1e-2f;
+static constexpr size_t TEST_BUFFER_LENGTH = 4;
+static float TEST_BUFFER[TEST_BUFFER_LENGTH] = { 1, -1, 0.5f, -0.2f };
+
+class ExternalVibrationUtilsTest : public Test {
+public:
+    void SetUp() override {
+        std::copy(std::begin(TEST_BUFFER), std::end(TEST_BUFFER), std::begin(mBuffer));
+    }
+
+protected:
+    void scaleBuffer(HapticLevel hapticLevel) {
+        scaleBuffer(HapticScale(hapticLevel), 0 /* limit */);
+    }
+
+    void scaleBuffer(HapticLevel hapticLevel, float adaptiveScaleFactor) {
+        scaleBuffer(hapticLevel, adaptiveScaleFactor, 0 /* limit */);
+    }
+
+    void scaleBuffer(HapticLevel hapticLevel, float adaptiveScaleFactor, float limit) {
+        scaleBuffer(HapticScale(hapticLevel, adaptiveScaleFactor), limit);
+    }
+
+    void scaleBuffer(HapticScale hapticScale, float limit) {
+        std::copy(std::begin(TEST_BUFFER), std::end(TEST_BUFFER), std::begin(mBuffer));
+        os::scaleHapticData(&mBuffer[0], TEST_BUFFER_LENGTH, hapticScale, limit);
+    }
+
+    float mBuffer[TEST_BUFFER_LENGTH];
+};
+
+TEST_F_WITH_FLAGS(
+        ExternalVibrationUtilsTest,
+        TestLegacyScaleMute,
+        REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    float expected[TEST_BUFFER_LENGTH];
+    std::fill(std::begin(expected), std::end(expected), 0);
+
+    scaleBuffer(HapticLevel::MUTE);
+    EXPECT_FLOATS_NEARLY_EQ(expected, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
+
+TEST_F_WITH_FLAGS(
+        ExternalVibrationUtilsTest,
+        TestFixedScaleMute,
+        REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    float expected[TEST_BUFFER_LENGTH];
+    std::fill(std::begin(expected), std::end(expected), 0);
+
+    scaleBuffer(HapticLevel::MUTE);
+    EXPECT_FLOATS_NEARLY_EQ(expected, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
+
+TEST_F_WITH_FLAGS(
+        ExternalVibrationUtilsTest,
+        TestLegacyScaleNone,
+        REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    float expected[TEST_BUFFER_LENGTH];
+    std::copy(std::begin(TEST_BUFFER), std::end(TEST_BUFFER), std::begin(expected));
+
+    scaleBuffer(HapticLevel::NONE);
+    EXPECT_FLOATS_NEARLY_EQ(expected, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
+
+TEST_F_WITH_FLAGS(
+        ExternalVibrationUtilsTest,
+        TestFixedScaleNone,
+        REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    float expected[TEST_BUFFER_LENGTH];
+    std::copy(std::begin(TEST_BUFFER), std::end(TEST_BUFFER), std::begin(expected));
+
+    scaleBuffer(HapticLevel::NONE);
+    EXPECT_FLOATS_NEARLY_EQ(expected, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
+
+TEST_F_WITH_FLAGS(
+    ExternalVibrationUtilsTest,
+    TestLegacyScaleToHapticLevel,
+    REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 1, -1, 0.84f, -0.66f };
+    scaleBuffer(HapticLevel::VERY_HIGH);
+    EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    float expectedHigh[TEST_BUFFER_LENGTH] = { 1, -1, 0.7f, -0.44f };
+    scaleBuffer(HapticLevel::HIGH);
+    EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    float expectedLow[TEST_BUFFER_LENGTH] = { 0.75f, -0.75f, 0.26f, -0.06f };
+    scaleBuffer(HapticLevel::LOW);
+    EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    float expectedVeryLow[TEST_BUFFER_LENGTH] = { 0.66f, -0.66f, 0.16f, -0.02f };
+    scaleBuffer(HapticLevel::VERY_LOW);
+    EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
+
+TEST_F_WITH_FLAGS(
+        ExternalVibrationUtilsTest,
+        TestFixedScaleToHapticLevel,
+        REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 1, -1, 0.79f, -0.39f };
+    scaleBuffer(HapticLevel::VERY_HIGH);
+    EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    float expectedHigh[TEST_BUFFER_LENGTH] = { 1, -1, 0.62f, -0.27f };
+    scaleBuffer(HapticLevel::HIGH);
+    EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    float expectedLow[TEST_BUFFER_LENGTH] = { 0.70f, -0.70f, 0.35f, -0.14f };
+    scaleBuffer(HapticLevel::LOW);
+    EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    float expectedVeryLow[TEST_BUFFER_LENGTH] = { 0.45f, -0.45f, 0.22f, -0.09f };
+    scaleBuffer(HapticLevel::VERY_LOW);
+    EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
+
+TEST_F_WITH_FLAGS(
+        ExternalVibrationUtilsTest,
+        TestAdaptiveScaleFactorAppliedAfterLegacyScale,
+        REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    // Haptic level scale up then adaptive scale down
+    float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -0.13f };
+    scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    // Haptic level scale up then adaptive scale up
+    float expectedHigh[TEST_BUFFER_LENGTH] = { 1.5f, -1.5f, 1.06f, -0.67f };
+    scaleBuffer(HapticLevel::HIGH, 1.5f /* adaptiveScaleFactor */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    // Haptic level scale down then adaptive scale down
+    float expectedLow[TEST_BUFFER_LENGTH] = { 0.45f, -0.45f, 0.15f, -0.04f };
+    scaleBuffer(HapticLevel::LOW, 0.6f /* adaptiveScaleFactor */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    // Haptic level scale down then adaptive scale up
+    float expectedVeryLow[TEST_BUFFER_LENGTH] = { 1.33f, -1.33f, 0.33f, -0.05f };
+    scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
+
+TEST_F_WITH_FLAGS(
+        ExternalVibrationUtilsTest,
+        TestAdaptiveScaleFactorAppliedAfterFixedScale,
+        REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    // Haptic level scale up then adaptive scale down
+    float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -0.07f };
+    scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    // Haptic level scale up then adaptive scale up
+    float expectedHigh[TEST_BUFFER_LENGTH] = { 1.5f, -1.5f, 0.93f, -0.41f };
+    scaleBuffer(HapticLevel::HIGH, 1.5f /* adaptiveScaleFactor */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    // Haptic level scale down then adaptive scale down
+    float expectedLow[TEST_BUFFER_LENGTH] = { 0.42f, -0.42f, 0.21f, -0.08f };
+    scaleBuffer(HapticLevel::LOW, 0.6f /* adaptiveScaleFactor */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    // Haptic level scale down then adaptive scale up
+    float expectedVeryLow[TEST_BUFFER_LENGTH] = { 0.91f, -0.91f, 0.45f, -0.18f };
+    scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
+
+TEST_F_WITH_FLAGS(
+        ExternalVibrationUtilsTest,
+        TestLimitAppliedAfterLegacyScale,
+        REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    // Scaled = { 0.2, -0.2, 0.16f, -0.13f };
+    float expectedClippedVeryHigh[TEST_BUFFER_LENGTH] = { 0.15f, -0.15f, 0.15f, -0.13f };
+    scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 0.15f /* limit */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    // Scaled = { 1, -1, 0.5f, -0.2f };
+    float expectedClippedVeryLow[TEST_BUFFER_LENGTH] = { 0.7f, -0.7f, 0.33f, -0.05f };
+    scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */, 0.7f /* limit */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
+
+TEST_F_WITH_FLAGS(
+        ExternalVibrationUtilsTest,
+        TestLimitAppliedAfterFixedScale,
+        REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling))
+) {
+    // Scaled = { 0.2, -0.2, 0.16f, -0.13f };
+    float expectedClippedVeryHigh[TEST_BUFFER_LENGTH] = { 0.15f, -0.15f, 0.15f, -0.07f };
+    scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 0.15f /* limit */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+
+    // Scaled = { 1, -1, 0.5f, -0.2f };
+    float expectedClippedVeryLow[TEST_BUFFER_LENGTH] = { 0.7f, -0.7f, 0.45f, -0.18f };
+    scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */, 0.7f /* limit */);
+    EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
+}
diff --git a/libs/vibrator/tests/test_utils.h b/libs/vibrator/tests/test_utils.h
new file mode 100644
index 0000000..f491ea1
--- /dev/null
+++ b/libs/vibrator/tests/test_utils.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *            http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBVIBRATOR_TEST_UTILS_H
+#define LIBVIBRATOR_TEST_UTILS_H
+
+#include <gtest/gtest.h>
+
+#if !defined(EXPECT_FLOATS_NEARLY_EQ)
+#define EXPECT_FLOATS_NEARLY_EQ(expected, actual, length, epsilon)              \
+        for (size_t i = 0; i < length; i++) {                                   \
+            EXPECT_NEAR(expected[i], actual[i], epsilon) << " at Index: " << i; \
+        }
+#else
+#error Macro EXPECT_FLOATS_NEARLY_EQ already defined
+#endif
+
+#endif //LIBVIBRATOR_TEST_UTILS_H
diff --git a/opengl/OWNERS b/opengl/OWNERS
index 3d60a1d..645a578 100644
--- a/opengl/OWNERS
+++ b/opengl/OWNERS
@@ -2,5 +2,4 @@
 cnorthrop@google.com
 ianelliott@google.com
 jessehall@google.com
-lpy@google.com
-vantablack@google.com
+tomnom@google.com
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index cf0d46a..18b6c5e 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -116,4 +116,5 @@
         unit_test: true,
     },
     test_suites: ["device-tests"],
+    native_coverage: false,
 }
diff --git a/services/inputflinger/tests/InputTracingTest.cpp b/services/inputflinger/tests/InputTracingTest.cpp
index 2ccd93e..3cc4bdd 100644
--- a/services/inputflinger/tests/InputTracingTest.cpp
+++ b/services/inputflinger/tests/InputTracingTest.cpp
@@ -133,8 +133,8 @@
         mDispatcher->setFocusedWindow(request);
     }
 
-    void tapAndExpect(const std::vector<const sp<FakeWindowHandle>>& windows,
-                      Level inboundTraceLevel, Level dispatchTraceLevel, InputTraceSession& s) {
+    void tapAndExpect(const std::vector<sp<FakeWindowHandle>>& windows, Level inboundTraceLevel,
+                      Level dispatchTraceLevel, InputTraceSession& s) {
         const auto down = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                                   .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(110))
                                   .build();
@@ -156,7 +156,7 @@
         }
     }
 
-    void keypressAndExpect(const std::vector<const sp<FakeWindowHandle>>& windows,
+    void keypressAndExpect(const std::vector<sp<FakeWindowHandle>>& windows,
                            Level inboundTraceLevel, Level dispatchTraceLevel,
                            InputTraceSession& s) {
         const auto down = KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build();
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
index 2c397bd..a54d435 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
@@ -134,8 +134,11 @@
     }
 
     size_t getPresentFenceShift(Period minFramePeriod) const {
-        const bool isTwoVsyncsAhead = targetsVsyncsAhead<2>(minFramePeriod);
         size_t shift = 0;
+        if (minFramePeriod.ns() == 0) {
+            return shift;
+        }
+        const bool isTwoVsyncsAhead = targetsVsyncsAhead<2>(minFramePeriod);
         if (isTwoVsyncsAhead) {
             shift = static_cast<size_t>(expectedFrameDuration().ns() / minFramePeriod.ns());
             if (shift >= mPresentFences.size()) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1aaa128..d4d32aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2334,7 +2334,7 @@
     if (flushTransactions) {
         needsTraversal |= commitMirrorDisplays(vsyncId);
         needsTraversal |= commitCreatedLayers(vsyncId, update.layerCreatedStates);
-        needsTraversal |= applyTransactions(update.transactions, vsyncId);
+        needsTraversal |= applyTransactions(update.transactions);
     }
     outTransactionsAreEmpty = !needsTraversal;
     const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
@@ -2515,7 +2515,7 @@
 
     bool newDataLatched = false;
     ATRACE_NAME("DisplayCallbackAndStatsUpdates");
-    mustComposite |= applyTransactionsLocked(update.transactions, vsyncId);
+    mustComposite |= applyTransactionsLocked(update.transactions);
     traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); });
     const nsecs_t latchTime = systemTime();
     bool unused = false;
@@ -5090,20 +5090,18 @@
 }
 
 // For tests only
-bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) {
+bool SurfaceFlinger::flushTransactionQueues() {
     mTransactionHandler.collectTransactions();
     std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions();
-    return applyTransactions(transactions, vsyncId);
+    return applyTransactions(transactions);
 }
 
-bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
-                                       VsyncId vsyncId) {
+bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) {
     Mutex::Autolock lock(mStateLock);
-    return applyTransactionsLocked(transactions, vsyncId);
+    return applyTransactionsLocked(transactions);
 }
 
-bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions,
-                                             VsyncId vsyncId) {
+bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions) {
     bool needsTraversal = false;
     // Now apply all transactions.
     for (auto& transaction : transactions) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a3534b5..2369043 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -814,9 +814,9 @@
             REQUIRES(mStateLock, kMainThreadContext);
     // Flush pending transactions that were presented after desiredPresentTime.
     // For test only
-    bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext);
+    bool flushTransactionQueues() REQUIRES(kMainThreadContext);
 
-    bool applyTransactions(std::vector<TransactionState>&, VsyncId) REQUIRES(kMainThreadContext);
+    bool applyTransactions(std::vector<TransactionState>&) REQUIRES(kMainThreadContext);
     bool applyAndCommitDisplayTransactionStatesLocked(std::vector<TransactionState>& transactions)
             REQUIRES(kMainThreadContext, mStateLock);
 
@@ -854,7 +854,7 @@
 
     static LatchUnsignaledConfig getLatchUnsignaledConfig();
     bool shouldLatchUnsignaled(const layer_state_t&, size_t numStates, bool firstTransaction) const;
-    bool applyTransactionsLocked(std::vector<TransactionState>& transactions, VsyncId)
+    bool applyTransactionsLocked(std::vector<TransactionState>& transactions)
             REQUIRES(mStateLock, kMainThreadContext);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4197cbd..264f49a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -547,7 +547,7 @@
     }
 
     auto flushTransactionQueues() {
-        return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId));
+        return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues());
     }
 
     auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {