use super::sys::*;
use crate::CoreError;
use libc::c_void;
use std::ffi::CString;
use std::os::raw::c_char;
unsafe extern "C" fn raw_client_on_create(_: *mut c_void) -> *mut c_void {
std::ptr::null_mut()
}
unsafe extern "C" fn raw_client_on_destroy(_: *mut c_void) {}
unsafe extern "C" fn raw_client_on_transact(
_: *mut AIBinder,
_: u32,
_: *const AParcel,
_: *mut AParcel,
) -> BinderStatus {
STATUS_UNKNOWN_TRANSACTION
}
pub struct RawBinderService {
_lib: DlHandle,
vt: Vtable,
_class: *mut AIBinder_Class,
_desc: CString,
service: OwnedBinder,
}
unsafe impl Send for RawBinderService {}
impl RawBinderService {
pub fn open(service_name: &str, descriptor: &str) -> Result<Self, CoreError> {
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 desc =
CString::new(descriptor).map_err(|_| CoreError::binder(-1, "descriptor:nul_byte"))?;
let raw = unsafe { (vt.get_service)(cs.as_ptr()) };
if raw.is_null() {
return Err(CoreError::binder(-1, "AServiceManager_getService:null"));
}
let class = unsafe {
(vt.class_define)(
desc.as_ptr(),
raw_client_on_create,
raw_client_on_destroy,
raw_client_on_transact,
)
};
if class.is_null() {
return Err(CoreError::binder(-1, "AIBinder_Class_define:client"));
}
unsafe { (vt.associate_class)(raw, class) };
let service = OwnedBinder {
ptr: raw,
dec_strong: vt.dec_strong,
};
Ok(Self {
_lib: lib,
vt,
_class: class,
_desc: desc,
service,
})
}
pub fn transact_bool(&self, code: u32) -> Result<bool, CoreError> {
let out = self.raw_noarg(code)?;
let r = ParcelReader::owned(&self.vt, &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(())
}
pub fn transact_bool_arg(&self, code: u32, value: bool) -> Result<(), CoreError> {
self.transact_i32(code, if value { 1 } else { 0 })
}
pub(super) fn raw_noarg(&self, code: u32) -> Result<OwnedParcel, CoreError> {
transact_write(&self.vt, self.service.ptr, code, |_| Ok(()))
}
pub(super) fn vtable(&self) -> &Vtable {
&self.vt
}
}