Merge "Snap for 11724015 from 39fb2e6fdaf52da4c8dc29db59b33d7ea64969c3 to sdk-release" into sdk-release
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index a5c0c60..95a05cd 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -790,7 +790,8 @@
 
     if (OK !=
         IInterface::asBinder(cb)->linkToDeath(sp<ServiceManager>::fromExisting(this))) {
-        ALOGE("%s Could not linkToDeath when adding client callback for %s", name.c_str());
+        ALOGE("%s Could not linkToDeath when adding client callback for %s",
+              ctx.toDebugString().c_str(), name.c_str());
         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Couldn't linkToDeath.");
     }
 
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 535ce01..2e46345 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -18,6 +18,7 @@
         "libbinder_ndk_sys",
         "libbinder_rpc_unstable_bindgen_sys",
         "libbinder_rs",
+        "libcfg_if",
         "libdowncast_rs",
         "libforeign_types",
         "liblibc",
diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs
index 163f000..7e5c9dd 100644
--- a/libs/binder/rust/rpcbinder/src/lib.rs
+++ b/libs/binder/rust/rpcbinder/src/lib.rs
@@ -16,10 +16,10 @@
 
 //! API for RPC Binder services.
 
-#[cfg(not(target_os = "trusty"))]
 mod server;
 mod session;
 
+pub use server::RpcServer;
 #[cfg(not(target_os = "trusty"))]
-pub use server::{RpcServer, RpcServerRef};
+pub use server::RpcServerRef;
 pub use session::{FileDescriptorTransportMode, RpcSession, RpcSessionRef};
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index 6fda878..d6bdbd8 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -14,160 +14,12 @@
  * limitations under the License.
  */
 
-use crate::session::FileDescriptorTransportMode;
-use binder::{unstable_api::AsNative, SpIBinder};
-use binder_rpc_unstable_bindgen::ARpcServer;
-use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
-use std::ffi::CString;
-use std::io::{Error, ErrorKind};
-use std::os::unix::io::{IntoRawFd, OwnedFd};
-
-foreign_type! {
-    type CType = binder_rpc_unstable_bindgen::ARpcServer;
-    fn drop = binder_rpc_unstable_bindgen::ARpcServer_free;
-
-    /// A type that represents a foreign instance of RpcServer.
-    #[derive(Debug)]
-    pub struct RpcServer;
-    /// A borrowed RpcServer.
-    pub struct RpcServerRef;
-}
-
-/// SAFETY: The opaque handle can be cloned freely.
-unsafe impl Send for RpcServer {}
-/// SAFETY: The underlying C++ RpcServer class is thread-safe.
-unsafe impl Sync for RpcServer {}
-
-impl RpcServer {
-    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
-    /// vsock port. Only connections from the given CID are accepted.
-    ///
-    // Set `cid` to libc::VMADDR_CID_ANY to accept connections from any client.
-    // Set `cid` to libc::VMADDR_CID_LOCAL to only bind to the local vsock interface.
-    pub fn new_vsock(mut service: SpIBinder, cid: u32, port: u32) -> Result<RpcServer, Error> {
-        let service = service.as_native_mut();
-
-        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
-        // Plus the binder objects are threadsafe.
-        unsafe {
-            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(
-                service, cid, port,
-            ))
-        }
-    }
-
-    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
-    /// socket file descriptor. The socket should be bound to an address before calling this
-    /// function.
-    pub fn new_bound_socket(
-        mut service: SpIBinder,
-        socket_fd: OwnedFd,
-    ) -> Result<RpcServer, Error> {
-        let service = service.as_native_mut();
-
-        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
-        // Plus the binder objects are threadsafe.
-        // The server takes ownership of the socket FD.
-        unsafe {
-            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
-                service,
-                socket_fd.into_raw_fd(),
-            ))
-        }
-    }
-
-    /// Creates a binder RPC server that bootstraps sessions using an existing Unix domain socket
-    /// pair, with a given root IBinder object. Callers should create a pair of SOCK_STREAM Unix
-    /// domain sockets, pass one to the server and the other to the client. Multiple client session
-    /// can be created from the client end of the pair.
-    pub fn new_unix_domain_bootstrap(
-        mut service: SpIBinder,
-        bootstrap_fd: OwnedFd,
-    ) -> Result<RpcServer, Error> {
-        let service = service.as_native_mut();
-
-        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
-        // Plus the binder objects are threadsafe.
-        // The server takes ownership of the bootstrap FD.
-        unsafe {
-            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
-                service,
-                bootstrap_fd.into_raw_fd(),
-            ))
-        }
-    }
-
-    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
-    /// IP address and port.
-    pub fn new_inet(mut service: SpIBinder, address: &str, port: u32) -> Result<RpcServer, Error> {
-        let address = match CString::new(address) {
-            Ok(s) => s,
-            Err(e) => {
-                log::error!("Cannot convert {} to CString. Error: {:?}", address, e);
-                return Err(Error::from(ErrorKind::InvalidInput));
-            }
-        };
-        let service = service.as_native_mut();
-
-        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
-        // Plus the binder objects are threadsafe.
-        unsafe {
-            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInet(
-                service,
-                address.as_ptr(),
-                port,
-            ))
-        }
-    }
-
-    unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> {
-        if ptr.is_null() {
-            return Err(Error::new(ErrorKind::Other, "Failed to start server"));
-        }
-        // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not
-        // null.
-        Ok(unsafe { RpcServer::from_ptr(ptr) })
-    }
-}
-
-impl RpcServerRef {
-    /// Sets the list of file descriptor transport modes supported by this server.
-    pub fn set_supported_file_descriptor_transport_modes(
-        &self,
-        modes: &[FileDescriptorTransportMode],
-    ) {
-        // SAFETY: Does not keep the pointer after returning does, nor does it
-        // read past its boundary. Only passes the 'self' pointer as an opaque handle.
-        unsafe {
-            binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
-                self.as_ptr(),
-                modes.as_ptr(),
-                modes.len(),
-            )
-        }
-    }
-
-    /// Starts a new background thread and calls join(). Returns immediately.
-    pub fn start(&self) {
-        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
-        unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
-    }
-
-    /// Joins the RpcServer thread. The call blocks until the server terminates.
-    /// This must be called from exactly one thread.
-    pub fn join(&self) {
-        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
-        unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
-    }
-
-    /// Shuts down the running RpcServer. Can be called multiple times and from
-    /// multiple threads. Called automatically during drop().
-    pub fn shutdown(&self) -> Result<(), Error> {
-        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
-        if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
-            Ok(())
-        } else {
-            Err(Error::from(ErrorKind::UnexpectedEof))
-        }
+cfg_if::cfg_if! {
+    if #[cfg(target_os = "trusty")] {
+        mod trusty;
+        pub use trusty::*;
+    } else {
+        mod android;
+        pub use android::*;
     }
 }
