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 if !self.0.is_null() { unsafe { libc::dlclose(self.0) }; }
153 }
154 }
155
156 struct OwnedParcel { ptr: *mut AParcel, delete: unsafe extern "C" fn(*mut AParcel) }
157 impl Drop for OwnedParcel {
158 fn drop(&mut self) { if !self.ptr.is_null() { unsafe { (self.delete)(self.ptr) }; } }
159 }
160
161 struct OwnedBinder { ptr: *mut AIBinder, dec_strong: unsafe extern "C" fn(*mut AIBinder) }
162 unsafe impl Send for OwnedBinder {}
163 impl Drop for OwnedBinder {
164 fn drop(&mut self) { if !self.ptr.is_null() { unsafe { (self.dec_strong)(self.ptr) }; } }
165 }
166
167 macro_rules! dlsym_fn {
170 ($handle:expr, $name:literal, $ty:ty) => {{
171 let sym = unsafe {
172 libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char)
173 };
174 if sym.is_null() {
175 return Err(CoreError::binder(-1, concat!("dlsym:", $name)));
176 }
177 unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }
178 }};
179 }
180
181 macro_rules! dlsym_opt {
182 ($handle:expr, $name:literal, $ty:ty) => {{
183 let sym = unsafe {
184 libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char)
185 };
186 if sym.is_null() { None }
187 else { Some(unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }) }
188 }};
189 }
190
191 fn load_vtable(handle: *mut c_void) -> Result<Vtable, CoreError> {
192 Ok(Vtable {
193 get_service: dlsym_fn!(handle, "AServiceManager_getService",
194 unsafe extern "C" fn(*const c_char) -> *mut AIBinder),
195 class_define: dlsym_fn!(handle, "AIBinder_Class_define",
196 unsafe extern "C" fn(
197 *const c_char,
198 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
199 unsafe extern "C" fn(*mut c_void),
200 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
201 ) -> *mut AIBinder_Class),
202 associate_class: dlsym_fn!(handle, "AIBinder_associateClass",
203 unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool),
204 new_binder: dlsym_fn!(handle, "AIBinder_new",
205 unsafe extern "C" fn(*const AIBinder_Class, *mut c_void) -> *mut AIBinder),
206 prepare_transaction: dlsym_fn!(handle, "AIBinder_prepareTransaction",
207 unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus),
208 transact: dlsym_fn!(handle, "AIBinder_transact",
209 unsafe extern "C" fn(*mut AIBinder, u32, *mut *mut AParcel, *mut *mut AParcel, u32) -> BinderStatus),
210 dec_strong: dlsym_fn!(handle, "AIBinder_decStrong",
211 unsafe extern "C" fn(*mut AIBinder)),
212 parcel_delete: dlsym_fn!(handle, "AParcel_delete",
213 unsafe extern "C" fn(*mut AParcel)),
214 read_int32: dlsym_fn!(handle, "AParcel_readInt32",
215 unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus),
216 read_string: dlsym_fn!(handle, "AParcel_readString",
217 unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus),
218 write_strong_binder: dlsym_fn!(handle, "AParcel_writeStrongBinder",
219 unsafe extern "C" fn(*mut AParcel, *mut AIBinder) -> BinderStatus),
220 set_thread_pool_max: dlsym_fn!(handle, "ABinderProcess_setThreadPoolMaxThreadCount",
221 unsafe extern "C" fn(u32)),
222 join_thread_pool: dlsym_fn!(handle, "ABinderProcess_joinThreadPool",
223 unsafe extern "C" fn()),
224 read_bool: dlsym_opt!(handle, "AParcel_readBool",
225 unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus),
226 })
227 }
228
229 struct ParcelReader<'a> { vt: &'a Vtable, parcel: &'a OwnedParcel }
232
233 impl<'a> ParcelReader<'a> {
234 fn read_i32(&self) -> Result<i32, CoreError> {
235 let mut v = 0i32;
236 let s = unsafe { (self.vt.read_int32)(self.parcel.ptr, &mut v) };
237 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readInt32")); }
238 Ok(v)
239 }
240 fn read_string(&self) -> Result<Option<String>, CoreError> {
241 let mut buf = StringBuf::new();
242 let s = unsafe {
243 (self.vt.read_string)(self.parcel.ptr, &mut buf as *mut StringBuf as *mut c_void, string_alloc)
244 };
245 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readString")); }
246 Ok(buf.finish())
247 }
248 fn skip_i32s(&self, n: usize) -> Result<(), CoreError> {
249 for _ in 0..n { self.read_i32()?; }
250 Ok(())
251 }
252 fn skip_int_array(&self) -> Result<(), CoreError> {
253 let count = self.read_i32()?.max(0) as usize;
254 self.skip_i32s(count)
255 }
256 fn read_first_package_from_names(&self) -> Result<Option<String>, CoreError> {
257 let count = self.read_i32()?.max(0) as usize;
258 let mut first: Option<String> = None;
259 for _ in 0..count {
260 let s = self.read_string()?;
261 if first.is_none() {
262 first = s.and_then(|c| c.split('/').next().map(str::to_owned));
263 }
264 }
265 Ok(first)
266 }
267 }
268
269 fn parse_root_task_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
272 let scratch = r.read_i32()?;
273 if scratch != 0 { r.skip_i32s(4)?; }
274 r.skip_int_array()?;
275 r.read_first_package_from_names()
276 }
277
278 fn parse_stack_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
279 r.skip_i32s(5)?;
280 r.skip_int_array()?;
281 r.read_first_package_from_names()
282 }
283
284 pub struct TxCodes {
287 pub observer_code: u32,
288 pub query_code: u32,
289 pub api_mode: u8, pub fg_code: u32,
291 }
292
293 pub fn read_tx_cache(cache_path: &str) -> Option<TxCodes> {
294 let text = std::fs::read_to_string(cache_path).ok()?;
295 let mut parts = text.split_whitespace();
296 let obs: u32 = parts.next()?.parse().ok()?;
297 let query: u32 = parts.next()?.parse().ok()?;
298 let api: u8 = parts.next()?.parse().ok()?;
299 let fg: u32 = parts.next()?.parse().ok()?;
300 if obs == 0 || query == 0 || fg == 0 || (api != 1 && api != 2) { return None; }
302 Some(TxCodes { observer_code: obs, query_code: query, api_mode: api, fg_code: fg })
303 }
304
305 pub fn write_tx_cache(cache_path: &str, codes: &TxCodes) {
306 let _ = std::fs::create_dir_all(
307 std::path::Path::new(cache_path).parent().unwrap_or(std::path::Path::new("/"))
308 );
309 let _ = std::fs::write(
310 cache_path,
311 format!("{} {} {} {}\n", codes.observer_code, codes.query_code, codes.api_mode, codes.fg_code),
312 );
313 }
314
315 pub fn resolve_tx_codes(cache_path: &str) -> Result<TxCodes, CoreError> {
316 if let Some(codes) = read_tx_cache(cache_path) {
317 return Ok(codes);
318 }
319 let (obs, query, api, fg) = dex::resolve_tx_codes_from_dex()
320 .ok_or_else(|| CoreError::binder(-1, "tx_code_resolution:dex_parse_failed"))?;
321 let codes = TxCodes { observer_code: obs, query_code: query, api_mode: api, fg_code: fg };
322 write_tx_cache(cache_path, &codes);
323 Ok(codes)
324 }
325
326 pub struct ActivityManagerBinder {
329 _lib: DlHandle,
330 vt: Vtable,
331 _class: *mut AIBinder_Class,
332 service: OwnedBinder,
333 tx_code: u32,
334 legacy: bool,
335 }
336 unsafe impl Send for ActivityManagerBinder {}
337
338 impl ActivityManagerBinder {
339 fn open_inner(handle: *mut c_void) -> Result<(DlHandle, Vtable, *mut AIBinder_Class, OwnedBinder), CoreError> {
340 let lib = DlHandle(handle);
341 let vt = load_vtable(handle)?;
342
343 let am_class = unsafe {
344 (vt.class_define)(
345 AM_DESCRIPTOR.as_ptr() as *const c_char,
346 am_on_create, am_on_destroy, am_on_transact,
347 )
348 };
349 if am_class.is_null() { return Err(CoreError::binder(-1, "AIBinder_Class_define:AM")); }
350
351 let raw = unsafe { (vt.get_service)(ACTIVITY_SERVICE.as_ptr() as *const c_char) };
352 if raw.is_null() { return Err(CoreError::binder(-1, "AServiceManager_getService:activity")); }
353 unsafe { (vt.associate_class)(raw, am_class) };
354
355 let service = OwnedBinder { ptr: raw, dec_strong: vt.dec_strong };
356 Ok((lib, vt, am_class, service))
357 }
358
359 fn dlopen_libbinder() -> Result<*mut c_void, CoreError> {
360 use std::os::raw::c_char;
361 let handle = unsafe {
362 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
363 };
364 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
365 Ok(handle)
366 }
367
368 pub fn open(cache_path: &str) -> Result<Self, CoreError> {
371 let handle = Self::dlopen_libbinder()?;
372 let (lib, vt, class, service) = Self::open_inner(handle)?;
373 let codes = resolve_tx_codes(cache_path)?;
374 let legacy = codes.api_mode == 2;
375 Ok(Self { _lib: lib, vt, _class: class, service, tx_code: codes.query_code, legacy })
376 }
377
378 pub fn open_with_observer(cache_path: &str) -> Result<(Self, i32), CoreError> {
384 let handle = Self::dlopen_libbinder()?;
385 let (lib, vt, am_class, service) = Self::open_inner(handle)?;
386 let codes = resolve_tx_codes(cache_path)?;
387 let legacy = codes.api_mode == 2;
388
389 let efd = unsafe { libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC) };
391 if efd < 0 { return Err(CoreError::sys(unsafe { *libc::__errno() }, "eventfd")); }
392
393 OBS_FG_CODE.store(codes.fg_code, Ordering::Relaxed);
395 OBS_EVENTFD.store(efd, Ordering::Relaxed);
396
397 let obs_class = unsafe {
399 (vt.class_define)(
400 OBS_DESCRIPTOR.as_ptr() as *const c_char,
401 obs_on_create, obs_on_destroy, obs_on_transact,
402 )
403 };
404 if obs_class.is_null() {
405 unsafe { libc::close(efd) };
406 return Err(CoreError::binder(-1, "AIBinder_Class_define:Observer"));
407 }
408
409 let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
411 if obs_binder.is_null() {
412 unsafe { libc::close(efd) };
413 return Err(CoreError::binder(-1, "AIBinder_new:Observer"));
414 }
415 unsafe { (vt.associate_class)(obs_binder, obs_class) };
416
417 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
419 let s = unsafe { (vt.prepare_transaction)(service.ptr, &mut in_ptr) };
420 if s != STATUS_OK {
421 unsafe { libc::close(efd) };
422 return Err(CoreError::binder(s, "prepareTransaction:registerObserver"));
423 }
424 unsafe { (vt.write_strong_binder)(in_ptr, obs_binder) };
425 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
426 let s = unsafe {
427 (vt.transact)(service.ptr, codes.observer_code, &mut in_ptr, &mut out_ptr, 0)
428 };
429 if !out_ptr.is_null() { unsafe { (vt.parcel_delete)(out_ptr) }; }
430 if s != STATUS_OK {
431 unsafe { libc::close(efd) };
432 return Err(CoreError::binder(s, "transact:registerProcessObserver"));
433 }
434
435 unsafe { (vt.set_thread_pool_max)(0) };
437 let join_fn = vt.join_thread_pool;
438 std::thread::spawn(move || unsafe { join_fn() });
439
440 let binder = Self { _lib: lib, vt, _class: am_class, service, tx_code: codes.query_code, legacy };
441 Ok((binder, efd))
442 }
443
444 fn do_transact(&self) -> Result<OwnedParcel, CoreError> {
445 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
446 let s = unsafe { (self.vt.prepare_transaction)(self.service.ptr, &mut in_ptr) };
447 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_prepareTransaction")); }
448 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
449 let s = unsafe {
450 (self.vt.transact)(self.service.ptr, self.tx_code, &mut in_ptr, &mut out_ptr, 0)
451 };
452 let out = OwnedParcel { ptr: out_ptr, delete: self.vt.parcel_delete };
453 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_transact")); }
454 Ok(out)
455 }
456
457 pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
458 let out = self.do_transact()?;
459 let r = ParcelReader { vt: &self.vt, parcel: &out };
460 let ex = r.read_i32()?;
461 if ex != EX_NONE { return Err(CoreError::binder(ex, "getFocusedTask:exception")); }
462 let present = r.read_i32()?;
463 if present == 0 { return Ok(None); }
464 if self.legacy { parse_stack_info_body(&r) } else { parse_root_task_info_body(&r) }
465 }
466 }
467}
468
469#[cfg(target_os = "android")]
472pub use imp::{ActivityManagerBinder, TxCodes, read_tx_cache, write_tx_cache, resolve_tx_codes};
473
474#[cfg(not(target_os = "android"))]
477pub struct ActivityManagerBinder;
478
479#[cfg(not(target_os = "android"))]
480impl ActivityManagerBinder {
481 pub fn open(_cache_path: &str) -> Result<Self, crate::CoreError> {
482 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
483 }
484 pub fn open_with_observer(_cache_path: &str) -> Result<(Self, i32), crate::CoreError> {
485 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
486 }
487 pub fn get_focused_package(&self) -> Result<Option<String>, crate::CoreError> {
488 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
489 }
490}
491
492#[cfg(not(target_os = "android"))]
493pub struct TxCodes { pub observer_code: u32, pub query_code: u32, pub api_mode: u8, pub fg_code: u32 }
494
495#[cfg(not(target_os = "android"))]
496pub fn read_tx_cache(_: &str) -> Option<TxCodes> { None }
497#[cfg(not(target_os = "android"))]
498pub fn write_tx_cache(_: &str, _: &TxCodes) {}
499#[cfg(not(target_os = "android"))]
500pub fn resolve_tx_codes(_: &str) -> Result<TxCodes, crate::CoreError> {
501 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
502}