use binder::unstable_api::new_spibinder;
use binder::{FromIBinder, SpIBinder, StatusCode, Strong};
use binder_ndk_sys::uid_t;
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
use std::os::fd::RawFd;
use std::os::raw::{c_int, c_void};
pub use binder_rpc_unstable_bindgen::ARpcSession_FileDescriptorTransportMode as FileDescriptorTransportMode;
foreign_type! {
type CType = binder_rpc_unstable_bindgen::ARpcSession;
fn drop = binder_rpc_unstable_bindgen::ARpcSession_free;
#[derive(Debug)]
pub struct RpcSession;
pub struct RpcSessionRef;
}
unsafe impl Send for RpcSession {}
unsafe impl Sync for RpcSession {}
impl RpcSession {
pub fn new() -> RpcSession {
unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) }
}
}
impl Default for RpcSession {
fn default() -> Self {
Self::new()
}
}
impl RpcSessionRef {
pub fn get_client_uid(&self) -> Option<uid_t> {
let mut uid: uid_t = 0;
unsafe {
binder_rpc_unstable_bindgen::ARpcSession_getClientUid(self.as_ptr(), &mut uid)
.then_some(uid)
}
}
pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) {
unsafe {
binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode(
self.as_ptr(),
mode,
)
};
}
pub fn set_max_incoming_threads(&self, threads: usize) {
unsafe {
binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads)
};
}
pub fn set_max_outgoing_connections(&self, connections: usize) {
unsafe {
binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingConnections(
self.as_ptr(),
connections,
)
};
}
#[cfg(not(target_os = "trusty"))]
pub fn setup_vsock_client<T: FromIBinder + ?Sized>(
&self,
cid: u32,
port: u32,
) -> Result<Strong<T>, StatusCode> {
let service = unsafe {
new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupVsockClient(
self.as_ptr(),
cid,
port,
))
};
Self::get_interface(service)
}
#[cfg(not(target_os = "trusty"))]
pub fn setup_unix_domain_client<T: FromIBinder + ?Sized>(
&self,
socket_name: &str,
) -> Result<Strong<T>, StatusCode> {
let socket_name = match std::ffi::CString::new(socket_name) {
Ok(s) => s,
Err(e) => {
log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
return Err(StatusCode::NAME_NOT_FOUND);
}
};
let service = unsafe {
new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainClient(
self.as_ptr(),
socket_name.as_ptr(),
))
};
Self::get_interface(service)
}
#[cfg(not(target_os = "trusty"))]
pub fn setup_unix_domain_bootstrap_client<T: FromIBinder + ?Sized>(
&self,
bootstrap_fd: std::os::fd::BorrowedFd,
) -> Result<Strong<T>, StatusCode> {
use std::os::fd::AsRawFd;
let service = unsafe {
new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainBootstrapClient(
self.as_ptr(),
bootstrap_fd.as_raw_fd(),
))
};
Self::get_interface(service)
}
#[cfg(not(target_os = "trusty"))]
pub fn setup_inet_client<T: FromIBinder + ?Sized>(
&self,
address: &str,
port: u32,
) -> Result<Strong<T>, StatusCode> {
let address = match std::ffi::CString::new(address) {
Ok(s) => s,
Err(e) => {
log::error!("Cannot convert {} to CString. Error: {:?}", address, e);
return Err(StatusCode::BAD_VALUE);
}
};
let service = unsafe {
new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupInet(
self.as_ptr(),
address.as_ptr(),
port,
))
};
Self::get_interface(service)
}
#[cfg(target_os = "trusty")]
pub fn setup_trusty_client<T: FromIBinder + ?Sized>(
&self,
port: &std::ffi::CStr,
) -> Result<Strong<T>, StatusCode> {
self.setup_preconnected_client(|| {
let h = tipc::Handle::connect(port)
.expect("Failed to connect to service port {SERVICE_PORT}");
let fd = h.as_raw_fd();
core::mem::forget(h);
Some(fd)
})
}
pub fn setup_preconnected_client<T: FromIBinder + ?Sized>(
&self,
request_fd: impl FnMut() -> Option<RawFd>,
) -> Result<Strong<T>, StatusCode> {
let request_fd_box: Box<dyn FnMut() -> Option<RawFd>> = Box::new(request_fd);
let param = Box::into_raw(Box::new(request_fd_box)) as *mut c_void;
let service = unsafe {
new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupPreconnectedClient(
self.as_ptr(),
Some(request_fd_wrapper),
param,
Some(param_delete_fd_wrapper),
))
};
Self::get_interface(service)
}
fn get_interface<T: FromIBinder + ?Sized>(
service: Option<SpIBinder>,
) -> Result<Strong<T>, StatusCode> {
if let Some(service) = service {
FromIBinder::try_from(service)
} else {
Err(StatusCode::NAME_NOT_FOUND)
}
}
}
unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
let request_fd_ptr = param as *mut Box<dyn FnMut() -> Option<RawFd>>;
let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() };
request_fd().unwrap_or(-1)
}
unsafe extern "C" fn param_delete_fd_wrapper(param: *mut c_void) {
let request_fd_box = unsafe { Box::from_raw(param as *mut Box<dyn FnMut() -> Option<RawFd>>) };
drop(request_fd_box);
}