diff --git a/libs/binder/rust/rpcbinder/src/server/android.rs b/libs/binder/rust/rpcbinder/src/server/android.rs
new file mode 100644
index 0000000..ad0365b
--- /dev/null
+++ b/libs/binder/rust/rpcbinder/src/server/android.rs
@@ -0,0 +1,173 @@
+/*
+ * 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 crate::session::FileDescriptorTransportMode;
+use binder::{unstable_api::AsNative, SpIBinder};
+use binder_rpc_unstable_bindgen::ARpcServer;
+use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
+use std::ffi::CString;
+use std::io::{Error, ErrorKind};
+use std::os::unix::io::{IntoRawFd, OwnedFd};
+
+foreign_type! {
+    type CType = binder_rpc_unstable_bindgen::ARpcServer;
+    fn drop = binder_rpc_unstable_bindgen::ARpcServer_free;
+
+    /// A type that represents a foreign instance of RpcServer.
+    #[derive(Debug)]
+    pub struct RpcServer;
+    /// A borrowed RpcServer.
+    pub struct RpcServerRef;
+}
+
+/// SAFETY: The opaque handle can be cloned freely.
+unsafe impl Send for RpcServer {}
+/// SAFETY: The underlying C++ RpcServer class is thread-safe.
+unsafe impl Sync for RpcServer {}
+
+impl RpcServer {
+    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+    /// vsock port. Only connections from the given CID are accepted.
+    ///
+    // Set `cid` to libc::VMADDR_CID_ANY to accept connections from any client.
+    // Set `cid` to libc::VMADDR_CID_LOCAL to only bind to the local vsock interface.
+    pub fn new_vsock(mut service: SpIBinder, cid: u32, port: u32) -> Result<RpcServer, Error> {
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(
+                service, cid, port,
+            ))
+        }
+    }
+
+    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+    /// socket file descriptor. The socket should be bound to an address before calling this
+    /// function.
+    pub fn new_bound_socket(
+        mut service: SpIBinder,
+        socket_fd: OwnedFd,
+    ) -> Result<RpcServer, Error> {
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        // The server takes ownership of the socket FD.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
+                service,
+                socket_fd.into_raw_fd(),
+            ))
+        }
+    }
+
+    /// Creates a binder RPC server that bootstraps sessions using an existing Unix domain socket
+    /// pair, with a given root IBinder object. Callers should create a pair of SOCK_STREAM Unix
+    /// domain sockets, pass one to the server and the other to the client. Multiple client session
+    /// can be created from the client end of the pair.
+    pub fn new_unix_domain_bootstrap(
+        mut service: SpIBinder,
+        bootstrap_fd: OwnedFd,
+    ) -> Result<RpcServer, Error> {
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        // The server takes ownership of the bootstrap FD.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
+                service,
+                bootstrap_fd.into_raw_fd(),
+            ))
+        }
+    }
+
+    /// Creates a binder RPC server, serving the supplied binder service implementation on the given
+    /// IP address and port.
+    pub fn new_inet(mut service: SpIBinder, address: &str, port: u32) -> Result<RpcServer, Error> {
+        let address = match CString::new(address) {
+            Ok(s) => s,
+            Err(e) => {
+                log::error!("Cannot convert {} to CString. Error: {:?}", address, e);
+                return Err(Error::from(ErrorKind::InvalidInput));
+            }
+        };
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInet(
+                service,
+                address.as_ptr(),
+                port,
+            ))
+        }
+    }
+
+    unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> {
+        if ptr.is_null() {
+            return Err(Error::new(ErrorKind::Other, "Failed to start server"));
+        }
+        // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not
+        // null.
+        Ok(unsafe { RpcServer::from_ptr(ptr) })
+    }
+}
+
+impl RpcServerRef {
+    /// Sets the list of file descriptor transport modes supported by this server.
+    pub fn set_supported_file_descriptor_transport_modes(
+        &self,
+        modes: &[FileDescriptorTransportMode],
+    ) {
+        // SAFETY: Does not keep the pointer after returning does, nor does it
+        // read past its boundary. Only passes the 'self' pointer as an opaque handle.
+        unsafe {
+            binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
+                self.as_ptr(),
+                modes.as_ptr(),
+                modes.len(),
+            )
+        }
+    }
+
+    /// Starts a new background thread and calls join(). Returns immediately.
+    pub fn start(&self) {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
+        unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
+    }
+
+    /// Joins the RpcServer thread. The call blocks until the server terminates.
+    /// This must be called from exactly one thread.
+    pub fn join(&self) {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
+        unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
+    }
+
+    /// Shuts down the running RpcServer. Can be called multiple times and from
+    /// multiple threads. Called automatically during drop().
+    pub fn shutdown(&self) -> Result<(), Error> {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
+        if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
+            Ok(())
+        } else {
+            Err(Error::from(ErrorKind::UnexpectedEof))
+        }
+    }
+}
diff --git a/libs/binder/rust/rpcbinder/src/server/trusty.rs b/libs/binder/rust/rpcbinder/src/server/trusty.rs
new file mode 100644
index 0000000..fe45dec
--- /dev/null
+++ b/libs/binder/rust/rpcbinder/src/server/trusty.rs
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2023 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 binder::{unstable_api::AsNative, SpIBinder};
+use libc::size_t;
+use std::ffi::{c_char, c_void};
+use std::ptr;
+use tipc::{ConnectResult, Handle, MessageResult, PortCfg, TipcError, UnbufferedService, Uuid};
+
+pub trait PerSessionCallback: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {}
+impl<T> PerSessionCallback for T where T: Fn(Uuid) -> Option<SpIBinder> + Send + Sync + 'static {}
+
+pub struct RpcServer {
+    inner: *mut binder_rpc_server_bindgen::ARpcServerTrusty,
+}
+
+/// SAFETY: The opaque handle points to a heap allocation
+/// that should be process-wide and not tied to the current thread.
+unsafe impl Send for RpcServer {}
+/// SAFETY: The underlying C++ RpcServer class is thread-safe.
+unsafe impl Sync for RpcServer {}
+
+impl Drop for RpcServer {
+    fn drop(&mut self) {
+        // SAFETY: `ARpcServerTrusty_delete` is the correct destructor to call
+        // on pointers returned by `ARpcServerTrusty_new`.
+        unsafe {
+            binder_rpc_server_bindgen::ARpcServerTrusty_delete(self.inner);
+        }
+    }
+}
+
+impl RpcServer {
+    /// Allocates a new RpcServer object.
+    pub fn new(service: SpIBinder) -> RpcServer {
+        Self::new_per_session(move |_uuid| Some(service.clone()))
+    }
+
+    /// Allocates a new per-session RpcServer object.
+    ///
+    /// Per-session objects take a closure that gets called once
+    /// for every new connection. The closure gets the UUID of
+    /// the peer and can accept or reject that connection.
+    pub fn new_per_session<F: PerSessionCallback>(f: F) -> RpcServer {
+        // SAFETY: Takes ownership of the returned handle, which has correct refcount.
+        let inner = unsafe {
+            binder_rpc_server_bindgen::ARpcServerTrusty_newPerSession(
+                Some(per_session_callback_wrapper::<F>),
+                Box::into_raw(Box::new(f)).cast(),
+                Some(per_session_callback_deleter::<F>),
+            )
+        };
+        RpcServer { inner }
+    }
+}
+
+unsafe extern "C" fn per_session_callback_wrapper<F: PerSessionCallback>(
+    uuid_ptr: *const c_void,
+    len: size_t,
+    cb_ptr: *mut c_char,
+) -> *mut binder_rpc_server_bindgen::AIBinder {
+    // SAFETY: This callback should only get called while the RpcServer is alive.
+    let cb = unsafe { &mut *cb_ptr.cast::<F>() };
+
+    if len != std::mem::size_of::<Uuid>() {
+        return ptr::null_mut();
+    }
+
+    // SAFETY: On the previous lines we check that we got exactly the right amount of bytes.
+    let uuid = unsafe {
+        let mut uuid = std::mem::MaybeUninit::<Uuid>::uninit();
+        uuid.as_mut_ptr().copy_from(uuid_ptr.cast(), 1);
+        uuid.assume_init()
+    };
+
+    cb(uuid).map_or_else(ptr::null_mut, |b| {
+        // Prevent AIBinder_decStrong from being called before AIBinder_toPlatformBinder.
+        // The per-session callback in C++ is supposed to call AIBinder_decStrong on the
+        // pointer we return here.
+        std::mem::ManuallyDrop::new(b).as_native_mut().cast()
+    })
+}
+
+unsafe extern "C" fn per_session_callback_deleter<F: PerSessionCallback>(cb: *mut c_char) {
+    // SAFETY: shared_ptr calls this to delete the pointer we gave it.
+    // It should only get called once the last shared reference goes away.
+    unsafe {
+        drop(Box::<F>::from_raw(cb.cast()));
+    }
+}
+
+pub struct RpcServerConnection {
+    ctx: *mut c_void,
+}
+
+impl Drop for RpcServerConnection {
+    fn drop(&mut self) {
+        // We do not need to close handle_fd since we do not own it.
+        unsafe {
+            binder_rpc_server_bindgen::ARpcServerTrusty_handleChannelCleanup(self.ctx);
+        }
+    }
+}
+
+impl UnbufferedService for RpcServer {
+    type Connection = RpcServerConnection;
+
+    fn on_connect(
+        &self,
+        _port: &PortCfg,
+        handle: &Handle,
+        peer: &Uuid,
+    ) -> tipc::Result<ConnectResult<Self::Connection>> {
+        let mut conn = RpcServerConnection { ctx: std::ptr::null_mut() };
+        let rc = unsafe {
+            binder_rpc_server_bindgen::ARpcServerTrusty_handleConnect(
+                self.inner,
+                handle.as_raw_fd(),
+                peer.as_ptr().cast(),
+                &mut conn.ctx,
+            )
+        };
+        if rc < 0 {
+            Err(TipcError::from_uapi(rc.into()))
+        } else {
+            Ok(ConnectResult::Accept(conn))
+        }
+    }
+
+    fn on_message(
+        &self,
+        conn: &Self::Connection,
+        _handle: &Handle,
+        buffer: &mut [u8],
+    ) -> tipc::Result<MessageResult> {
+        assert!(buffer.is_empty());
+        let rc = unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleMessage(conn.ctx) };
+        if rc < 0 {
+            Err(TipcError::from_uapi(rc.into()))
+        } else {
+            Ok(MessageResult::MaintainConnection)
+        }
+    }
+
+    fn on_disconnect(&self, conn: &Self::Connection) {
+        unsafe { binder_rpc_server_bindgen::ARpcServerTrusty_handleDisconnect(conn.ctx) };
+    }
+}
diff --git a/libs/binder/trusty/include/binder/ARpcServerTrusty.h b/libs/binder/trusty/include/binder/ARpcServerTrusty.h
new file mode 100644
index 0000000..c82268b
--- /dev/null
+++ b/libs/binder/trusty/include/binder/ARpcServerTrusty.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <lib/tipc/tipc_srv.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct AIBinder;
+struct ARpcServerTrusty;
+
+struct ARpcServerTrusty* ARpcServerTrusty_newPerSession(struct AIBinder* (*)(const void*, size_t,
+                                                                             char*),
+                                                        char*, void (*)(char*));
+void ARpcServerTrusty_delete(struct ARpcServerTrusty*);
+int ARpcServerTrusty_handleConnect(struct ARpcServerTrusty*, handle_t, const struct uuid*, void**);
+int ARpcServerTrusty_handleMessage(void*);
+void ARpcServerTrusty_handleDisconnect(void*);
+void ARpcServerTrusty_handleChannelCleanup(void*);
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index bd1d90f..fe44ea5 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <binder/ARpcServerTrusty.h>
 #include <binder/IBinder.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
@@ -100,6 +101,16 @@
         return rpcServer;
     }
 
+    friend struct ::ARpcServerTrusty;
+    friend ::ARpcServerTrusty* ::ARpcServerTrusty_newPerSession(::AIBinder* (*)(const void*, size_t,
+                                                                                char*),
+                                                                char*, void (*)(char*));
+    friend void ::ARpcServerTrusty_delete(::ARpcServerTrusty*);
+    friend int ::ARpcServerTrusty_handleConnect(::ARpcServerTrusty*, handle_t, const uuid*, void**);
+    friend int ::ARpcServerTrusty_handleMessage(void*);
+    friend void ::ARpcServerTrusty_handleDisconnect(void*);
+    friend void ::ARpcServerTrusty_handleChannelCleanup(void*);
+
     // The Rpc-specific context maintained for every open TIPC channel.
     struct ChannelContext {
         sp<RpcSession> session;
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
new file mode 100644
index 0000000..451383a
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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/binder_libbinder.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcServerTrusty.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcTransportTipcTrusty.h>
+
+using android::RpcServer;
+using android::RpcServerTrusty;
+using android::RpcSession;
+using android::RpcTransportCtxFactoryTipcTrusty;
+using android::sp;
+using android::wp;
+
+struct ARpcServerTrusty {
+    sp<RpcServer> mRpcServer;
+
+    ARpcServerTrusty() = delete;
+    ARpcServerTrusty(sp<RpcServer> rpcServer) : mRpcServer(std::move(rpcServer)) {}
+};
+
+ARpcServerTrusty* ARpcServerTrusty_newPerSession(AIBinder* (*cb)(const void*, size_t, char*),
+                                                 char* cbArg, void (*cbArgDeleter)(char*)) {
+    std::shared_ptr<char> cbArgSp(cbArg, cbArgDeleter);
+
+    auto rpcTransportCtxFactory = RpcTransportCtxFactoryTipcTrusty::make();
+    if (rpcTransportCtxFactory == nullptr) {
+        return nullptr;
+    }
+
+    auto ctx = rpcTransportCtxFactory->newServerCtx();
+    if (ctx == nullptr) {
+        return nullptr;
+    }
+
+    auto rpcServer = RpcServerTrusty::makeRpcServer(std::move(ctx));
+    if (rpcServer == nullptr) {
+        return nullptr;
+    }
+
+    rpcServer->setPerSessionRootObject(
+            [cb, cbArgSp](wp<RpcSession> /*session*/, const void* addrPtr, size_t len) {
+                auto* aib = (*cb)(addrPtr, len, cbArgSp.get());
+                auto b = AIBinder_toPlatformBinder(aib);
+
+                // We have a new sp<IBinder> backed by the same binder, so we can
+                // finally release the AIBinder* from the callback
+                AIBinder_decStrong(aib);
+
+                return b;
+            });
+
+    return new (std::nothrow) ARpcServerTrusty(std::move(rpcServer));
+}
+
+void ARpcServerTrusty_delete(ARpcServerTrusty* rstr) {
+    delete rstr;
+}
+
+int ARpcServerTrusty_handleConnect(ARpcServerTrusty* rstr, handle_t chan, const uuid* peer,
+                                   void** ctx_p) {
+    return RpcServerTrusty::handleConnectInternal(rstr->mRpcServer.get(), chan, peer, ctx_p);
+}
+
+int ARpcServerTrusty_handleMessage(void* ctx) {
+    return RpcServerTrusty::handleMessageInternal(ctx);
+}
+
+void ARpcServerTrusty_handleDisconnect(void* ctx) {
+    RpcServerTrusty::handleDisconnectInternal(ctx);
+}
+
+void ARpcServerTrusty_handleChannelCleanup(void* ctx) {
+    RpcServerTrusty::handleChannelCleanup(ctx);
+}
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/rules.mk b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/rules.mk
new file mode 100644
index 0000000..6def634
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/rules.mk
@@ -0,0 +1,29 @@
+# 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_DIR := $(LOCAL_DIR)/../../../..
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := \
+	$(LOCAL_DIR)/ARpcServerTrusty.cpp \
+
+MODULE_LIBRARY_DEPS += \
+	$(LIBBINDER_DIR)/trusty \
+	$(LIBBINDER_DIR)/trusty/ndk \
+	trusty/user/base/lib/libstdc++-trusty \
+
+include make/library.mk
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/lib.rs b/libs/binder/trusty/rust/binder_rpc_server_bindgen/lib.rs
new file mode 100644
index 0000000..2e8b3ec
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/lib.rs
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+//! Generated Rust bindings to binder_rpc_server
+
+#[allow(bad_style)]
+mod sys {
+    include!(env!("BINDGEN_INC_FILE"));
+}
+
+pub use sys::*;
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/rules.mk b/libs/binder/trusty/rust/binder_rpc_server_bindgen/rules.mk
new file mode 100644
index 0000000..4ee333f
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/rules.mk
@@ -0,0 +1,37 @@
+# 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_DIR := $(LOCAL_DIR)/../../..
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/lib.rs
+
+MODULE_CRATE_NAME := binder_rpc_server_bindgen
+
+MODULE_LIBRARY_DEPS += \
+	$(LOCAL_DIR)/cpp \
+	trusty/user/base/lib/libstdc++-trusty \
+	trusty/user/base/lib/trusty-sys \
+
+MODULE_BINDGEN_SRC_HEADER := \
+	$(LIBBINDER_DIR)/trusty/include/binder/ARpcServerTrusty.h
+
+MODULE_BINDGEN_FLAGS += \
+	--allowlist-type="ARpcServerTrusty" \
+	--allowlist-function="ARpcServerTrusty_.*" \
+
+include make/library.mk
diff --git a/libs/binder/trusty/rust/binder_rpc_test/main.rs b/libs/binder/trusty/rust/binder_rpc_test/main.rs
index a71ce2c..3c1e784 100644
--- a/libs/binder/trusty/rust/binder_rpc_test/main.rs
+++ b/libs/binder/trusty/rust/binder_rpc_test/main.rs
@@ -23,14 +23,21 @@
 test::init!();
 
 const SERVICE_PORT: &str = "com.android.trusty.binderRpcTestService.V1";
