1#[cfg(target_os = "android")]
27mod imp {
28 use crate::CoreError;
29 use crate::dex;
30 use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd};
31 use std::os::raw::{c_char, c_void};
32 use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU32, AtomicUsize, Ordering};
33 use std::sync::Mutex;
34
35 const STATUS_OK: i32 = 0;
38 const STATUS_UNKNOWN_TRANSACTION: i32 = -2;
39 const EX_NONE: i32 = 0;
40
41 const AM_DESCRIPTOR: &[u8] = b"android.app.IActivityManager\0";
44 const OBS_DESCRIPTOR: &[u8] = b"android.app.IProcessObserver\0";
45 const FGPROC_DESCRIPTOR: &[u8] = b"android.app.IForegroundProcessObserver\0";
46 const ACTIVITY_SERVICE: &[u8] = b"activity\0";
47 #[cfg(target_pointer_width = "64")]
48 const LIBBINDER_PATH: &[u8] = b"/system/lib64/libbinder_ndk.so\0";
49 #[cfg(target_pointer_width = "32")]
50 const LIBBINDER_PATH: &[u8] = b"/system/lib/libbinder_ndk.so\0";
51
52 static OBS_FG_CODE: AtomicU32 = AtomicU32::new(0);
63 static OBS_EVENTFD: Mutex<Option<OwnedFd>> = Mutex::new(None);
64
65 fn obs_eventfd_guard() -> std::sync::MutexGuard<'static, Option<OwnedFd>> {
66 OBS_EVENTFD.lock().unwrap_or_else(|p| p.into_inner())
67 }
68
69 static FGPROC_FG_CODE: AtomicU32 = AtomicU32::new(0);
77 static FGPROC_PID: AtomicI32 = AtomicI32::new(0);
78 static FGPROC_EVENTFD: Mutex<Option<OwnedFd>> = Mutex::new(None);
79 static FGPROC_READ_I32: AtomicUsize = AtomicUsize::new(0);
80 static FGPROC_IPROC_MODE: AtomicU32 = AtomicU32::new(0);
85
86 fn fgproc_eventfd_guard() -> std::sync::MutexGuard<'static, Option<OwnedFd>> {
87 FGPROC_EVENTFD.lock().unwrap_or_else(|p| p.into_inner())
88 }
89
90 type AIBinder = c_void;
93 #[allow(non_camel_case_types)]
94 type AIBinder_Class = c_void;
95 type AParcel = c_void;
96 type BinderStatus = i32;
97 type StringAllocator = unsafe extern "C" fn(*mut c_void, i32, *mut *mut c_char) -> bool;
98
99 unsafe extern "C" fn am_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
103 unsafe extern "C" fn am_on_destroy(_: *mut c_void) {}
104 unsafe extern "C" fn am_on_transact(
105 _: *mut AIBinder, _: u32, _: *const AParcel, _: *mut AParcel,
106 ) -> BinderStatus { STATUS_UNKNOWN_TRANSACTION }
107
108 unsafe extern "C" fn obs_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
110 unsafe extern "C" fn obs_on_destroy(_: *mut c_void) {}
111 unsafe extern "C" fn obs_on_transact(
112 _: *mut AIBinder, code: u32, _: *const AParcel, _: *mut AParcel,
113 ) -> BinderStatus {
114 if code == OBS_FG_CODE.load(Ordering::Relaxed) {
115 if let Some(fd) = obs_eventfd_guard().as_ref() {
118 let val: u64 = 1;
119 unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
120 }
121 }
122 STATUS_OK
123 }
124
125 unsafe extern "C" fn fgproc_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
134 unsafe extern "C" fn fgproc_on_destroy(_: *mut c_void) {}
135 unsafe extern "C" fn fgproc_on_transact(
136 _: *mut AIBinder, code: u32, in_parcel: *const AParcel, _: *mut AParcel,
137 ) -> BinderStatus {
138 if code != FGPROC_FG_CODE.load(Ordering::Relaxed) {
139 return STATUS_UNKNOWN_TRANSACTION;
140 }
141 let read_addr = FGPROC_READ_I32.load(Ordering::Relaxed);
144 if read_addr != 0 {
145 let read_fn: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus =
146 unsafe { std::mem::transmute(read_addr) };
147 if FGPROC_IPROC_MODE.load(Ordering::Relaxed) == 1 {
148 let mut pid: i32 = 0;
150 let mut _uid: i32 = 0;
151 let mut fg: i32 = 0;
152 let mut ok = unsafe { read_fn(in_parcel, &mut pid) } == STATUS_OK;
153 ok &= unsafe { read_fn(in_parcel, &mut _uid) } == STATUS_OK;
154 ok &= unsafe { read_fn(in_parcel, &mut fg) } == STATUS_OK;
155 if ok {
156 FGPROC_PID.store(pid, Ordering::Relaxed);
157 if fg == 0 {
160 return STATUS_OK;
161 }
162 } else {
163 return STATUS_OK;
164 }
165 } else {
166 let mut pid: i32 = 0;
167 if unsafe { read_fn(in_parcel, &mut pid) } == STATUS_OK {
168 FGPROC_PID.store(pid, Ordering::Relaxed);
169 }
170 }
171 }
172 if let Some(fd) = fgproc_eventfd_guard().as_ref() {
175 let val: u64 = 1;
176 unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
177 }
178 STATUS_OK
179 }
180
181 pub fn last_foreground_pid() -> i32 {
184 FGPROC_PID.load(Ordering::Relaxed)
185 }
186
187 const MAX_BINDER_STRING_LEN: usize = 1024 * 1024;
194
195 unsafe extern "C" fn string_alloc(
196 cookie: *mut c_void, length: i32, buffer: *mut *mut c_char,
197 ) -> bool {
198 if length < 0 { return false; }
202 let len = length as usize;
203 if len > MAX_BINDER_STRING_LEN { return false; }
204 let s = unsafe { &mut *(cookie as *mut StringBuf) };
205 s.0.reserve_exact(len + 1);
206 unsafe { s.0.as_mut_vec().resize(len + 1, 0) };
207 unsafe { *buffer = s.0.as_mut_ptr() as *mut c_char };
208 true
209 }
210
211 struct StringBuf(String);
212 impl StringBuf {
213 fn new() -> Self { Self(String::new()) }
214 fn finish(mut self) -> Option<String> {
215 if let Some(pos) = self.0.as_bytes().iter().position(|&b| b == 0) {
216 unsafe { self.0.as_mut_vec().truncate(pos) };
217 }
218 if self.0.is_empty() { None } else { Some(self.0) }
219 }
220 }
221
222 struct Vtable {
225 get_service: unsafe extern "C" fn(*const c_char) -> *mut AIBinder,
226 class_define: unsafe extern "C" fn(
227 *const c_char,
228 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
229 unsafe extern "C" fn(*mut c_void),
230 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
231 ) -> *mut AIBinder_Class,
232 associate_class: unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool,
233 new_binder: unsafe extern "C" fn(*const AIBinder_Class, *mut c_void) -> *mut AIBinder,
234 prepare_transaction: unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus,
235 transact: unsafe extern "C" fn(*mut AIBinder, u32, *mut *mut AParcel, *mut *mut AParcel, u32) -> BinderStatus,
236 dec_strong: unsafe extern "C" fn(*mut AIBinder),
237 parcel_delete: unsafe extern "C" fn(*mut AParcel),
238 read_int32: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus,
239 read_string: unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus,
240 write_strong_binder: unsafe extern "C" fn(*mut AParcel, *mut AIBinder) -> BinderStatus,
241 set_thread_pool_max: unsafe extern "C" fn(u32),
242 join_thread_pool: unsafe extern "C" fn(),
243 get_user_data: unsafe extern "C" fn(*const AIBinder) -> *mut c_void,
244 write_int32: unsafe extern "C" fn(*mut AParcel, i32) -> BinderStatus,
245 read_bool: Option<unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus>,
247 }
248
249 struct DlHandle(*mut c_void);
252 unsafe impl Send for DlHandle {}
253 impl Drop for DlHandle {
254 fn drop(&mut self) {
255 }
261 }
262
263 struct OwnedParcel { ptr: *mut AParcel, delete: unsafe extern "C" fn(*mut AParcel) }
264 impl Drop for OwnedParcel {
265 fn drop(&mut self) { if !self.ptr.is_null() { unsafe { (self.delete)(self.ptr) }; } }
266 }
267
268 struct OwnedBinder { ptr: *mut AIBinder, dec_strong: unsafe extern "C" fn(*mut AIBinder) }
269 unsafe impl Send for OwnedBinder {}
270 impl Drop for OwnedBinder {
271 fn drop(&mut self) { if !self.ptr.is_null() { unsafe { (self.dec_strong)(self.ptr) }; } }
272 }
273
274 macro_rules! dlsym_fn {
277 ($handle:expr, $name:literal, $ty:ty) => {{
278 let sym = unsafe {
279 libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char)
280 };
281 if sym.is_null() {
282 return Err(CoreError::binder(-1, concat!("dlsym:", $name)));
283 }
284 unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }
285 }};
286 }
287
288 macro_rules! dlsym_opt {
289 ($handle:expr, $name:literal, $ty:ty) => {{
290 let sym = unsafe {
291 libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char)
292 };
293 if sym.is_null() { None }
294 else { Some(unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }) }
295 }};
296 }
297
298 fn load_vtable(handle: *mut c_void) -> Result<Vtable, CoreError> {
299 Ok(Vtable {
300 get_service: dlsym_fn!(handle, "AServiceManager_getService",
301 unsafe extern "C" fn(*const c_char) -> *mut AIBinder),
302 class_define: dlsym_fn!(handle, "AIBinder_Class_define",
303 unsafe extern "C" fn(
304 *const c_char,
305 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
306 unsafe extern "C" fn(*mut c_void),
307 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
308 ) -> *mut AIBinder_Class),
309 associate_class: dlsym_fn!(handle, "AIBinder_associateClass",
310 unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool),
311 new_binder: dlsym_fn!(handle, "AIBinder_new",
312 unsafe extern "C" fn(*const AIBinder_Class, *mut c_void) -> *mut AIBinder),
313 prepare_transaction: dlsym_fn!(handle, "AIBinder_prepareTransaction",
314 unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus),
315 transact: dlsym_fn!(handle, "AIBinder_transact",
316 unsafe extern "C" fn(*mut AIBinder, u32, *mut *mut AParcel, *mut *mut AParcel, u32) -> BinderStatus),
317 dec_strong: dlsym_fn!(handle, "AIBinder_decStrong",
318 unsafe extern "C" fn(*mut AIBinder)),
319 parcel_delete: dlsym_fn!(handle, "AParcel_delete",
320 unsafe extern "C" fn(*mut AParcel)),
321 read_int32: dlsym_fn!(handle, "AParcel_readInt32",
322 unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus),
323 read_string: dlsym_fn!(handle, "AParcel_readString",
324 unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus),
325 write_strong_binder: dlsym_fn!(handle, "AParcel_writeStrongBinder",
326 unsafe extern "C" fn(*mut AParcel, *mut AIBinder) -> BinderStatus),
327 set_thread_pool_max: dlsym_fn!(handle, "ABinderProcess_setThreadPoolMaxThreadCount",
328 unsafe extern "C" fn(u32)),
329 join_thread_pool: dlsym_fn!(handle, "ABinderProcess_joinThreadPool",
330 unsafe extern "C" fn()),
331 get_user_data: dlsym_fn!(handle, "AIBinder_getUserData",
332 unsafe extern "C" fn(*const AIBinder) -> *mut c_void),
333 write_int32: dlsym_fn!(handle, "AParcel_writeInt32",
334 unsafe extern "C" fn(*mut AParcel, i32) -> BinderStatus),
335 read_bool: dlsym_opt!(handle, "AParcel_readBool",
336 unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus),
337 })
338 }
339
340 struct ParcelReader<'a> { vt: &'a Vtable, parcel: &'a OwnedParcel }
343
344 impl<'a> ParcelReader<'a> {
345 fn read_i32(&self) -> Result<i32, CoreError> {
346 let mut v = 0i32;
347 let s = unsafe { (self.vt.read_int32)(self.parcel.ptr, &mut v) };
348 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readInt32")); }
349 Ok(v)
350 }
351 fn read_string(&self) -> Result<Option<String>, CoreError> {
352 let mut buf = StringBuf::new();
353 let s = unsafe {
354 (self.vt.read_string)(self.parcel.ptr, &mut buf as *mut StringBuf as *mut c_void, string_alloc)
355 };
356 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readString")); }
357 Ok(buf.finish())
358 }
359 fn skip_i32s(&self, n: usize) -> Result<(), CoreError> {
360 for _ in 0..n { self.read_i32()?; }
361 Ok(())
362 }
363 fn skip_int_array(&self) -> Result<(), CoreError> {
364 let count = self.read_i32()?.max(0) as usize;
365 self.skip_i32s(count)
366 }
367 fn read_first_package_from_names(&self) -> Result<Option<String>, CoreError> {
368 let count = self.read_i32()?.max(0) as usize;
369 let mut first: Option<String> = None;
370 for _ in 0..count {
371 let s = self.read_string()?;
372 if first.is_none() {
373 first = s.and_then(|c| c.split('/').next().map(str::to_owned));
374 }
375 }
376 Ok(first)
377 }
378 }
379
380 struct ParcelWriter<'a> { vt: &'a Vtable, parcel: &'a OwnedParcel }
383
384 impl<'a> ParcelWriter<'a> {
385 fn write_i32(&self, v: i32) -> Result<(), CoreError> {
386 let s = unsafe { (self.vt.write_int32)(self.parcel.ptr, v) };
387 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_writeInt32")); }
388 Ok(())
389 }
390 fn write_strong_binder(&self, b: *mut AIBinder) -> Result<(), CoreError> {
391 let s = unsafe { (self.vt.write_strong_binder)(self.parcel.ptr, b) };
392 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_writeStrongBinder")); }
393 Ok(())
394 }
395 }
396
397 fn transact_write(
404 vt: &Vtable,
405 binder: *mut AIBinder,
406 code: u32,
407 writes: impl FnOnce(&ParcelWriter<'_>) -> Result<(), CoreError>,
408 ) -> Result<OwnedParcel, CoreError> {
409 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
410 let s = unsafe { (vt.prepare_transaction)(binder, &mut in_ptr) };
411 if s != STATUS_OK {
412 return Err(CoreError::binder(s, "AIBinder_prepareTransaction"));
413 }
414 let mut inp = OwnedParcel { ptr: in_ptr, delete: vt.parcel_delete };
415 {
416 let writer = ParcelWriter { vt, parcel: &inp };
417 writes(&writer)?;
418 }
419 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
420 let s = unsafe { (vt.transact)(binder, code, &mut inp.ptr, &mut out_ptr, 0) };
421 inp.ptr = std::ptr::null_mut();
423 let out = OwnedParcel { ptr: out_ptr, delete: vt.parcel_delete };
424 if s != STATUS_OK {
425 return Err(CoreError::binder(s, "AIBinder_transact"));
426 }
427 Ok(out)
428 }
429
430 fn parse_stack_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
433 r.skip_i32s(5)?;
434 r.skip_int_array()?;
435 r.read_first_package_from_names()
436 }
437
438 fn parse_root_task_info_task(r: &ParcelReader<'_>) -> Result<(i32, Option<String>), CoreError> {
445 let scratch = r.read_i32()?;
446 if scratch != 0 { r.skip_i32s(4)?; }
447 r.skip_int_array()?; let pkg = r.read_first_package_from_names()?; let bounds_count = r.read_i32()?;
451 let n = if bounds_count < 0 { 0 } else { bounds_count as usize };
452 for _ in 0..n {
453 let entry = r.read_i32()?;
454 if entry != 0 { r.skip_i32s(4)?; }
455 }
456 r.skip_int_array()?; r.skip_i32s(2)?; r.skip_i32s(1)?; let task_id = r.read_i32()?;
460 Ok((task_id, pkg))
461 }
462
463 pub struct TxCodes {
466 pub observer_code: u32,
467 pub query_code: u32,
468 pub api_mode: u8, pub fg_code: u32,
470 }
471
472 pub fn resolve_tx_codes() -> Result<TxCodes, CoreError> {
473 let (obs, query, api, fg) = dex::resolve_tx_codes_from_dex()
474 .ok_or_else(|| CoreError::binder(-1, "tx_code_resolution:dex_parse_failed"))?;
475 Ok(TxCodes { observer_code: obs, query_code: query, api_mode: api, fg_code: fg })
476 }
477
478 pub struct ActivityManagerBinder {
481 _lib: DlHandle,
482 vt: Vtable,
483 _class: *mut AIBinder_Class,
484 service: OwnedBinder,
485 tx_code: u32,
486 legacy: bool,
487 }
488 unsafe impl Send for ActivityManagerBinder {}
489
490 impl ActivityManagerBinder {
491 fn open_inner(handle: *mut c_void) -> Result<(DlHandle, Vtable, *mut AIBinder_Class, OwnedBinder), CoreError> {
492 let lib = DlHandle(handle);
493 let vt = load_vtable(handle)?;
494
495 let am_class = unsafe {
496 (vt.class_define)(
497 AM_DESCRIPTOR.as_ptr() as *const c_char,
498 am_on_create, am_on_destroy, am_on_transact,
499 )
500 };
501 if am_class.is_null() { return Err(CoreError::binder(-1, "AIBinder_Class_define:AM")); }
502
503 let raw = unsafe { (vt.get_service)(ACTIVITY_SERVICE.as_ptr() as *const c_char) };
504 if raw.is_null() { return Err(CoreError::binder(-1, "AServiceManager_getService:activity")); }
505 unsafe { (vt.associate_class)(raw, am_class) };
506
507 let service = OwnedBinder { ptr: raw, dec_strong: vt.dec_strong };
508 Ok((lib, vt, am_class, service))
509 }
510
511 fn dlopen_libbinder() -> Result<*mut c_void, CoreError> {
512 use std::os::raw::c_char;
513 let handle = unsafe {
514 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
515 };
516 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
517 Ok(handle)
518 }
519
520 pub fn open() -> Result<Self, CoreError> {
523 let handle = Self::dlopen_libbinder()?;
524 let (lib, vt, class, service) = Self::open_inner(handle)?;
525 let codes = resolve_tx_codes()?;
526 let legacy = codes.api_mode == 2;
527 Ok(Self { _lib: lib, vt, _class: class, service, tx_code: codes.query_code, legacy })
528 }
529
530 pub fn open_with_observer() -> Result<(Self, OwnedFd), CoreError> {
539 let handle = Self::dlopen_libbinder()?;
540 let (lib, vt, am_class, service) = Self::open_inner(handle)?;
541 let codes = resolve_tx_codes()?;
542 let legacy = codes.api_mode == 2;
543
544 let owned = unsafe {
547 let raw = libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC);
548 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
549 OwnedFd::from_raw_fd(raw)
550 };
551
552 let obs_class = unsafe {
554 (vt.class_define)(
555 OBS_DESCRIPTOR.as_ptr() as *const c_char,
556 obs_on_create, obs_on_destroy, obs_on_transact,
557 )
558 };
559 if obs_class.is_null() {
560 return Err(CoreError::binder(-1, "AIBinder_Class_define:Observer"));
561 }
562
563 let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
565 if obs_binder.is_null() {
566 return Err(CoreError::binder(-1, "AIBinder_new:Observer"));
567 }
568 unsafe { (vt.associate_class)(obs_binder, obs_class) };
569
570 let _ = transact_write(&vt, service.ptr, codes.observer_code, |w| {
572 w.write_strong_binder(obs_binder)
573 })?;
574
575 let consumer = owned.try_clone()
578 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:observer"))?;
579
580 OBS_FG_CODE.store(codes.fg_code, Ordering::Relaxed);
582 *obs_eventfd_guard() = Some(owned);
583
584 unsafe { (vt.set_thread_pool_max)(0) };
586 let join_fn = vt.join_thread_pool;
587 std::thread::spawn(move || unsafe { join_fn() });
588
589 let binder = Self { _lib: lib, vt, _class: am_class, service, tx_code: codes.query_code, legacy };
590 Ok((binder, consumer))
591 }
592
593 pub fn open_with_fgproc_observer() -> Result<(Self, OwnedFd), CoreError> {
617 let handle = Self::dlopen_libbinder()?;
618 let (lib, vt, am_class, service) = Self::open_inner(handle)?;
619
620 let (register_code, fgproc_code, mode, descriptor): (u32, u32, u32, &[u8]) =
625 match crate::dex::resolve_fgproc_codes() {
626 Some((r, c)) => (r, c, 0, FGPROC_DESCRIPTOR),
627 None => match crate::dex::resolve_fgproc_codes_fallback() {
628 Some((r, c)) => (r, c, 1, OBS_DESCRIPTOR),
629 None => {
630 return Err(CoreError::binder(-1, "tx_code_resolution:fgproc_dex_parse_failed"));
631 }
632 },
633 };
634
635 let owned = unsafe {
638 let raw = libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC);
639 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
640 OwnedFd::from_raw_fd(raw)
641 };
642
643 let obs_class = unsafe {
646 (vt.class_define)(
647 descriptor.as_ptr() as *const c_char,
648 fgproc_on_create, fgproc_on_destroy, fgproc_on_transact,
649 )
650 };
651 if obs_class.is_null() {
652 return Err(CoreError::binder(-1, "AIBinder_Class_define:FGProcessObserver"));
653 }
654
655 let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
657 if obs_binder.is_null() {
658 return Err(CoreError::binder(-1, "AIBinder_new:FGProcessObserver"));
659 }
660 unsafe { (vt.associate_class)(obs_binder, obs_class) };
661
662 let _ = transact_write(&vt, service.ptr, register_code, |w| {
665 w.write_strong_binder(obs_binder)
666 })?;
667
668 let consumer = owned.try_clone()
671 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:fgproc_observer"))?;
672
673 FGPROC_READ_I32.store(vt.read_int32 as usize, Ordering::Relaxed);
678 FGPROC_IPROC_MODE.store(mode, Ordering::Relaxed);
679 FGPROC_FG_CODE.store(fgproc_code, Ordering::Relaxed);
680 FGPROC_PID.store(0, Ordering::Relaxed);
681 *fgproc_eventfd_guard() = Some(owned);
682
683 unsafe { (vt.set_thread_pool_max)(0) };
685 let join_fn = vt.join_thread_pool;
686 std::thread::spawn(move || unsafe { join_fn() });
687
688 let binder = Self { _lib: lib, vt, _class: am_class, service, tx_code: 0, legacy: false };
689 Ok((binder, consumer))
690 }
691
692 fn do_transact(&self) -> Result<OwnedParcel, CoreError> {
693 transact_write(&self.vt, self.service.ptr, self.tx_code, |_| Ok(()))
694 }
695
696 pub fn get_focused_task(&self) -> Result<Option<(i32, Option<String>)>, CoreError> {
703 if self.legacy {
704 return Ok(None);
706 }
707 let out = self.do_transact()?;
708 let r = ParcelReader { vt: &self.vt, parcel: &out };
709 let ex = r.read_i32()?;
710 if ex != EX_NONE { return Err(CoreError::binder(ex, "getFocusedTask:exception")); }
711 let present = r.read_i32()?;
712 if present == 0 { return Ok(None); }
713 Ok(Some(parse_root_task_info_task(&r)?))
714 }
715
716 pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
720 if self.legacy {
721 let out = self.do_transact()?;
722 let r = ParcelReader { vt: &self.vt, parcel: &out };
723 let ex = r.read_i32()?;
724 if ex != EX_NONE { return Err(CoreError::binder(ex, "getFocusedTask:exception")); }
725 let present = r.read_i32()?;
726 if present == 0 { return Ok(None); }
727 return parse_stack_info_body(&r);
728 }
729 Ok(self.get_focused_task()?.map(|(_, pkg)| pkg).flatten())
730 }
731
732 pub fn get_focused_task_id(&self) -> Result<Option<i32>, CoreError> {
736 Ok(self.get_focused_task()?.map(|(task_id, _)| task_id))
737 }
738 }
739
740 const DISPLAY_SERVICE: &[u8] = b"display\0";
743 const DISPLAY_DESCRIPTOR: &[u8] = b"android.hardware.display.IDisplayManager\0";
744 const CALLBACK_DESCRIPTOR: &[u8] = b"android.hardware.display.IDisplayManagerCallback\0";
745 const POWER_SERVICE: &[u8] = b"power\0";
746
747 const TX_DISPLAY_REGISTER_CALLBACK: u32 = 4;
748
749 static DISP_EVENTFD: Mutex<Option<OwnedFd>> = Mutex::new(None);
752
753 fn disp_eventfd_guard() -> std::sync::MutexGuard<'static, Option<OwnedFd>> {
754 DISP_EVENTFD.lock().unwrap_or_else(|p| p.into_inner())
755 }
756
757 unsafe extern "C" fn disp_cb_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
758 unsafe extern "C" fn disp_cb_on_destroy(_: *mut c_void) {}
759 unsafe extern "C" fn disp_cb_on_transact(
760 _: *mut AIBinder, code: u32, _: *const AParcel, _: *mut AParcel,
761 ) -> BinderStatus {
762 if code == 1 {
763 if let Some(fd) = disp_eventfd_guard().as_ref() {
764 let val: u64 = 1;
765 unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
766 }
767 }
768 STATUS_OK
769 }
770
771 pub struct DisplayManagerBinder {
772 _lib: DlHandle,
773 vt: Vtable,
774 display: OwnedBinder,
775 power: Option<OwnedBinder>,
776 is_interactive_tx: u32,
777 }
778 unsafe impl Send for DisplayManagerBinder {}
779
780 impl DisplayManagerBinder {
781 pub fn open_with_callback() -> Result<(Self, crate::reactor::Fd), CoreError> {
782 let handle = unsafe {
783 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
784 };
785 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
786 let lib = DlHandle(handle);
787 let vt = load_vtable(handle)?;
788
789 let owned = unsafe {
793 let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
794 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
795 OwnedFd::from_raw_fd(raw)
796 };
797
798 let raw_display = unsafe { (vt.get_service)(DISPLAY_SERVICE.as_ptr() as *const c_char) };
800 if raw_display.is_null() {
801 return Err(CoreError::binder(-1, "AServiceManager_getService:display"));
802 }
803 let display = OwnedBinder { ptr: raw_display, dec_strong: vt.dec_strong };
804
805 let cb_class = unsafe {
807 (vt.class_define)(
808 CALLBACK_DESCRIPTOR.as_ptr() as *const c_char,
809 disp_cb_on_create, disp_cb_on_destroy, disp_cb_on_transact,
810 )
811 };
812 if cb_class.is_null() {
813 return Err(CoreError::binder(-1, "AIBinder_Class_define:DisplayCallback"));
814 }
815
816 let cb_binder = unsafe { (vt.new_binder)(cb_class, std::ptr::null_mut()) };
817 if cb_binder.is_null() {
818 return Err(CoreError::binder(-1, "AIBinder_new:DisplayCallback"));
819 }
820
821 let _ = transact_write(
823 &vt,
824 display.ptr,
825 TX_DISPLAY_REGISTER_CALLBACK,
826 |w| w.write_strong_binder(cb_binder),
827 )?;
828
829 let power = {
831 let raw = unsafe { (vt.get_service)(POWER_SERVICE.as_ptr() as *const c_char) };
832 if raw.is_null() { None } else { Some(OwnedBinder { ptr: raw, dec_strong: vt.dec_strong }) }
833 };
834
835 let is_interactive_tx = crate::dex::resolve_is_interactive_tx()
837 .ok_or_else(|| CoreError::binder(-1, "dex:TRANSACTION_isInteractive not found"))?;
838
839 let efd_owned = owned.try_clone()
842 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:display"))
843 .and_then(|dup| unsafe {
844 crate::reactor::Fd::from_owned_raw_fd(dup.into_raw_fd(), "display.efd")
845 .map_err(|_| CoreError::binder(-1, "Fd::from_owned_raw_fd:display.efd"))
846 })?;
847
848 *disp_eventfd_guard() = Some(owned);
850
851 unsafe { (vt.set_thread_pool_max)(0) };
853 let join_fn = vt.join_thread_pool;
854 std::thread::spawn(move || unsafe { join_fn() });
855
856 Ok((Self { _lib: lib, vt, display, power, is_interactive_tx }, efd_owned))
857 }
858
859 pub fn is_interactive(&self) -> Result<bool, CoreError> {
860 let power = self.power.as_ref()
861 .ok_or_else(|| CoreError::binder(-1, "power:unavailable"))?;
862 let out = transact_write(&self.vt, power.ptr, self.is_interactive_tx, |_| Ok(()))?;
863 let r = ParcelReader { vt: &self.vt, parcel: &out };
864 let ex = r.read_i32()?;
865 if ex != EX_NONE { return Err(CoreError::binder(ex, "isInteractive:exception")); }
866 if let Some(rb) = self.vt.read_bool {
867 let mut v = false;
868 let s = unsafe { rb(out.ptr as *const AParcel, &mut v) };
869 if s != STATUS_OK { return Err(CoreError::binder(s, "readBool:isInteractive")); }
870 Ok(v)
871 } else {
872 Ok(r.read_i32()? != 0)
873 }
874 }
875 }
876
877 const WINDOW_SERVICE: &[u8] = b"window\0";
880 const WM_DESCRIPTOR: &[u8] = b"android.view.IWindowManager\0";
881 const FPS_DESCRIPTOR: &[u8] = b"android.window.ITaskFpsCallback\0";
882 static FPS_VALUE: AtomicU32 = AtomicU32::new(0);
889 static FPS_SEEN: AtomicBool = AtomicBool::new(false);
894 static FPS_CODE: AtomicU32 = AtomicU32::new(0);
895 static FPS_READ_I32: AtomicUsize = AtomicUsize::new(0);
896
897 unsafe extern "C" fn wm_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
901 unsafe extern "C" fn wm_on_destroy(_: *mut c_void) {}
902 unsafe extern "C" fn wm_on_transact(
903 _: *mut AIBinder, _: u32, _: *const AParcel, _: *mut AParcel,
904 ) -> BinderStatus { STATUS_OK }
905
906 unsafe extern "C" fn fps_on_create(userdata: *mut c_void) -> *mut c_void { userdata }
912 unsafe extern "C" fn fps_on_destroy(userdata: *mut c_void) {
913 if !userdata.is_null() {
914 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
915 }
916 }
917 unsafe extern "C" fn fps_on_transact(
918 binder: *mut AIBinder, code: u32, in_parcel: *const AParcel, _: *mut AParcel,
919 ) -> BinderStatus {
920 if code != FPS_CODE.load(Ordering::Relaxed) {
921 return STATUS_UNKNOWN_TRANSACTION;
922 }
923 let read_addr = FPS_READ_I32.load(Ordering::Relaxed);
926 if read_addr != 0 {
927 let read_fn: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus =
928 unsafe { std::mem::transmute(read_addr) };
929 let mut bits: i32 = 0;
930 if unsafe { read_fn(in_parcel, &mut bits) } == STATUS_OK {
931 FPS_VALUE.store(bits as u32, Ordering::Relaxed);
934 FPS_SEEN.store(true, Ordering::Release);
935 let get_user_data = GET_USER_DATA
941 .lock()
942 .unwrap_or_else(|p| p.into_inner());
943 if let Some(get_user_data) = *get_user_data {
944 let userdata = unsafe { get_user_data(binder) };
945 if !userdata.is_null() {
946 let efd = userdata as *mut OwnedFd;
947 let val: u64 = 1;
948 unsafe {
949 libc::write((*efd).as_raw_fd(), &val as *const u64 as *const c_void, 8)
950 };
951 }
952 }
953 }
954 }
955 STATUS_OK
956 }
957
958 pub struct FpsListener {
972 _lib: DlHandle,
973 vt: Vtable,
974 window: OwnedBinder,
975 cb_binder: *mut AIBinder,
976 _wm_class: *mut AIBinder_Class,
977 register_code: u32,
978 unregister_code: u32,
979 task_id: i32,
980 }
981 unsafe impl Send for FpsListener {}
982
983 impl FpsListener {
984 pub fn open() -> Result<(Self, OwnedFd), CoreError> {
990 let handle = unsafe {
991 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
992 };
993 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
994 let lib = DlHandle(handle);
995 let vt = load_vtable(handle)?;
996
997 let (register_code, unregister_code, on_fps_code) =
998 crate::dex::resolve_fps_codes()
999 .ok_or_else(|| CoreError::binder(-1, "dex:TRANSACTION_registerTaskFpsCallback not found"))?;
1000
1001 let window = {
1002 let raw = unsafe { (vt.get_service)(WINDOW_SERVICE.as_ptr() as *const c_char) };
1003 if raw.is_null() { return Err(CoreError::binder(-1, "AServiceManager_getService:window")); }
1004 OwnedBinder { ptr: raw, dec_strong: vt.dec_strong }
1005 };
1006
1007 let wm_class = unsafe {
1010 (vt.class_define)(
1011 WM_DESCRIPTOR.as_ptr() as *const c_char,
1012 wm_on_create, wm_on_destroy, wm_on_transact,
1013 )
1014 };
1015 if wm_class.is_null() {
1016 return Err(CoreError::binder(-1, "AIBinder_Class_define:IWindowManager"));
1017 }
1018 unsafe { (vt.associate_class)(window.ptr, wm_class) };
1019
1020 let cb_class = unsafe {
1021 (vt.class_define)(
1022 FPS_DESCRIPTOR.as_ptr() as *const c_char,
1023 fps_on_create, fps_on_destroy, fps_on_transact,
1024 )
1025 };
1026 if cb_class.is_null() {
1027 return Err(CoreError::binder(-1, "AIBinder_Class_define:ITaskFpsCallback"));
1028 }
1029
1030 let owned = unsafe {
1035 let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
1036 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
1037 OwnedFd::from_raw_fd(raw)
1038 };
1039
1040 let consumer = owned.try_clone()
1041 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:fps"))?;
1042
1043 let userdata = Box::into_raw(Box::new(owned)) as *mut c_void;
1044 let cb_binder = unsafe { (vt.new_binder)(cb_class, userdata) };
1045 if cb_binder.is_null() {
1046 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
1048 return Err(CoreError::binder(-1, "AIBinder_new:ITaskFpsCallback"));
1049 }
1050 unsafe { (vt.associate_class)(cb_binder, cb_class) };
1051
1052 FPS_READ_I32.store(vt.read_int32 as usize, Ordering::Relaxed);
1055 FPS_SEEN.store(false, Ordering::Relaxed);
1056 FPS_CODE.store(on_fps_code, Ordering::Relaxed);
1057 FPS_VALUE.store(0, Ordering::Relaxed);
1058 *GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner()) = Some(vt.get_user_data);
1061
1062 unsafe { (vt.set_thread_pool_max)(0) };
1063 let join_fn = vt.join_thread_pool;
1064 std::thread::spawn(move || unsafe { join_fn() });
1065
1066 Ok((Self {
1067 _lib: lib, vt, window, cb_binder, _wm_class: wm_class,
1068 register_code, unregister_code, task_id: -1,
1069 }, consumer))
1070 }
1071
1072 pub fn register(&mut self, task_id: i32) -> Result<(), CoreError> {
1076 if self.task_id == task_id {
1077 return Ok(());
1078 }
1079 if self.task_id >= 0 {
1080 let _ = self.unregister();
1081 }
1082
1083 let _ = transact_write(&self.vt, self.window.ptr, self.register_code, |w| {
1084 w.write_i32(task_id)?;
1085 w.write_strong_binder(self.cb_binder)
1086 })?;
1087 self.task_id = task_id;
1088 Ok(())
1089 }
1090
1091 pub fn unregister(&mut self) -> Result<(), CoreError> {
1094 if self.task_id < 0 {
1095 return Ok(());
1096 }
1097 let _ = transact_write(&self.vt, self.window.ptr, self.unregister_code, |w| {
1098 w.write_strong_binder(self.cb_binder)
1099 })?;
1100 self.task_id = -1;
1101 Ok(())
1102 }
1103
1104 pub fn last_fps(&self) -> Option<f32> {
1109 fps_from_state(FPS_SEEN.load(Ordering::Acquire), FPS_VALUE.load(Ordering::Relaxed))
1110 }
1111
1112 pub fn task_id(&self) -> Option<i32> {
1114 (self.task_id >= 0).then_some(self.task_id)
1115 }
1116 }
1117
1118 impl Drop for FpsListener {
1119 fn drop(&mut self) {
1127 let _ = self.unregister();
1128 }
1129 }
1130
1131 fn fps_from_state(seen: bool, bits: u32) -> Option<f32> {
1136 if seen {
1137 Some(f32::from_bits(bits))
1138 } else {
1139 None
1140 }
1141 }
1142
1143 const TASK_SERVICE: &[u8] = b"activity_task\0";
1146 const ATM_DESCRIPTOR: &[u8] = b"android.app.IActivityTaskManager\0";
1147 const TASK_STACK_DESCRIPTOR: &[u8] = b"android.app.ITaskStackListener\0";
1148
1149 unsafe extern "C" fn atm_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
1153 unsafe extern "C" fn atm_on_destroy(_: *mut c_void) {}
1154 unsafe extern "C" fn atm_on_transact(
1155 _: *mut AIBinder, _: u32, _: *const AParcel, _: *mut AParcel,
1156 ) -> BinderStatus { STATUS_OK }
1157
1158 static GET_USER_DATA: std::sync::Mutex<Option<unsafe extern "C" fn(*const AIBinder) -> *mut c_void>> =
1174 std::sync::Mutex::new(None);
1175
1176 unsafe extern "C" fn task_stack_on_create(userdata: *mut c_void) -> *mut c_void { userdata }
1177 unsafe extern "C" fn task_stack_on_destroy(userdata: *mut c_void) {
1178 if !userdata.is_null() {
1179 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
1180 }
1181 }
1182 unsafe extern "C" fn task_stack_on_transact(
1183 binder: *mut AIBinder, _code: u32, _in_parcel: *const AParcel, _reply: *mut AParcel,
1184 ) -> BinderStatus {
1185 let get_user_data = GET_USER_DATA
1186 .lock()
1187 .unwrap_or_else(|p| p.into_inner());
1188 if let Some(get_user_data) = *get_user_data {
1189 let userdata = unsafe { get_user_data(binder) };
1190 if !userdata.is_null() {
1191 let efd = userdata as *mut OwnedFd;
1192 let val: u64 = 1;
1193 unsafe { libc::write((*efd).as_raw_fd(), &val as *const u64 as *const c_void, 8) };
1194 }
1195 }
1196 STATUS_OK
1197 }
1198
1199 pub struct TaskStackListener {
1219 _lib: DlHandle,
1220 vt: Vtable,
1221 service: OwnedBinder,
1222 cb_binder: *mut AIBinder,
1223 _atm_class: *mut AIBinder_Class,
1224 register_code: u32,
1225 unregister_code: u32,
1226 }
1227 unsafe impl Send for TaskStackListener {}
1228
1229 impl TaskStackListener {
1230 pub fn open() -> Result<(Self, OwnedFd), CoreError> {
1234 let handle = unsafe {
1235 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
1236 };
1237 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
1238 let lib = DlHandle(handle);
1239 let vt = load_vtable(handle)?;
1240
1241 let (register_code, unregister_code) =
1242 crate::dex::resolve_task_stack_codes()
1243 .ok_or_else(|| CoreError::binder(-1, "dex:TRANSACTION_registerTaskStackListener not found"))?;
1244
1245 let service = {
1246 let raw = unsafe { (vt.get_service)(TASK_SERVICE.as_ptr() as *const c_char) };
1247 if raw.is_null() { return Err(CoreError::binder(-1, "AServiceManager_getService:activity_task")); }
1248 OwnedBinder { ptr: raw, dec_strong: vt.dec_strong }
1249 };
1250
1251 let atm_class = unsafe {
1254 (vt.class_define)(
1255 ATM_DESCRIPTOR.as_ptr() as *const c_char,
1256 atm_on_create, atm_on_destroy, atm_on_transact,
1257 )
1258 };
1259 if atm_class.is_null() {
1260 return Err(CoreError::binder(-1, "AIBinder_Class_define:IActivityTaskManager"));
1261 }
1262 unsafe { (vt.associate_class)(service.ptr, atm_class) };
1263
1264 let cb_class = unsafe {
1265 (vt.class_define)(
1266 TASK_STACK_DESCRIPTOR.as_ptr() as *const c_char,
1267 task_stack_on_create, task_stack_on_destroy, task_stack_on_transact,
1268 )
1269 };
1270 if cb_class.is_null() {
1271 return Err(CoreError::binder(-1, "AIBinder_Class_define:ITaskStackListener"));
1272 }
1273
1274 let owned = unsafe {
1279 let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
1280 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
1281 OwnedFd::from_raw_fd(raw)
1282 };
1283
1284 let consumer = owned.try_clone()
1285 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:task_stack"))?;
1286
1287 let userdata = Box::into_raw(Box::new(owned)) as *mut c_void;
1288 let cb_binder = unsafe { (vt.new_binder)(cb_class, userdata) };
1289 if cb_binder.is_null() {
1290 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
1292 return Err(CoreError::binder(-1, "AIBinder_new:ITaskStackListener"));
1293 }
1294 unsafe { (vt.associate_class)(cb_binder, cb_class) };
1295
1296 *GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner()) = Some(vt.get_user_data);
1299
1300 unsafe { (vt.set_thread_pool_max)(0) };
1301 let join_fn = vt.join_thread_pool;
1302 std::thread::spawn(move || unsafe { join_fn() });
1303
1304 Ok((Self {
1305 _lib: lib, vt, service, cb_binder, _atm_class: atm_class,
1306 register_code, unregister_code,
1307 }, consumer))
1308 }
1309
1310 pub fn register(&self) -> Result<(), CoreError> {
1314 let _ = transact_write(&self.vt, self.service.ptr, self.register_code, |w| {
1315 w.write_strong_binder(self.cb_binder)
1316 })?;
1317 Ok(())
1318 }
1319
1320 pub fn unregister(&self) -> Result<(), CoreError> {
1324 let _ = transact_write(&self.vt, self.service.ptr, self.unregister_code, |w| {
1325 w.write_strong_binder(self.cb_binder)
1326 })?;
1327 Ok(())
1328 }
1329 }
1330
1331 impl Drop for TaskStackListener {
1332 fn drop(&mut self) {
1337 let _ = self.unregister();
1338 }
1339 }
1340
1341 pub struct RawBinderService {
1350 _lib: DlHandle,
1351 vt: Vtable,
1352 service: OwnedBinder,
1353 }
1354 unsafe impl Send for RawBinderService {}
1355
1356 impl RawBinderService {
1357 pub fn open(service_name: &str) -> Result<Self, CoreError> {
1359 use std::ffi::CString;
1360 let handle = unsafe {
1361 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
1362 };
1363 if handle.is_null() {
1364 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
1365 }
1366 let lib = DlHandle(handle);
1367 let vt = load_vtable(handle)?;
1368 let cs = CString::new(service_name)
1369 .map_err(|_| CoreError::binder(-1, "service_name:nul_byte"))?;
1370 let raw = unsafe { (vt.get_service)(cs.as_ptr()) };
1371 if raw.is_null() {
1372 return Err(CoreError::binder(-1, "AServiceManager_getService:null"));
1373 }
1374 let service = OwnedBinder { ptr: raw, dec_strong: vt.dec_strong };
1375 Ok(Self { _lib: lib, vt, service })
1376 }
1377
1378 pub fn transact_bool(&self, code: u32) -> Result<bool, CoreError> {
1380 let out = self.raw_noarg(code)?;
1381 let r = ParcelReader { vt: &self.vt, parcel: &out };
1382 let ex = r.read_i32()?;
1383 if ex != EX_NONE { return Err(CoreError::binder(ex, "transact_bool:exception")); }
1384 if let Some(rb) = self.vt.read_bool {
1385 let mut v = false;
1386 let s = unsafe { rb(out.ptr as *const AParcel, &mut v) };
1387 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readBool")); }
1388 Ok(v)
1389 } else {
1390 Ok(r.read_i32()? != 0)
1391 }
1392 }
1393
1394 pub fn transact_i32(&self, code: u32, arg: i32) -> Result<(), CoreError> {
1396 let _ = transact_write(&self.vt, self.service.ptr, code, |w| w.write_i32(arg))?;
1397 Ok(())
1398 }
1399
1400 fn raw_noarg(&self, code: u32) -> Result<OwnedParcel, CoreError> {
1401 transact_write(&self.vt, self.service.ptr, code, |_| Ok(()))
1402 }
1403 }
1404
1405 #[cfg(test)]
1406 mod tests {
1407 use super::*;
1408
1409 fn alloc(length: i32) -> bool {
1410 let mut buf = StringBuf::new();
1411 let mut out: *mut c_char = std::ptr::null_mut();
1412 unsafe { string_alloc(&mut buf as *mut StringBuf as *mut c_void, length, &mut out) }
1413 }
1414
1415 #[test]
1416 fn string_alloc_rejects_oversized() {
1417 assert!(!alloc(MAX_BINDER_STRING_LEN as i32 + 1));
1418 }
1419
1420 #[test]
1421 fn string_alloc_rejects_negative() {
1422 assert!(!alloc(-1));
1423 }
1424
1425 #[test]
1426 fn string_alloc_accepts_valid_len_and_nul_terminates() {
1427 let mut buf = StringBuf::new();
1428 let mut out: *mut c_char = std::ptr::null_mut();
1429 let ok = unsafe {
1430 string_alloc(&mut buf as *mut StringBuf as *mut c_void, 4, &mut out)
1431 };
1432 assert!(ok);
1433 assert!(!out.is_null());
1434 {
1435 let vec = unsafe { buf.0.as_mut_vec() };
1436 b"ABCD".iter().enumerate().for_each(|(i, &b)| vec[i] = b);
1437 vec[4] = 0;
1438 }
1439 assert_eq!(buf.finish().as_deref(), Some("ABCD"));
1440 }
1441
1442 #[test]
1443 fn fps_zero_report_distinct_from_unseen() {
1444 assert_eq!(fps_from_state(false, 0), None);
1445 assert_eq!(fps_from_state(true, 0), Some(0.0));
1446 assert_eq!(fps_from_state(true, 60.0f32.to_bits()), Some(60.0));
1447 assert_eq!(fps_from_state(false, 60.0f32.to_bits()), None);
1448 }
1449 }
1450}
1451
1452#[cfg(target_os = "android")]
1455pub use imp::{ActivityManagerBinder, DisplayManagerBinder, FpsListener, RawBinderService, TaskStackListener, TxCodes, last_foreground_pid, resolve_tx_codes};
1456
1457#[cfg(not(target_os = "android"))]
1460pub struct ActivityManagerBinder;
1461
1462#[cfg(not(target_os = "android"))]
1463impl ActivityManagerBinder {
1464 pub fn open() -> Result<Self, crate::CoreError> {
1465 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1466 }
1467 pub fn open_with_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1468 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1469 }
1470 pub fn open_with_fgproc_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1471 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1472 }
1473 pub fn get_focused_task(&self) -> Result<Option<(i32, Option<String>)>, crate::CoreError> {
1474 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1475 }
1476 pub fn get_focused_package(&self) -> Result<Option<String>, crate::CoreError> {
1477 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1478 }
1479 pub fn get_focused_task_id(&self) -> Result<Option<i32>, crate::CoreError> {
1480 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1481 }
1482}
1483
1484#[cfg(not(target_os = "android"))]
1485pub struct DisplayManagerBinder;
1486
1487#[cfg(not(target_os = "android"))]
1488impl DisplayManagerBinder {
1489 pub fn open_with_callback() -> Result<(Self, crate::reactor::Fd), crate::CoreError> {
1490 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1491 }
1492 pub fn is_interactive(&self) -> Result<bool, crate::CoreError> {
1493 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1494 }
1495}
1496
1497#[cfg(not(target_os = "android"))]
1498pub struct RawBinderService;
1499
1500#[cfg(not(target_os = "android"))]
1501impl RawBinderService {
1502 pub fn open(_service_name: &str) -> Result<Self, crate::CoreError> {
1503 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1504 }
1505 pub fn transact_bool(&self, _code: u32) -> Result<bool, crate::CoreError> {
1506 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1507 }
1508 pub fn transact_i32(&self, _code: u32, _arg: i32) -> Result<(), crate::CoreError> {
1509 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1510 }
1511}
1512
1513#[cfg(not(target_os = "android"))]
1514pub struct FpsListener;
1515
1516#[cfg(not(target_os = "android"))]
1517impl FpsListener {
1518 pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1519 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1520 }
1521 pub fn register(&mut self, _task_id: i32) -> Result<(), crate::CoreError> {
1522 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1523 }
1524 pub fn unregister(&mut self) -> Result<(), crate::CoreError> {
1525 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1526 }
1527 pub fn last_fps(&self) -> Option<f32> {
1528 None
1529 }
1530 pub fn task_id(&self) -> Option<i32> {
1531 None
1532 }
1533}
1534
1535#[cfg(not(target_os = "android"))]
1536pub struct TaskStackListener;
1537
1538#[cfg(not(target_os = "android"))]
1539impl TaskStackListener {
1540 pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1541 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1542 }
1543 pub fn register(&self) -> Result<(), crate::CoreError> {
1544 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1545 }
1546 pub fn unregister(&self) -> Result<(), crate::CoreError> {
1547 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1548 }
1549}
1550
1551#[cfg(not(target_os = "android"))]
1552pub struct TxCodes { pub observer_code: u32, pub query_code: u32, pub api_mode: u8, pub fg_code: u32 }
1553
1554#[cfg(not(target_os = "android"))]
1555pub fn resolve_tx_codes() -> Result<TxCodes, crate::CoreError> {
1556 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1557}
1558
1559#[cfg(not(target_os = "android"))]
1560pub fn last_foreground_pid() -> i32 {
1561 0
1562}