use crate::session::{FileDescriptorTransportMode, RpcSessionRef};
use binder::{unstable_api::AsNative, SpIBinder};
use binder_rpc_unstable_bindgen::{ARpcServer, ARpcSession};
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
use std::ffi::{c_uint, c_void, CString};
use std::io::{Error, ErrorKind};
use std::os::unix::io::{IntoRawFd, OwnedFd};
pub trait RpcServerFactory:
Fn(&RpcSessionRef, &[u8]) -> Option<SpIBinder> + Send + Sync + 'static
{
}
impl<T> RpcServerFactory for T where
T: Fn(&RpcSessionRef, &[u8]) -> Option<SpIBinder> + Send + Sync + 'static
{
}
foreign_type! {
type CType = binder_rpc_unstable_bindgen::ARpcServer;
fn drop = binder_rpc_unstable_bindgen::ARpcServer_free;
#[derive(Debug)]
pub struct RpcServer;
pub struct RpcServerRef;
}
unsafe impl Send for RpcServer {}
unsafe impl Sync for RpcServer {}
impl RpcServer {
pub fn new_vsock(
mut service: SpIBinder,
cid: u32,
port: u32,
) -> Result<(RpcServer, u32 /* assigned_port */), Error> {
let service = service.as_native_mut();
let mut assigned_port: c_uint = 0;
let server = unsafe {
Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(
service,
cid,
port,
&mut assigned_port,
))?
};
Ok((server, assigned_port as _))
}
pub fn new_bound_socket(
mut service: SpIBinder,
socket_fd: OwnedFd,
) -> Result<RpcServer, Error> {
let service = service.as_native_mut();
unsafe {
Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
service,
socket_fd.into_raw_fd(),
))
}
}
pub fn new_bound_socket_with_factory<F: RpcServerFactory>(
socket_fd: OwnedFd,
factory: F,
) -> Result<RpcServer, Error> {
let userfactory = Box::into_raw(Box::new(factory)).cast::<c_void>();
unsafe {
Self::checked_from_ptr(
binder_rpc_unstable_bindgen::ARpcServer_newBoundSocketWithFactory(
socket_fd.into_raw_fd(),
Some(per_session_factory_wrapper::<F>),
userfactory,
Some(per_session_factory_deleter_wrapper::<F>),
),
)
}
}
pub fn new_unix_domain_bootstrap(
mut service: SpIBinder,
bootstrap_fd: OwnedFd,
) -> Result<RpcServer, Error> {
let service = service.as_native_mut();
unsafe {
Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
service,
bootstrap_fd.into_raw_fd(),
))
}
}
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();
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::other("Failed to start server"));
}
Ok(unsafe { RpcServer::from_ptr(ptr) })
}
}
impl RpcServerRef {
pub fn set_supported_file_descriptor_transport_modes(
&self,
modes: &[FileDescriptorTransportMode],
) {
unsafe {
binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
self.as_ptr(),
modes.as_ptr(),
modes.len(),
)
}
}
pub fn set_max_threads(&self, count: usize) {
unsafe { binder_rpc_unstable_bindgen::ARpcServer_setMaxThreads(self.as_ptr(), count) };
}
pub fn start(&self) {
unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
}
pub fn join(&self) {
unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
}
pub fn shutdown(&self) -> Result<(), Error> {
if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
Ok(())
} else {
Err(Error::from(ErrorKind::UnexpectedEof))
}
}
}
unsafe extern "C" fn per_session_factory_wrapper<F: RpcServerFactory>(
session: *mut ARpcSession,
client_info_data: *const c_void,
client_info_len: usize,
userfactory: *mut c_void,
) -> *mut binder_ndk_sys::AIBinder {
let factory = unsafe { &*(userfactory.cast::<F>()) };
let session_ref = unsafe { RpcSessionRef::from_ptr(session) };
let client_info_slice =
unsafe { std::slice::from_raw_parts(client_info_data.cast::<u8>(), client_info_len) };
match factory(session_ref, client_info_slice) {
Some(binder) => {
let mut binder = std::mem::ManuallyDrop::new(binder);
binder.as_native_mut()
}
None => std::ptr::null_mut(),
}
}
unsafe extern "C" fn per_session_factory_deleter_wrapper<F: RpcServerFactory>(
userfactory: *mut c_void,
) {
let _ = unsafe { Box::from_raw(userfactory.cast::<F>()) };
}