+const RUST_SERVICE_PORT: &str = "com.android.trusty.rust.binderRpcTestService.V1";
 
-fn get_service() -> Strong<dyn IBinderRpcTest> {
-    let port = CString::try_new(SERVICE_PORT).expect("Failed to allocate port name");
+fn get_service(port: &str) -> Strong<dyn IBinderRpcTest> {
+    let port = CString::try_new(port).expect("Failed to allocate port name");
     RpcSession::new().setup_trusty_client(port.as_c_str()).expect("Failed to create session")
 }
 
 #[test]
 fn ping() {
-    let srv = get_service();
+    let srv = get_service(SERVICE_PORT);
+    assert_eq!(srv.as_binder().ping_binder(), Ok(()));
+}
+
+#[test]
+fn ping_rust() {
+    let srv = get_service(RUST_SERVICE_PORT);
     assert_eq!(srv.as_binder().ping_binder(), Ok(()));
 }
diff --git a/libs/binder/trusty/rust/binder_rpc_test/service/main.rs b/libs/binder/trusty/rust/binder_rpc_test/service/main.rs
new file mode 100644
index 0000000..b9a86bf
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_test/service/main.rs
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2023 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 binder::{BinderFeatures, Interface, ParcelFileDescriptor, SpIBinder, Status, Strong};
+use binder_rpc_test_aidl::aidl::IBinderRpcCallback::IBinderRpcCallback;
+use binder_rpc_test_aidl::aidl::IBinderRpcSession::IBinderRpcSession;
+use binder_rpc_test_aidl::aidl::IBinderRpcTest::{BnBinderRpcTest, IBinderRpcTest};
+use rpcbinder::RpcServer;
+use std::rc::Rc;
+use tipc::{service_dispatcher, wrap_service, Manager, PortCfg};
+
+const RUST_SERVICE_PORT: &str = "com.android.trusty.rust.binderRpcTestService.V1";
+
+#[derive(Debug, Default)]
+struct TestService;
+
+impl Interface for TestService {}
+
+impl IBinderRpcTest for TestService {
+    fn sendString(&self, _: &str) -> Result<(), Status> {
+        todo!()
+    }
+    fn doubleString(&self, _: &str) -> Result<String, Status> {
+        todo!()
+    }
+    fn getClientPort(&self) -> Result<i32, Status> {
+        todo!()
+    }
+    fn countBinders(&self) -> Result<Vec<i32>, Status> {
+        todo!()
+    }
+    fn getNullBinder(&self) -> Result<SpIBinder, Status> {
+        todo!()
+    }
+    fn pingMe(&self, _: &SpIBinder) -> Result<i32, Status> {
+        todo!()
+    }
+    fn repeatBinder(&self, _: Option<&SpIBinder>) -> Result<Option<SpIBinder>, Status> {
+        todo!()
+    }
+    fn holdBinder(&self, _: Option<&SpIBinder>) -> Result<(), Status> {
+        todo!()
+    }
+    fn getHeldBinder(&self) -> Result<Option<SpIBinder>, Status> {
+        todo!()
+    }
+    fn nestMe(&self, _: &Strong<(dyn IBinderRpcTest + 'static)>, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn alwaysGiveMeTheSameBinder(&self) -> Result<SpIBinder, Status> {
+        todo!()
+    }
+    fn openSession(&self, _: &str) -> Result<Strong<(dyn IBinderRpcSession + 'static)>, Status> {
+        todo!()
+    }
+    fn getNumOpenSessions(&self) -> Result<i32, Status> {
+        todo!()
+    }
+    fn lock(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn unlockInMsAsync(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn lockUnlock(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn sleepMs(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn sleepMsAsync(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn doCallback(
+        &self,
+        _: &Strong<(dyn IBinderRpcCallback + 'static)>,
+        _: bool,
+        _: bool,
+        _: &str,
+    ) -> Result<(), Status> {
+        todo!()
+    }
+    fn doCallbackAsync(
+        &self,
+        _: &Strong<(dyn IBinderRpcCallback + 'static)>,
+        _: bool,
+        _: bool,
+        _: &str,
+    ) -> Result<(), Status> {
+        todo!()
+    }
+    fn die(&self, _: bool) -> Result<(), Status> {
+        todo!()
+    }
+    fn scheduleShutdown(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn useKernelBinderCallingId(&self) -> Result<(), Status> {
+        todo!()
+    }
+    fn echoAsFile(&self, _: &str) -> Result<ParcelFileDescriptor, Status> {
+        todo!()
+    }
+    fn concatFiles(&self, _: &[ParcelFileDescriptor]) -> Result<ParcelFileDescriptor, Status> {
+        todo!()
+    }
+    fn blockingSendFdOneway(&self, _: &ParcelFileDescriptor) -> Result<(), Status> {
+        todo!()
+    }
+    fn blockingRecvFd(&self) -> Result<ParcelFileDescriptor, Status> {
+        todo!()
+    }
+    fn blockingSendIntOneway(&self, _: i32) -> Result<(), Status> {
+        todo!()
+    }
+    fn blockingRecvInt(&self) -> Result<i32, Status> {
+        todo!()
+    }
+}
+
+wrap_service!(TestRpcServer(RpcServer: UnbufferedService));
+
+service_dispatcher! {
+    enum TestDispatcher {
+        TestRpcServer,
+    }
+}
+
+fn main() {
+    let mut dispatcher = TestDispatcher::<1>::new().expect("Could not create test dispatcher");
+
+    let service = BnBinderRpcTest::new_binder(TestService::default(), BinderFeatures::default());
+    let rpc_server =
+        TestRpcServer::new(RpcServer::new_per_session(move |_uuid| Some(service.as_binder())));
+
+    let cfg = PortCfg::new(RUST_SERVICE_PORT)
+        .expect("Could not create port config")
+        .allow_ta_connect()
+        .allow_ns_connect();
+    dispatcher.add_service(Rc::new(rpc_server), cfg).expect("Could not add service to dispatcher");
+
+    Manager::<_, _, 1, 4>::new_with_dispatcher(dispatcher, [])
+        .expect("Could not create service manager")
+        .run_event_loop()
+        .expect("Test event loop failed");
+}
diff --git a/libs/binder/trusty/rust/binder_rpc_test/service/manifest.json b/libs/binder/trusty/rust/binder_rpc_test/service/manifest.json
new file mode 100644
index 0000000..121ba11
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_test/service/manifest.json
@@ -0,0 +1,10 @@
+{
+    "uuid": "4741fc65-8b65-4893-ba55-b182c003c8b7",
+    "app_name": "rust_binder_rpc_test_service",
+    "min_heap": 16384,
+    "min_stack": 16384,
+    "mgmt_flags": {
+        "non_critical_app": true,
+        "restart_on_exit": true
+    }
+}
diff --git a/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk b/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk
new file mode 100644
index 0000000..1ddc382
--- /dev/null
+++ b/libs/binder/trusty/rust/binder_rpc_test/service/rules.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2023 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_DIR := $(LOCAL_DIR)/../../../..
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LOCAL_DIR)/main.rs
+
+MODULE_CRATE_NAME := binder_rpc_test_service
+
+MODULE_LIBRARY_DEPS += \
+	$(LIBBINDER_DIR)/trusty/rust \
+	$(LIBBINDER_DIR)/trusty/rust/rpcbinder \
+	$(LOCAL_DIR)/../aidl \
+	trusty/user/base/lib/tipc/rust \
+
+MANIFEST := $(LOCAL_DIR)/manifest.json
+
+include make/trusted_app.mk
diff --git a/libs/binder/trusty/rust/rpcbinder/rules.mk b/libs/binder/trusty/rust/rpcbinder/rules.mk
index 76f3b94..97f5c03 100644
--- a/libs/binder/trusty/rust/rpcbinder/rules.mk
+++ b/libs/binder/trusty/rust/rpcbinder/rules.mk
@@ -28,6 +28,8 @@
 	$(LIBBINDER_DIR)/trusty/rust \
 	$(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \
 	$(LIBBINDER_DIR)/trusty/rust/binder_rpc_unstable_bindgen \
+	$(LIBBINDER_DIR)/trusty/rust/binder_rpc_server_bindgen \
+	external/rust/crates/cfg-if \
 	external/rust/crates/foreign-types \
 	trusty/user/base/lib/tipc/rust \
 	trusty/user/base/lib/trusty-sys \
diff --git a/libs/binder/trusty/usertests-inc.mk b/libs/binder/trusty/usertests-inc.mk
index 241e668..833d209 100644
--- a/libs/binder/trusty/usertests-inc.mk
+++ b/libs/binder/trusty/usertests-inc.mk
@@ -16,6 +16,7 @@
 TRUSTY_USER_TESTS += \
 	frameworks/native/libs/binder/trusty/binderRpcTest \
 	frameworks/native/libs/binder/trusty/binderRpcTest/service \
+	frameworks/native/libs/binder/trusty/rust/binder_rpc_test/service \
 
 TRUSTY_RUST_USER_TESTS += \
 	frameworks/native/libs/binder/trusty/rust/binder_rpc_test \
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index 92fe4c0..ee95e59 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -77,7 +77,7 @@
                                                                  backendFormat,
                                                                  isOutputBuffer);
     } else {
-        LOG_ALWAYS_FATAL("Unexpected backend %d", backend);
+        LOG_ALWAYS_FATAL("Unexpected backend %u", static_cast<unsigned>(backend));
     }
 
     mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
@@ -145,8 +145,8 @@
                              "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
                              "texType: %i\n\t\tVkImageInfo: success: %i fFormat: %i "
                              "fSampleCount: %u fLevelCount: %u colorType %i",
-                             msg, tex.isValid(), dataspace, tex.width(), tex.height(),
-                             tex.hasMipmaps(), tex.isProtected(),
+                             msg, tex.isValid(), static_cast<int32_t>(dataspace), tex.width(),
+                             tex.height(), tex.hasMipmaps(), tex.isProtected(),
                              static_cast<int>(tex.textureType()), retrievedImageInfo,
                              imageInfo.fFormat, imageInfo.fSampleCount, imageInfo.fLevelCount,
                              colorType);
diff --git a/services/surfaceflinger/tests/OWNERS b/services/surfaceflinger/tests/OWNERS
new file mode 100644
index 0000000..1878326
--- /dev/null
+++ b/services/surfaceflinger/tests/OWNERS
@@ -0,0 +1,5 @@
+per-file HdrSdrRatioOverlay_test.cpp = set noparent
+per-file HdrSdrRatioOverlay_test.cpp = alecmouri@google.com, sallyqi@google.com, jreck@google.com
+
+per-file Layer* = set noparent
+per-file Layer* = pdwilliams@google.com, vishnun@google.com, melodymhsu@google.com
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
index 22b72f9..f2e2c8a 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
@@ -33,24 +33,45 @@
 TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
     using namespace std::chrono_literals;
 
+    std::mutex timerMutex;
+    std::condition_variable cv;
+
     injectDefaultInternalDisplay([](FakeDisplayDeviceInjector&) {});
 
-    mFlinger.scheduler()->replaceTouchTimer(100);
-    std::this_thread::sleep_for(10ms);                  // wait for callback to be triggered
+    std::unique_lock lock(timerMutex);
+    bool didReset = false; // keeps track of what the most recent call was
+
+    auto waitForTimerReset = [&] { cv.wait_for(lock, 100ms, [&] { return didReset; }); };
+    auto waitForTimerExpired = [&] { cv.wait_for(lock, 100ms, [&] { return !didReset; }); };
+
+    // Add extra logic to unblock the test when the timer callbacks get called
+    mFlinger.scheduler()->replaceTouchTimer(10, [&](bool isReset) {
+        {
+            std::unique_lock lock(timerMutex); // guarantee we're waiting on the cv
+            didReset = isReset;
+        }
+        cv.notify_one();                   // wake the cv
+        std::unique_lock lock(timerMutex); // guarantee we finished the cv logic
+    });
+
+    waitForTimerReset();
     EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch
 
-    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
-    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+    waitForTimerExpired();
+    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive()); // Stopping timer deactivates touch
 
     EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::CAMERA_SHOT)));
-    std::this_thread::sleep_for(10ms); // wait for callback to maybe be triggered
-    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
 
-    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
+    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+    // Wait for the timer to start just in case
+    waitForTimerReset();
+    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+    // Wait for the timer to stop, again just in case
+    waitForTimerExpired();
     EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
 
     EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)));
-    std::this_thread::sleep_for(10ms); // wait for callback to be triggered.
+    waitForTimerReset();
     EXPECT_TRUE(mFlinger.scheduler()->isTouchActive());
 }
 
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 2a1b88e..c0255d3 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -136,14 +136,25 @@
         return mLayerHistory.mActiveLayerInfos.size();
     }
 
-    void replaceTouchTimer(int64_t millis) {
+    void replaceTouchTimer(int64_t millis,
+                           std::function<void(bool isReset)>&& testCallback = nullptr) {
         if (mTouchTimer) {
             mTouchTimer.reset();
         }
         mTouchTimer.emplace(
                 "Testable Touch timer", std::chrono::milliseconds(millis),
-                [this] { touchTimerCallback(TimerState::Reset); },
-                [this] { touchTimerCallback(TimerState::Expired); });
+                [this, testCallback] {
+                    touchTimerCallback(TimerState::Reset);
+                    if (testCallback != nullptr) {
+                        testCallback(true);
+                    }
+                },
+                [this, testCallback] {
+                    touchTimerCallback(TimerState::Expired);
+                    if (testCallback != nullptr) {
+                        testCallback(false);
+                    }
+                });
         mTouchTimer->start();
     }