use crate::CoreError;
use super::sys::*;
use std::os::raw::c_char;
pub struct RawBinderService {
_lib: DlHandle,
vt: Vtable,
service: OwnedBinder,
}
unsafe impl Send for RawBinderService {}
impl RawBinderService {
pub fn open(service_name: &str) -> Result<Self, CoreError> {
use std::ffi::CString;
let handle = unsafe {
libc::dlopen(
LIBBINDER_PATH.as_ptr() as *const c_char,
libc::RTLD_NOW | libc::RTLD_LOCAL,
)
};
if handle.is_null() {
return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
}
let lib = DlHandle;
let vt = load_vtable(handle)?;
let cs = CString::new(service_name)
.map_err(|_| CoreError::binder(-1, "service_name:nul_byte"))?;
let raw = unsafe { (vt.get_service)(cs.as_ptr()) };
if raw.is_null() {
return Err(CoreError::binder(-1, "AServiceManager_getService:null"));
}
let service = OwnedBinder {
ptr: raw,
dec_strong: vt.dec_strong,
};
Ok(Self {
_lib: lib,
vt,
service,
})
}
pub fn transact_bool(&self, code: u32) -> Result<bool, CoreError> {
let out = self.raw_noarg(code)?;
let r = ParcelReader {
vt: &self.vt,
parcel: &out,
};
let ex = r.read_i32()?;
if ex != EX_NONE {
return Err(CoreError::binder(ex, "transact_bool:exception"));
}
if let Some(rb) = self.vt.read_bool {
let mut v = false;
let s = unsafe { rb(out.ptr as *const AParcel, &mut v) };
if s != STATUS_OK {
return Err(CoreError::binder(s, "AParcel_readBool"));
}
Ok(v)
} else {
Ok(r.read_i32()? != 0)
}
}
pub fn transact_i32(&self, code: u32, arg: i32) -> Result<(), CoreError> {
let _ = transact_write(&self.vt, self.service.ptr, code, |w| w.write_i32(arg))?;
Ok(())
}
fn raw_noarg(&self, code: u32) -> Result<OwnedParcel, CoreError> {
transact_write(&self.vt, self.service.ptr, code, |_| Ok(()))
}
}