use super::sys::*;
use crate::CoreError;
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
use std::os::raw::{c_char, c_void};
const TASK_SERVICE: &[u8] = b"activity_task\0";
const ATM_DESCRIPTOR: &[u8] = b"android.app.IActivityTaskManager\0";
const TASK_STACK_DESCRIPTOR: &[u8] = b"android.app.ITaskStackListener\0";
unsafe extern "C" fn atm_on_create(_: *mut c_void) -> *mut c_void {
std::ptr::null_mut()
}
unsafe extern "C" fn atm_on_destroy(_: *mut c_void) {}
unsafe extern "C" fn atm_on_transact(
_: *mut AIBinder,
_: u32,
_: *const AParcel,
_: *mut AParcel,
) -> BinderStatus {
STATUS_OK
}
unsafe extern "C" fn task_stack_on_create(userdata: *mut c_void) -> *mut c_void {
userdata
}
unsafe extern "C" fn task_stack_on_destroy(userdata: *mut c_void) {
if !userdata.is_null() {
unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
}
}
unsafe extern "C" fn task_stack_on_transact(
binder: *mut AIBinder,
_code: u32,
_in_parcel: *const AParcel,
_reply: *mut AParcel,
) -> BinderStatus {
let get_user_data = GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner());
if let Some(get_user_data) = *get_user_data {
let userdata = unsafe { get_user_data(binder) };
if !userdata.is_null() {
let efd = userdata as *mut OwnedFd;
let val: u64 = 1;
unsafe { libc::write((*efd).as_raw_fd(), &val as *const u64 as *const c_void, 8) };
}
}
STATUS_OK
}
pub struct TaskStackListener {
_lib: DlHandle,
vt: Vtable,
service: OwnedBinder,
cb_binder: *mut AIBinder,
_atm_class: *mut AIBinder_Class,
register_code: u32,
unregister_code: u32,
}
unsafe impl Send for TaskStackListener {}
impl TaskStackListener {
pub fn open() -> Result<(Self, OwnedFd), 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 (register_code, unregister_code) = crate::android::dex::resolve_task_stack_codes()
.ok_or_else(|| {
CoreError::binder(-1, "dex:TRANSACTION_registerTaskStackListener not found")
})?;
let service = {
let raw = unsafe { (vt.get_service)(TASK_SERVICE.as_ptr() as *const c_char) };
if raw.is_null() {
return Err(CoreError::binder(
-1,
"AServiceManager_getService:activity_task",
));
}
OwnedBinder {
ptr: raw,
dec_strong: vt.dec_strong,
}
};
let atm_class = unsafe {
(vt.class_define)(
ATM_DESCRIPTOR.as_ptr() as *const c_char,
atm_on_create,
atm_on_destroy,
atm_on_transact,
)
};
if atm_class.is_null() {
return Err(CoreError::binder(
-1,
"AIBinder_Class_define:IActivityTaskManager",
));
}
unsafe { (vt.associate_class)(service.ptr, atm_class) };
let cb_class = unsafe {
(vt.class_define)(
TASK_STACK_DESCRIPTOR.as_ptr() as *const c_char,
task_stack_on_create,
task_stack_on_destroy,
task_stack_on_transact,
)
};
if cb_class.is_null() {
return Err(CoreError::binder(
-1,
"AIBinder_Class_define:ITaskStackListener",
));
}
let owned = unsafe {
let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
if raw < 0 {
return Err(CoreError::sys(*libc::__errno(), "eventfd"));
}
OwnedFd::from_raw_fd(raw)
};
let consumer = owned
.try_clone()
.map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:task_stack"))?;
let userdata = Box::into_raw(Box::new(owned)) as *mut c_void;
let cb_binder = unsafe { (vt.new_binder)(cb_class, userdata) };
if cb_binder.is_null() {
unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
return Err(CoreError::binder(-1, "AIBinder_new:ITaskStackListener"));
}
unsafe { (vt.associate_class)(cb_binder, cb_class) };
*GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner()) = Some(vt.get_user_data);
unsafe { (vt.set_thread_pool_max)(0) };
let join_fn = vt.join_thread_pool;
std::thread::spawn(move || unsafe { join_fn() });
Ok((
Self {
_lib: lib,
vt,
service,
cb_binder,
_atm_class: atm_class,
register_code,
unregister_code,
},
consumer,
))
}
pub fn register(&self) -> Result<(), CoreError> {
let _ = transact_write(&self.vt, self.service.ptr, self.register_code, |w| {
w.write_strong_binder(self.cb_binder)
})?;
Ok(())
}
pub fn unregister(&self) -> Result<(), CoreError> {
let _ = transact_write(&self.vt, self.service.ptr, self.unregister_code, |w| {
w.write_strong_binder(self.cb_binder)
})?;
Ok(())
}
}
impl Drop for TaskStackListener {
fn drop(&mut self) {
let _ = self.unregister();
}
}