Loading libs/binder/rust/rpcbinder/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ rust_library { "libbinder_ndk_sys", "libbinder_rpc_unstable_bindgen_sys", "libbinder_rs", "libcfg_if", "libdowncast_rs", "libforeign_types", "liblibc", Loading libs/binder/rust/rpcbinder/src/lib.rs +2 −2 Original line number Diff line number Diff line Loading @@ -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}; libs/binder/rust/rpcbinder/src/server.rs +7 −155 Original line number Diff line number Diff line Loading @@ -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(()) cfg_if::cfg_if! { if #[cfg(target_os = "trusty")] { mod trusty; pub use trusty::*; } else { Err(Error::from(ErrorKind::UnexpectedEof)) } mod android; pub use android::*; } } libs/binder/rust/rpcbinder/src/server/android.rs 0 → 100644 +173 −0 Original line number Diff line number Diff line /* * 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)) } } } libs/binder/rust/rpcbinder/src/server/trusty.rs 0 → 100644 +161 −0 Original line number Diff line number Diff line /* * 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) }; } } Loading
libs/binder/rust/rpcbinder/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ rust_library { "libbinder_ndk_sys", "libbinder_rpc_unstable_bindgen_sys", "libbinder_rs", "libcfg_if", "libdowncast_rs", "libforeign_types", "liblibc", Loading
libs/binder/rust/rpcbinder/src/lib.rs +2 −2 Original line number Diff line number Diff line Loading @@ -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};
libs/binder/rust/rpcbinder/src/server.rs +7 −155 Original line number Diff line number Diff line Loading @@ -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(()) cfg_if::cfg_if! { if #[cfg(target_os = "trusty")] { mod trusty; pub use trusty::*; } else { Err(Error::from(ErrorKind::UnexpectedEof)) } mod android; pub use android::*; } }
libs/binder/rust/rpcbinder/src/server/android.rs 0 → 100644 +173 −0 Original line number Diff line number Diff line /* * 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)) } } }
libs/binder/rust/rpcbinder/src/server/trusty.rs 0 → 100644 +161 −0 Original line number Diff line number Diff line /* * 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) }; } }