use crate::binder::{
AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode,
};
use crate::error::{status_result, status_t, Result, StatusCode};
use crate::parcel::{BorrowedParcel, Serialize};
use crate::proxy::SpIBinder;
use crate::sys;
use std::convert::TryFrom;
use std::ffi::{c_void, CStr, CString};
use std::fs::File;
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::os::raw::c_char;
use std::os::unix::io::FromRawFd;
use std::slice;
use std::sync::Mutex;
#[repr(C)]
pub struct Binder<T: Remotable> {
ibinder: *mut sys::AIBinder,
rust_object: *mut T,
}
unsafe impl<T: Remotable> Send for Binder<T> {}
unsafe impl<T: Remotable> Sync for Binder<T> {}
impl<T: Remotable> Binder<T> {
pub fn new(rust_object: T) -> Binder<T> {
Self::new_with_stability(rust_object, Stability::default())
}
pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> {
let class = T::get_class();
let rust_object = Box::into_raw(Box::new(rust_object));
let ibinder = unsafe {
sys::AIBinder_new(class.into(), rust_object as *mut c_void)
};
let mut binder = Binder { ibinder, rust_object };
binder.mark_stability(stability);
binder
}
pub fn set_extension(&mut self, extension: &mut SpIBinder) -> Result<()> {
let status = unsafe {
sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut())
};
status_result(status)
}
pub fn get_descriptor() -> &'static str {
T::get_descriptor()
}
fn mark_stability(&mut self, stability: Stability) {
match stability {
Stability::Local => self.mark_local_stability(),
Stability::Vintf => {
unsafe {
sys::AIBinder_markVintfStability(self.as_native_mut());
}
}
}
}
#[cfg(any(vendor_ndk, android_vndk))]
fn mark_local_stability(&mut self) {
unsafe {
sys::AIBinder_markVendorStability(self.as_native_mut());
}
}
#[cfg(not(any(vendor_ndk, android_vndk)))]
fn mark_local_stability(&mut self) {
unsafe {
sys::AIBinder_markSystemStability(self.as_native_mut());
}
}
}
impl<T: Remotable> Interface for Binder<T> {
fn as_binder(&self) -> SpIBinder {
unsafe {
sys::AIBinder_incStrong(self.ibinder);
SpIBinder::from_raw(self.ibinder).unwrap()
}
}
}
impl<T: Remotable> InterfaceClassMethods for Binder<T> {
fn get_descriptor() -> &'static str {
<T as Remotable>::get_descriptor()
}
unsafe extern "C" fn on_transact(
binder: *mut sys::AIBinder,
code: u32,
data: *const sys::AParcel,
reply: *mut sys::AParcel,
) -> status_t {
let res = {
let mut reply = BorrowedParcel::from_raw(reply).unwrap();
let data = BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap();
let object = sys::AIBinder_getUserData(binder);
let binder: &T = &*(object as *const T);
binder.on_transact(code, &data, &mut reply)
};
match res {
Ok(()) => 0i32,
Err(e) => e as i32,
}
}
unsafe extern "C" fn on_destroy(object: *mut c_void) {
drop(Box::from_raw(object as *mut T));
}
unsafe extern "C" fn on_create(args: *mut c_void) -> *mut c_void {
args
}
unsafe extern "C" fn on_dump(
binder: *mut sys::AIBinder,
fd: i32,
args: *mut *const c_char,
num_args: u32,
) -> status_t {
if fd < 0 {
return StatusCode::UNEXPECTED_NULL as status_t;
}
let file = ManuallyDrop::new(File::from_raw_fd(fd));
if args.is_null() && num_args != 0 {
return StatusCode::UNEXPECTED_NULL as status_t;
}
let args = if args.is_null() || num_args == 0 {
vec![]
} else {
slice::from_raw_parts(args, num_args as usize)
.iter()
.map(|s| CStr::from_ptr(*s))
.collect()
};
let object = sys::AIBinder_getUserData(binder);
let binder: &T = &*(object as *const T);
let res = binder.on_dump(&file, &args);
match res {
Ok(()) => 0,
Err(e) => e as status_t,
}
}
}
impl<T: Remotable> Drop for Binder<T> {
fn drop(&mut self) {
unsafe {
sys::AIBinder_decStrong(self.ibinder);
}
}
}
impl<T: Remotable> Deref for Binder<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe {
&*self.rust_object
}
}
}
impl<B: Remotable> Serialize for Binder<B> {
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
parcel.write_binder(Some(&self.as_binder()))
}
}
impl<B: Remotable> TryFrom<SpIBinder> for Binder<B> {
type Error = StatusCode;
fn try_from(mut ibinder: SpIBinder) -> Result<Self> {
let class = B::get_class();
if Some(class) != ibinder.get_class() {
return Err(StatusCode::BAD_TYPE);
}
let userdata = unsafe {
sys::AIBinder_getUserData(ibinder.as_native_mut())
};
if userdata.is_null() {
return Err(StatusCode::UNEXPECTED_NULL);
}
let mut ibinder = ManuallyDrop::new(ibinder);
Ok(Binder { ibinder: ibinder.as_native_mut(), rust_object: userdata as *mut B })
}
}
unsafe impl<B: Remotable> AsNative<sys::AIBinder> for Binder<B> {
fn as_native(&self) -> *const sys::AIBinder {
self.ibinder
}
fn as_native_mut(&mut self) -> *mut sys::AIBinder {
self.ibinder
}
}
pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
let instance = CString::new(identifier).unwrap();
let status = unsafe {
sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr())
};
status_result(status)
}
pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
let instance = CString::new(identifier).unwrap();
let status = unsafe {
sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr())
};
status_result(status)
}
pub fn force_lazy_services_persist(persist: bool) {
unsafe {
sys::AServiceManager_forceLazyServicesPersist(persist)
}
}
#[must_use]
#[derive(Debug)]
pub struct LazyServiceGuard {
_private: (),
}
static GUARD_COUNT: Mutex<u64> = Mutex::new(0);
impl LazyServiceGuard {
pub fn new() -> Self {
let mut count = GUARD_COUNT.lock().unwrap();
*count += 1;
if *count == 1 {
force_lazy_services_persist(true);
}
Self { _private: () }
}
}
impl Drop for LazyServiceGuard {
fn drop(&mut self) {
let mut count = GUARD_COUNT.lock().unwrap();
*count -= 1;
if *count == 0 {
force_lazy_services_persist(false);
}
}
}
impl Clone for LazyServiceGuard {
fn clone(&self) -> Self {
Self::new()
}
}
impl Default for LazyServiceGuard {
fn default() -> Self {
Self::new()
}
}
impl Remotable for () {
fn get_descriptor() -> &'static str {
""
}
fn on_transact(
&self,
_code: TransactionCode,
_data: &BorrowedParcel<'_>,
_reply: &mut BorrowedParcel<'_>,
) -> Result<()> {
Ok(())
}
fn on_dump(&self, _file: &File, _args: &[&CStr]) -> Result<()> {
Ok(())
}
binder_fn_get_class!(Binder::<Self>);
}
impl Interface for () {}
pub fn is_handling_transaction() -> bool {
unsafe {
sys::AIBinder_isHandlingTransaction()
}
}