use crate::CoreError;
use crate::android::dex;
use super::sys::*;
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
use std::os::raw::{c_char, c_void};
use std::sync::Mutex;
use std::sync::atomic::{AtomicI32, AtomicU32, AtomicUsize, Ordering};
const AM_DESCRIPTOR: &[u8] = b"android.app.IActivityManager\0";
const OBS_DESCRIPTOR: &[u8] = b"android.app.IProcessObserver\0";
const FGPROC_DESCRIPTOR: &[u8] = b"android.app.IForegroundProcessObserver\0";
const ACTIVITY_SERVICE: &[u8] = b"activity\0";
static OBS_FG_CODE: AtomicU32 = AtomicU32::new(0);
static OBS_EVENTFD: Mutex<Option<OwnedFd>> = Mutex::new(None);
fn obs_eventfd_guard() -> std::sync::MutexGuard<'static, Option<OwnedFd>> {
OBS_EVENTFD.lock().unwrap_or_else(|p| p.into_inner())
}
static FGPROC_FG_CODE: AtomicU32 = AtomicU32::new(0);
static FGPROC_PID: AtomicI32 = AtomicI32::new(0);
static FGPROC_EVENTFD: Mutex<Option<OwnedFd>> = Mutex::new(None);
static FGPROC_READ_I32: AtomicUsize = AtomicUsize::new(0);
static FGPROC_IPROC_MODE: AtomicU32 = AtomicU32::new(0);
fn fgproc_eventfd_guard() -> std::sync::MutexGuard<'static, Option<OwnedFd>> {
FGPROC_EVENTFD.lock().unwrap_or_else(|p| p.into_inner())
}
unsafe extern "C" fn am_on_create(_: *mut c_void) -> *mut c_void {
std::ptr::null_mut()
}
unsafe extern "C" fn am_on_destroy(_: *mut c_void) {}
unsafe extern "C" fn am_on_transact(
_: *mut AIBinder,
_: u32,
_: *const AParcel,
_: *mut AParcel,
) -> BinderStatus {
STATUS_UNKNOWN_TRANSACTION
}
unsafe extern "C" fn obs_on_create(_: *mut c_void) -> *mut c_void {
std::ptr::null_mut()
}
unsafe extern "C" fn obs_on_destroy(_: *mut c_void) {}
unsafe extern "C" fn obs_on_transact(
_: *mut AIBinder,
code: u32,
_: *const AParcel,
_: *mut AParcel,
) -> BinderStatus {
if code == OBS_FG_CODE.load(Ordering::Relaxed) {
if let Some(fd) = obs_eventfd_guard().as_ref() {
let val: u64 = 1;
unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
}
}
STATUS_OK
}
unsafe extern "C" fn fgproc_on_create(_: *mut c_void) -> *mut c_void {
std::ptr::null_mut()
}
unsafe extern "C" fn fgproc_on_destroy(_: *mut c_void) {}
unsafe extern "C" fn fgproc_on_transact(
_: *mut AIBinder,
code: u32,
in_parcel: *const AParcel,
_: *mut AParcel,
) -> BinderStatus {
if code != FGPROC_FG_CODE.load(Ordering::Relaxed) {
return STATUS_UNKNOWN_TRANSACTION;
}
let read_addr = FGPROC_READ_I32.load(Ordering::Relaxed);
if read_addr != 0 {
let read_fn: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus =
unsafe { std::mem::transmute(read_addr) };
if FGPROC_IPROC_MODE.load(Ordering::Relaxed) == 1 {
let mut pid: i32 = 0;
let mut _uid: i32 = 0;
let mut fg: i32 = 0;
let mut ok = unsafe { read_fn(in_parcel, &mut pid) } == STATUS_OK;
ok &= unsafe { read_fn(in_parcel, &mut _uid) } == STATUS_OK;
ok &= unsafe { read_fn(in_parcel, &mut fg) } == STATUS_OK;
if ok {
FGPROC_PID.store(pid, Ordering::Relaxed);
if fg == 0 {
return STATUS_OK;
}
} else {
return STATUS_OK;
}
} else {
let mut pid: i32 = 0;
if unsafe { read_fn(in_parcel, &mut pid) } == STATUS_OK {
FGPROC_PID.store(pid, Ordering::Relaxed);
}
}
}
if let Some(fd) = fgproc_eventfd_guard().as_ref() {
let val: u64 = 1;
unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
}
STATUS_OK
}
pub fn last_foreground_pid() -> i32 {
FGPROC_PID.load(Ordering::Relaxed)
}
fn parse_stack_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
r.skip_i32s(5)?;
r.skip_int_array()?;
r.read_first_package_from_names()
}
fn parse_root_task_info_task(r: &ParcelReader<'_>) -> Result<(i32, Option<String>), CoreError> {
let scratch = r.read_i32()?;
if scratch != 0 {
r.skip_i32s(4)?;
}
r.skip_int_array()?; let pkg = r.read_first_package_from_names()?; let bounds_count = r.read_i32()?;
let n = if bounds_count < 0 {
0
} else {
bounds_count as usize
};
for _ in 0..n {
let entry = r.read_i32()?;
if entry != 0 {
r.skip_i32s(4)?;
}
}
r.skip_int_array()?; r.skip_i32s(2)?; r.skip_i32s(1)?; let task_id = r.read_i32()?;
Ok((task_id, pkg))
}
pub struct TxCodes {
pub observer_code: u32,
pub query_code: u32,
pub api_mode: u8, pub fg_code: u32,
}
pub fn resolve_tx_codes() -> Result<TxCodes, CoreError> {
let (obs, query, api, fg) = dex::resolve_tx_codes_from_dex()
.ok_or_else(|| CoreError::binder(-1, "tx_code_resolution:dex_parse_failed"))?;
Ok(TxCodes {
observer_code: obs,
query_code: query,
api_mode: api,
fg_code: fg,
})
}
pub struct ActivityManager {
_lib: DlHandle,
vt: Vtable,
_class: *mut AIBinder_Class,
service: OwnedBinder,
tx_code: u32,
legacy: bool,
}
unsafe impl Send for ActivityManager {}
impl ActivityManager {
fn open_inner(
handle: *mut c_void,
) -> Result<(DlHandle, Vtable, *mut AIBinder_Class, OwnedBinder), CoreError> {
let lib = DlHandle;
let vt = load_vtable(handle)?;
let am_class = unsafe {
(vt.class_define)(
AM_DESCRIPTOR.as_ptr() as *const c_char,
am_on_create,
am_on_destroy,
am_on_transact,
)
};
if am_class.is_null() {
return Err(CoreError::binder(-1, "AIBinder_Class_define:AM"));
}
let raw = unsafe { (vt.get_service)(ACTIVITY_SERVICE.as_ptr() as *const c_char) };
if raw.is_null() {
return Err(CoreError::binder(-1, "AServiceManager_getService:activity"));
}
unsafe { (vt.associate_class)(raw, am_class) };
let service = OwnedBinder {
ptr: raw,
dec_strong: vt.dec_strong,
};
Ok((lib, vt, am_class, service))
}
fn dlopen_libbinder() -> Result<*mut c_void, CoreError> {
use std::os::raw::c_char;
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"));
}
Ok(handle)
}
pub fn open() -> Result<Self, CoreError> {
let handle = Self::dlopen_libbinder()?;
let (lib, vt, class, service) = Self::open_inner(handle)?;
let codes = resolve_tx_codes()?;
let legacy = codes.api_mode == 2;
Ok(Self {
_lib: lib,
vt,
_class: class,
service,
tx_code: codes.query_code,
legacy,
})
}
pub fn open_with_observer() -> Result<(Self, OwnedFd), CoreError> {
let handle = Self::dlopen_libbinder()?;
let (lib, vt, am_class, service) = Self::open_inner(handle)?;
let codes = resolve_tx_codes()?;
let legacy = codes.api_mode == 2;
let owned = unsafe {
let raw = libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC);
if raw < 0 {
return Err(CoreError::sys(*libc::__errno(), "eventfd"));
}
OwnedFd::from_raw_fd(raw)
};
let obs_class = unsafe {
(vt.class_define)(
OBS_DESCRIPTOR.as_ptr() as *const c_char,
obs_on_create,
obs_on_destroy,
obs_on_transact,
)
};
if obs_class.is_null() {
return Err(CoreError::binder(-1, "AIBinder_Class_define:Observer"));
}
let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
if obs_binder.is_null() {
return Err(CoreError::binder(-1, "AIBinder_new:Observer"));
}
unsafe { (vt.associate_class)(obs_binder, obs_class) };
let _ = transact_write(&vt, service.ptr, codes.observer_code, |w| {
w.write_strong_binder(obs_binder)
})?;
let consumer = owned
.try_clone()
.map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:observer"))?;
OBS_FG_CODE.store(codes.fg_code, Ordering::Relaxed);
*obs_eventfd_guard() = Some(owned);
unsafe { (vt.set_thread_pool_max)(0) };
let join_fn = vt.join_thread_pool;
std::thread::spawn(move || unsafe { join_fn() });
let binder = Self {
_lib: lib,
vt,
_class: am_class,
service,
tx_code: codes.query_code,
legacy,
};
Ok((binder, consumer))
}
pub fn open_with_fgproc_observer() -> Result<(Self, OwnedFd), CoreError> {
let handle = Self::dlopen_libbinder()?;
let (lib, vt, am_class, service) = Self::open_inner(handle)?;
let (register_code, fgproc_code, mode, descriptor): (u32, u32, u32, &[u8]) =
match crate::android::dex::resolve_fgproc_codes() {
Some((r, c)) => (r, c, 0, FGPROC_DESCRIPTOR),
None => match crate::android::dex::resolve_fgproc_codes_fallback() {
Some((r, c)) => (r, c, 1, OBS_DESCRIPTOR),
None => {
return Err(CoreError::binder(
-1,
"tx_code_resolution:fgproc_dex_parse_failed",
));
}
},
};
let owned = unsafe {
let raw = libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC);
if raw < 0 {
return Err(CoreError::sys(*libc::__errno(), "eventfd"));
}
OwnedFd::from_raw_fd(raw)
};
let obs_class = unsafe {
(vt.class_define)(
descriptor.as_ptr() as *const c_char,
fgproc_on_create,
fgproc_on_destroy,
fgproc_on_transact,
)
};
if obs_class.is_null() {
return Err(CoreError::binder(
-1,
"AIBinder_Class_define:FGProcessObserver",
));
}
let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
if obs_binder.is_null() {
return Err(CoreError::binder(-1, "AIBinder_new:FGProcessObserver"));
}
unsafe { (vt.associate_class)(obs_binder, obs_class) };
let _ = transact_write(&vt, service.ptr, register_code, |w| {
w.write_strong_binder(obs_binder)
})?;
let consumer = owned.try_clone().map_err(|e| {
CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:fgproc_observer")
})?;
FGPROC_READ_I32.store(vt.read_int32 as usize, Ordering::Relaxed);
FGPROC_IPROC_MODE.store(mode, Ordering::Relaxed);
FGPROC_FG_CODE.store(fgproc_code, Ordering::Relaxed);
FGPROC_PID.store(0, Ordering::Relaxed);
*fgproc_eventfd_guard() = Some(owned);
unsafe { (vt.set_thread_pool_max)(0) };
let join_fn = vt.join_thread_pool;
std::thread::spawn(move || unsafe { join_fn() });
let binder = Self {
_lib: lib,
vt,
_class: am_class,
service,
tx_code: 0,
legacy: false,
};
Ok((binder, consumer))
}
fn do_transact(&self) -> Result<OwnedParcel, CoreError> {
transact_write(&self.vt, self.service.ptr, self.tx_code, |_| Ok(()))
}
pub fn get_focused_task(&self) -> Result<Option<(i32, Option<String>)>, CoreError> {
if self.legacy {
return Ok(None);
}
let out = self.do_transact()?;
let r = ParcelReader {
vt: &self.vt,
parcel: &out,
};
let ex = r.read_i32()?;
if ex != EX_NONE {
return Err(CoreError::binder(ex, "getFocusedTask:exception"));
}
let present = r.read_i32()?;
if present == 0 {
return Ok(None);
}
Ok(Some(parse_root_task_info_task(&r)?))
}
pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
if self.legacy {
let out = self.do_transact()?;
let r = ParcelReader {
vt: &self.vt,
parcel: &out,
};
let ex = r.read_i32()?;
if ex != EX_NONE {
return Err(CoreError::binder(ex, "getFocusedTask:exception"));
}
let present = r.read_i32()?;
if present == 0 {
return Ok(None);
}
return parse_stack_info_body(&r);
}
Ok(self.get_focused_task()?.and_then(|(_, pkg)| pkg))
}
pub fn get_focused_task_id(&self) -> Result<Option<i32>, CoreError> {
Ok(self.get_focused_task()?.map(|(task_id, _)| task_id))
}
}