diff options
Diffstat (limited to 'libs/binder/rust/rpcbinder/src/server/android.rs')
-rw-r--r-- | libs/binder/rust/rpcbinder/src/server/android.rs | 187 |
1 files changed, 187 insertions, 0 deletions
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 0000000000..2ab34472a9 --- /dev/null +++ b/libs/binder/rust/rpcbinder/src/server/android.rs @@ -0,0 +1,187 @@ +/* + * 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(), + ) + } + } + + /// Sets the max number of threads this Server uses for incoming client connections. + /// + /// This must be called before adding a client session. This corresponds + /// to the number of incoming connections to RpcSession objects in the + /// server, which will correspond to the number of outgoing connections + /// in client RpcSession objects. Specifically this is useful for handling + /// client-side callback connections. + /// + /// If this is not specified, this will be a single-threaded server. + pub fn set_max_threads(&self, count: usize) { + // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer. + unsafe { binder_rpc_unstable_bindgen::ARpcServer_setMaxThreads(self.as_ptr(), count) }; + } + + /// 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)) + } + } +} |