1use crate::CoreError;
26
27#[cfg(target_os = "android")]
32mod imp {
33 use super::*;
34 use crate::dex;
35 use std::os::raw::{c_char, c_void};
36 use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
37
38 const STATUS_OK: i32 = 0;
41 const STATUS_UNKNOWN_TRANSACTION: i32 = -2;
42 const EX_NONE: i32 = 0;
43
44 const AM_DESCRIPTOR: &[u8] = b"android.app.IActivityManager\0";
47 const OBS_DESCRIPTOR: &[u8] = b"android.app.IProcessObserver\0";
48 const ACTIVITY_SERVICE: &[u8] = b"activity\0";
49 const LIBBINDER_PATH: &[u8] = b"/system/lib64/libbinder_ndk.so\0";
50
51 static OBS_FG_CODE: AtomicU32 = AtomicU32::new(0);
60 static OBS_EVENTFD: AtomicI32 = AtomicI32::new(-1);
61
62 type AIBinder = c_void;
65 #[allow(non_camel_case_types)]
66 type AIBinder_Class = c_void;
67 type AParcel = c_void;
68 type BinderStatus = i32;
69 type StringAllocator = unsafe extern "C" fn(*mut c_void, i32, *mut *mut c_char) -> bool;
70
71 unsafe extern "C" fn am_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
75 unsafe extern "C" fn am_on_destroy(_: *mut c_void) {}
76 unsafe extern "C" fn am_on_transact(
77 _: *mut AIBinder, _: u32, _: *const AParcel, _: *mut AParcel,
78 ) -> BinderStatus { STATUS_UNKNOWN_TRANSACTION }
79
80 unsafe extern "C" fn obs_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
82 unsafe extern "C" fn obs_on_destroy(_: *mut c_void) {}
83 unsafe extern "C" fn obs_on_transact(
84 _: *mut AIBinder, code: u32, _: *const AParcel, _: *mut AParcel,
85 ) -> BinderStatus {
86 if code == OBS_FG_CODE.load(Ordering::Relaxed) {
87 let efd = OBS_EVENTFD.load(Ordering::Relaxed);
88 if efd >= 0 {
89 let val: u64 = 1;
90 unsafe { libc::write(efd, &val as *const u64 as *const c_void, 8) };
91 }
92 }
93 STATUS_OK
94 }
95
96 unsafe extern "C" fn string_alloc(
99 cookie: *mut c_void, length: i32, buffer: *mut *mut c_char,
100 ) -> bool {
101 if length < 0 { return true; }
102 let s = unsafe { &mut *(cookie as *mut StringBuf) };
103 s.0.reserve_exact(length as usize + 1);
104 unsafe { s.0.as_mut_vec().resize(length as usize + 1, 0) };
105 unsafe { *buffer = s.0.as_mut_ptr() as *mut c_char };
106 true
107 }
108
109 struct StringBuf(String);
110 impl StringBuf {
111 fn new() -> Self { Self(String::new()) }
112 fn finish(mut self) -> Option<String> {
113 if let Some(pos) = self.0.as_bytes().iter().position(|&b| b == 0) {
114 unsafe { self.0.as_mut_vec().truncate(pos) };
115 }
116 if self.0.is_empty() { None } else { Some(self.0) }
117 }
118 }
119
120 struct Vtable {
123 get_service: unsafe extern "C" fn(*const c_char) -> *mut AIBinder,
124 class_define: unsafe extern "C" fn(
125 *const c_char,
126 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
127 unsafe extern "C" fn(*mut c_void),
128 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
129 ) -> *mut AIBinder_Class,
130 associate_class: unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool,
131 new_binder: unsafe extern "C" fn(*const AIBinder_Class, *mut c_void) -> *mut AIBinder,
132 prepare_transaction: unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus,
133 transact: unsafe extern "C" fn(*mut AIBinder, u32, *mut *mut AParcel, *mut *mut AParcel, u32) -> BinderStatus,
134 dec_strong: unsafe extern "C" fn(*mut AIBinder),
135 parcel_delete: unsafe extern "C" fn(*mut AParcel),
136 read_int32: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus,
137 read_string: unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus,
138 write_strong_binder: unsafe extern "C" fn(*mut AParcel, *mut AIBinder) -> BinderStatus,
139 set_thread_pool_max: unsafe extern "C" fn(u32),
140 join_thread_pool: unsafe extern "C" fn(),
141 #[allow(dead_code)]
143 read_bool: Option<unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus>,
144 }
145
146 struct DlHandle(*mut c_void);
149 unsafe impl Send for DlHandle {}
150 impl Drop for DlHandle {
151 fn drop(&mut self) {
152 }
158 }
159
160 struct OwnedParcel { ptr: *mut AParcel, delete: unsafe extern "C" fn(*mut AParcel) }
161 impl Drop for OwnedParcel {
162 fn drop(&mut self) { if !self.ptr.is_null() { unsafe { (self.delete)(self.ptr) }; } }
163 }
164
165 struct OwnedBinder { ptr: *mut AIBinder, dec_strong: unsafe extern "C" fn(*mut AIBinder) }
166 unsafe impl Send for OwnedBinder {}
167 impl Drop for OwnedBinder {
168 fn drop(&mut self) { if !self.ptr.is_null() { unsafe { (self.dec_strong)(self.ptr) }; } }
169 }
170
171 macro_rules! dlsym_fn {
174 ($handle:expr, $name:literal, $ty:ty) => {{
175 let sym = unsafe {
176 libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char)
177 };
178 if sym.is_null() {
179 return Err(CoreError::binder(-1, concat!("dlsym:", $name)));
180 }
181 unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }
182 }};
183 }
184
185 macro_rules! dlsym_opt {
186 ($handle:expr, $name:literal, $ty:ty) => {{
187 let sym = unsafe {
188 libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char)
189 };
190 if sym.is_null() { None }
191 else { Some(unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }) }
192 }};
193 }
194
195 fn load_vtable(handle: *mut c_void) -> Result<Vtable, CoreError> {
196 Ok(Vtable {
197 get_service: dlsym_fn!(handle, "AServiceManager_getService",
198 unsafe extern "C" fn(*const c_char) -> *mut AIBinder),
199 class_define: dlsym_fn!(handle, "AIBinder_Class_define",
200 unsafe extern "C" fn(
201 *const c_char,
202 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
203 unsafe extern "C" fn(*mut c_void),
204 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
205 ) -> *mut AIBinder_Class),
206 associate_class: dlsym_fn!(handle, "AIBinder_associateClass",
207 unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool),
208 new_binder: dlsym_fn!(handle, "AIBinder_new",
209 unsafe extern "C" fn(*const AIBinder_Class, *mut c_void) -> *mut AIBinder),
210 prepare_transaction: dlsym_fn!(handle, "AIBinder_prepareTransaction",
211 unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus),
212 transact: dlsym_fn!(handle, "AIBinder_transact",
213 unsafe extern "C" fn(*mut AIBinder, u32, *mut *mut AParcel, *mut *mut AParcel, u32) -> BinderStatus),
214 dec_strong: dlsym_fn!(handle, "AIBinder_decStrong",
215 unsafe extern "C" fn(*mut AIBinder)),
216 parcel_delete: dlsym_fn!(handle, "AParcel_delete",
217 unsafe extern "C" fn(*mut AParcel)),
218 read_int32: dlsym_fn!(handle, "AParcel_readInt32",
219 unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus),
220 read_string: dlsym_fn!(handle, "AParcel_readString",
221 unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus),
222 write_strong_binder: dlsym_fn!(handle, "AParcel_writeStrongBinder",
223 unsafe extern "C" fn(*mut AParcel, *mut AIBinder) -> BinderStatus),
224 set_thread_pool_max: dlsym_fn!(handle, "ABinderProcess_setThreadPoolMaxThreadCount",
225 unsafe extern "C" fn(u32)),
226 join_thread_pool: dlsym_fn!(handle, "ABinderProcess_joinThreadPool",
227 unsafe extern "C" fn()),
228 read_bool: dlsym_opt!(handle, "AParcel_readBool",
229 unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus),
230 })
231 }
232
233 struct ParcelReader<'a> { vt: &'a Vtable, parcel: &'a OwnedParcel }
236
237 impl<'a> ParcelReader<'a> {
238 fn read_i32(&self) -> Result<i32, CoreError> {
239 let mut v = 0i32;
240 let s = unsafe { (self.vt.read_int32)(self.parcel.ptr, &mut v) };
241 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readInt32")); }
242 Ok(v)
243 }
244 fn read_string(&self) -> Result<Option<String>, CoreError> {
245 let mut buf = StringBuf::new();
246 let s = unsafe {
247 (self.vt.read_string)(self.parcel.ptr, &mut buf as *mut StringBuf as *mut c_void, string_alloc)
248 };
249 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readString")); }
250 Ok(buf.finish())
251 }
252 fn skip_i32s(&self, n: usize) -> Result<(), CoreError> {
253 for _ in 0..n { self.read_i32()?; }
254 Ok(())
255 }
256 fn skip_int_array(&self) -> Result<(), CoreError> {
257 let count = self.read_i32()?.max(0) as usize;
258 self.skip_i32s(count)
259 }
260 fn read_first_package_from_names(&self) -> Result<Option<String>, CoreError> {
261 let count = self.read_i32()?.max(0) as usize;
262 let mut first: Option<String> = None;
263 for _ in 0..count {
264 let s = self.read_string()?;
265 if first.is_none() {
266 first = s.and_then(|c| c.split('/').next().map(str::to_owned));
267 }
268 }
269 Ok(first)
270 }
271 }
272
273 fn parse_root_task_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
276 let scratch = r.read_i32()?;
277 if scratch != 0 { r.skip_i32s(4)?; }
278 r.skip_int_array()?;
279 r.read_first_package_from_names()
280 }
281
282 fn parse_stack_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
283 r.skip_i32s(5)?;
284 r.skip_int_array()?;
285 r.read_first_package_from_names()
286 }
287
288 pub struct TxCodes {
291 pub observer_code: u32,
292 pub query_code: u32,
293 pub api_mode: u8, pub fg_code: u32,
295 }
296
297 pub fn read_tx_cache(cache_path: &str) -> Option<TxCodes> {
298 let text = std::fs::read_to_string(cache_path).ok()?;
299 let mut parts = text.split_whitespace();
300 let obs: u32 = parts.next()?.parse().ok()?;
301 let query: u32 = parts.next()?.parse().ok()?;
302 let api: u8 = parts.next()?.parse().ok()?;
303 let fg: u32 = parts.next()?.parse().ok()?;
304 if obs == 0 || query == 0 || fg == 0 || (api != 1 && api != 2) { return None; }
306 Some(TxCodes { observer_code: obs, query_code: query, api_mode: api, fg_code: fg })
307 }
308
309 pub fn write_tx_cache(cache_path: &str, codes: &TxCodes) {
310 let _ = std::fs::create_dir_all(
311 std::path::Path::new(cache_path).parent().unwrap_or(std::path::Path::new("/"))
312 );
313 let _ = std::fs::write(
314 cache_path,
315 format!("{} {} {} {}\n", codes.observer_code, codes.query_code, codes.api_mode, codes.fg_code),
316 );
317 }
318
319 pub fn resolve_tx_codes(cache_path: &str) -> Result<TxCodes, CoreError> {
320 if let Some(codes) = read_tx_cache(cache_path) {
321 return Ok(codes);
322 }
323 let (obs, query, api, fg) = dex::resolve_tx_codes_from_dex()
324 .ok_or_else(|| CoreError::binder(-1, "tx_code_resolution:dex_parse_failed"))?;
325 let codes = TxCodes { observer_code: obs, query_code: query, api_mode: api, fg_code: fg };
326 write_tx_cache(cache_path, &codes);
327 Ok(codes)
328 }
329
330 pub struct ActivityManagerBinder {
333 _lib: DlHandle,
334 vt: Vtable,
335 _class: *mut AIBinder_Class,
336 service: OwnedBinder,
337 tx_code: u32,
338 legacy: bool,
339 }
340 unsafe impl Send for ActivityManagerBinder {}
341
342 impl ActivityManagerBinder {
343 fn open_inner(handle: *mut c_void) -> Result<(DlHandle, Vtable, *mut AIBinder_Class, OwnedBinder), CoreError> {
344 let lib = DlHandle(handle);
345 let vt = load_vtable(handle)?;
346
347 let am_class = unsafe {
348 (vt.class_define)(
349 AM_DESCRIPTOR.as_ptr() as *const c_char,
350 am_on_create, am_on_destroy, am_on_transact,
351 )
352 };
353 if am_class.is_null() { return Err(CoreError::binder(-1, "AIBinder_Class_define:AM")); }
354
355 let raw = unsafe { (vt.get_service)(ACTIVITY_SERVICE.as_ptr() as *const c_char) };
356 if raw.is_null() { return Err(CoreError::binder(-1, "AServiceManager_getService:activity")); }
357 unsafe { (vt.associate_class)(raw, am_class) };
358
359 let service = OwnedBinder { ptr: raw, dec_strong: vt.dec_strong };
360 Ok((lib, vt, am_class, service))
361 }
362
363 fn dlopen_libbinder() -> Result<*mut c_void, CoreError> {
364 use std::os::raw::c_char;
365 let handle = unsafe {
366 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
367 };
368 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
369 Ok(handle)
370 }
371
372 pub fn open(cache_path: &str) -> Result<Self, CoreError> {
375 let handle = Self::dlopen_libbinder()?;
376 let (lib, vt, class, service) = Self::open_inner(handle)?;
377 let codes = resolve_tx_codes(cache_path)?;
378 let legacy = codes.api_mode == 2;
379 Ok(Self { _lib: lib, vt, _class: class, service, tx_code: codes.query_code, legacy })
380 }
381
382 pub fn open_with_observer(cache_path: &str) -> Result<(Self, i32), CoreError> {
388 let handle = Self::dlopen_libbinder()?;
389 let (lib, vt, am_class, service) = Self::open_inner(handle)?;
390 let codes = resolve_tx_codes(cache_path)?;
391 let legacy = codes.api_mode == 2;
392
393 let efd = unsafe { libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC) };
395 if efd < 0 { return Err(CoreError::sys(unsafe { *libc::__errno() }, "eventfd")); }
396
397 OBS_FG_CODE.store(codes.fg_code, Ordering::Relaxed);
399 OBS_EVENTFD.store(efd, Ordering::Relaxed);
400
401 let obs_class = unsafe {
403 (vt.class_define)(
404 OBS_DESCRIPTOR.as_ptr() as *const c_char,
405 obs_on_create, obs_on_destroy, obs_on_transact,
406 )
407 };
408 if obs_class.is_null() {
409 unsafe { libc::close(efd) };
410 return Err(CoreError::binder(-1, "AIBinder_Class_define:Observer"));
411 }
412
413 let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
415 if obs_binder.is_null() {
416 unsafe { libc::close(efd) };
417 return Err(CoreError::binder(-1, "AIBinder_new:Observer"));
418 }
419 unsafe { (vt.associate_class)(obs_binder, obs_class) };
420
421 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
423 let s = unsafe { (vt.prepare_transaction)(service.ptr, &mut in_ptr) };
424 if s != STATUS_OK {
425 unsafe { libc::close(efd) };
426 return Err(CoreError::binder(s, "prepareTransaction:registerObserver"));
427 }
428 unsafe { (vt.write_strong_binder)(in_ptr, obs_binder) };
429 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
430 let s = unsafe {
431 (vt.transact)(service.ptr, codes.observer_code, &mut in_ptr, &mut out_ptr, 0)
432 };
433 if !out_ptr.is_null() { unsafe { (vt.parcel_delete)(out_ptr) }; }
434 if s != STATUS_OK {
435 unsafe { libc::close(efd) };
436 return Err(CoreError::binder(s, "transact:registerProcessObserver"));
437 }
438
439 unsafe { (vt.set_thread_pool_max)(0) };
441 let join_fn = vt.join_thread_pool;
442 std::thread::spawn(move || unsafe { join_fn() });
443
444 let binder = Self { _lib: lib, vt, _class: am_class, service, tx_code: codes.query_code, legacy };
445 Ok((binder, efd))
446 }
447
448 fn do_transact(&self) -> Result<OwnedParcel, CoreError> {
449 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
450 let s = unsafe { (self.vt.prepare_transaction)(self.service.ptr, &mut in_ptr) };
451 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_prepareTransaction")); }
452 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
453 let s = unsafe {
454 (self.vt.transact)(self.service.ptr, self.tx_code, &mut in_ptr, &mut out_ptr, 0)
455 };
456 let out = OwnedParcel { ptr: out_ptr, delete: self.vt.parcel_delete };
457 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_transact")); }
458 Ok(out)
459 }
460
461 pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
462 let out = self.do_transact()?;
463 let r = ParcelReader { vt: &self.vt, parcel: &out };
464 let ex = r.read_i32()?;
465 if ex != EX_NONE { return Err(CoreError::binder(ex, "getFocusedTask:exception")); }
466 let present = r.read_i32()?;
467 if present == 0 { return Ok(None); }
468 if self.legacy { parse_stack_info_body(&r) } else { parse_root_task_info_body(&r) }
469 }
470 }
471}
472
473#[cfg(target_os = "android")]
476pub use imp::{ActivityManagerBinder, TxCodes, read_tx_cache, write_tx_cache, resolve_tx_codes};
477
478#[cfg(not(target_os = "android"))]
481pub struct ActivityManagerBinder;
482
483#[cfg(not(target_os = "android"))]
484impl ActivityManagerBinder {
485 pub fn open(_cache_path: &str) -> Result<Self, crate::CoreError> {
486 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
487 }
488 pub fn open_with_observer(_cache_path: &str) -> Result<(Self, i32), crate::CoreError> {
489 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
490 }
491 pub fn get_focused_package(&self) -> Result<Option<String>, crate::CoreError> {
492 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
493 }
494}
495
496#[cfg(not(target_os = "android"))]
497pub struct TxCodes { pub observer_code: u32, pub query_code: u32, pub api_mode: u8, pub fg_code: u32 }
498
499#[cfg(not(target_os = "android"))]
500pub fn read_tx_cache(_: &str) -> Option<TxCodes> { None }
501#[cfg(not(target_os = "android"))]
502pub fn write_tx_cache(_: &str, _: &TxCodes) {}
503#[cfg(not(target_os = "android"))]
504pub fn resolve_tx_codes(_: &str) -> Result<TxCodes, crate::CoreError> {
505 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
506}