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(sanitize_fps(bits as u32), Ordering::Relaxed);
936 FPS_SEEN.store(true, Ordering::Release);
937 let get_user_data = GET_USER_DATA
943 .lock()
944 .unwrap_or_else(|p| p.into_inner());
945 if let Some(get_user_data) = *get_user_data {
946 let userdata = unsafe { get_user_data(binder) };
947 if !userdata.is_null() {
948 let efd = userdata as *mut OwnedFd;
949 let val: u64 = 1;
950 unsafe {
951 libc::write((*efd).as_raw_fd(), &val as *const u64 as *const c_void, 8)
952 };
953 }
954 }
955 }
956 }
957 STATUS_OK
958 }
959
960 pub struct FpsListener {
974 _lib: DlHandle,
975 vt: Vtable,
976 window: OwnedBinder,
977 cb_binder: *mut AIBinder,
978 _wm_class: *mut AIBinder_Class,
979 register_code: u32,
980 unregister_code: u32,
981 task_id: i32,
982 }
983 unsafe impl Send for FpsListener {}
984
985 impl FpsListener {
986 pub fn open() -> Result<(Self, OwnedFd), CoreError> {
992 let handle = unsafe {
993 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
994 };
995 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
996 let lib = DlHandle(handle);
997 let vt = load_vtable(handle)?;
998
999 let (register_code, unregister_code, on_fps_code) =
1000 crate::dex::resolve_fps_codes()
1001 .ok_or_else(|| CoreError::binder(-1, "dex:TRANSACTION_registerTaskFpsCallback not found"))?;
1002
1003 let window = {
1004 let raw = unsafe { (vt.get_service)(WINDOW_SERVICE.as_ptr() as *const c_char) };
1005 if raw.is_null() { return Err(CoreError::binder(-1, "AServiceManager_getService:window")); }
1006 OwnedBinder { ptr: raw, dec_strong: vt.dec_strong }
1007 };
1008
1009 let wm_class = unsafe {
1012 (vt.class_define)(
1013 WM_DESCRIPTOR.as_ptr() as *const c_char,
1014 wm_on_create, wm_on_destroy, wm_on_transact,
1015 )
1016 };
1017 if wm_class.is_null() {
1018 return Err(CoreError::binder(-1, "AIBinder_Class_define:IWindowManager"));
1019 }
1020 unsafe { (vt.associate_class)(window.ptr, wm_class) };
1021
1022 let cb_class = unsafe {
1023 (vt.class_define)(
1024 FPS_DESCRIPTOR.as_ptr() as *const c_char,
1025 fps_on_create, fps_on_destroy, fps_on_transact,
1026 )
1027 };
1028 if cb_class.is_null() {
1029 return Err(CoreError::binder(-1, "AIBinder_Class_define:ITaskFpsCallback"));
1030 }
1031
1032 let owned = unsafe {
1037 let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
1038 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
1039 OwnedFd::from_raw_fd(raw)
1040 };
1041
1042 let consumer = owned.try_clone()
1043 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:fps"))?;
1044
1045 let userdata = Box::into_raw(Box::new(owned)) as *mut c_void;
1046 let cb_binder = unsafe { (vt.new_binder)(cb_class, userdata) };
1047 if cb_binder.is_null() {
1048 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
1050 return Err(CoreError::binder(-1, "AIBinder_new:ITaskFpsCallback"));
1051 }
1052 unsafe { (vt.associate_class)(cb_binder, cb_class) };
1053
1054 FPS_READ_I32.store(vt.read_int32 as usize, Ordering::Relaxed);
1057 FPS_SEEN.store(false, Ordering::Relaxed);
1058 FPS_CODE.store(on_fps_code, Ordering::Relaxed);
1059 FPS_VALUE.store(0, Ordering::Relaxed);
1060 *GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner()) = Some(vt.get_user_data);
1063
1064 unsafe { (vt.set_thread_pool_max)(0) };
1065 let join_fn = vt.join_thread_pool;
1066 std::thread::spawn(move || unsafe { join_fn() });
1067
1068 Ok((Self {
1069 _lib: lib, vt, window, cb_binder, _wm_class: wm_class,
1070 register_code, unregister_code, task_id: -1,
1071 }, consumer))
1072 }
1073
1074 pub fn register(&mut self, task_id: i32) -> Result<(), CoreError> {
1078 if self.task_id == task_id {
1079 return Ok(());
1080 }
1081 if self.task_id >= 0 {
1082 let _ = self.unregister();
1083 }
1084
1085 let _ = transact_write(&self.vt, self.window.ptr, self.register_code, |w| {
1086 w.write_i32(task_id)?;
1087 w.write_strong_binder(self.cb_binder)
1088 })?;
1089 self.task_id = task_id;
1090 Ok(())
1091 }
1092
1093 pub fn unregister(&mut self) -> Result<(), CoreError> {
1096 if self.task_id < 0 {
1097 return Ok(());
1098 }
1099 let _ = transact_write(&self.vt, self.window.ptr, self.unregister_code, |w| {
1100 w.write_strong_binder(self.cb_binder)
1101 })?;
1102 self.task_id = -1;
1103 Ok(())
1104 }
1105
1106 pub fn last_fps(&self) -> Option<f32> {
1111 fps_from_state(FPS_SEEN.load(Ordering::Acquire), FPS_VALUE.load(Ordering::Relaxed))
1112 }
1113
1114 pub fn task_id(&self) -> Option<i32> {
1116 (self.task_id >= 0).then_some(self.task_id)
1117 }
1118 }
1119
1120 impl Drop for FpsListener {
1121 fn drop(&mut self) {
1129 let _ = self.unregister();
1130 }
1131 }
1132
1133 fn fps_from_state(seen: bool, bits: u32) -> Option<f32> {
1138 if seen {
1139 Some(f32::from_bits(bits))
1140 } else {
1141 None
1142 }
1143 }
1144
1145 fn sanitize_fps(bits: u32) -> u32 {
1150 let v = f32::from_bits(bits);
1151 if v.is_finite() && v >= 0.0 {
1152 bits
1153 } else {
1154 0.0f32.to_bits()
1155 }
1156 }
1157
1158 const TASK_SERVICE: &[u8] = b"activity_task\0";
1161 const ATM_DESCRIPTOR: &[u8] = b"android.app.IActivityTaskManager\0";
1162 const TASK_STACK_DESCRIPTOR: &[u8] = b"android.app.ITaskStackListener\0";
1163
1164 unsafe extern "C" fn atm_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
1168 unsafe extern "C" fn atm_on_destroy(_: *mut c_void) {}
1169 unsafe extern "C" fn atm_on_transact(
1170 _: *mut AIBinder, _: u32, _: *const AParcel, _: *mut AParcel,
1171 ) -> BinderStatus { STATUS_OK }
1172
1173 static GET_USER_DATA: std::sync::Mutex<Option<unsafe extern "C" fn(*const AIBinder) -> *mut c_void>> =
1189 std::sync::Mutex::new(None);
1190
1191 unsafe extern "C" fn task_stack_on_create(userdata: *mut c_void) -> *mut c_void { userdata }
1192 unsafe extern "C" fn task_stack_on_destroy(userdata: *mut c_void) {
1193 if !userdata.is_null() {
1194 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
1195 }
1196 }
1197 unsafe extern "C" fn task_stack_on_transact(
1198 binder: *mut AIBinder, _code: u32, _in_parcel: *const AParcel, _reply: *mut AParcel,
1199 ) -> BinderStatus {
1200 let get_user_data = GET_USER_DATA
1201 .lock()
1202 .unwrap_or_else(|p| p.into_inner());
1203 if let Some(get_user_data) = *get_user_data {
1204 let userdata = unsafe { get_user_data(binder) };
1205 if !userdata.is_null() {
1206 let efd = userdata as *mut OwnedFd;
1207 let val: u64 = 1;
1208 unsafe { libc::write((*efd).as_raw_fd(), &val as *const u64 as *const c_void, 8) };
1209 }
1210 }
1211 STATUS_OK
1212 }
1213
1214 pub struct TaskStackListener {
1234 _lib: DlHandle,
1235 vt: Vtable,
1236 service: OwnedBinder,
1237 cb_binder: *mut AIBinder,
1238 _atm_class: *mut AIBinder_Class,
1239 register_code: u32,
1240 unregister_code: u32,
1241 }
1242 unsafe impl Send for TaskStackListener {}
1243
1244 impl TaskStackListener {
1245 pub fn open() -> Result<(Self, OwnedFd), CoreError> {
1249 let handle = unsafe {
1250 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
1251 };
1252 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
1253 let lib = DlHandle(handle);
1254 let vt = load_vtable(handle)?;
1255
1256 let (register_code, unregister_code) =
1257 crate::dex::resolve_task_stack_codes()
1258 .ok_or_else(|| CoreError::binder(-1, "dex:TRANSACTION_registerTaskStackListener not found"))?;
1259
1260 let service = {
1261 let raw = unsafe { (vt.get_service)(TASK_SERVICE.as_ptr() as *const c_char) };
1262 if raw.is_null() { return Err(CoreError::binder(-1, "AServiceManager_getService:activity_task")); }
1263 OwnedBinder { ptr: raw, dec_strong: vt.dec_strong }
1264 };
1265
1266 let atm_class = unsafe {
1269 (vt.class_define)(
1270 ATM_DESCRIPTOR.as_ptr() as *const c_char,
1271 atm_on_create, atm_on_destroy, atm_on_transact,
1272 )
1273 };
1274 if atm_class.is_null() {
1275 return Err(CoreError::binder(-1, "AIBinder_Class_define:IActivityTaskManager"));
1276 }
1277 unsafe { (vt.associate_class)(service.ptr, atm_class) };
1278
1279 let cb_class = unsafe {
1280 (vt.class_define)(
1281 TASK_STACK_DESCRIPTOR.as_ptr() as *const c_char,
1282 task_stack_on_create, task_stack_on_destroy, task_stack_on_transact,
1283 )
1284 };
1285 if cb_class.is_null() {
1286 return Err(CoreError::binder(-1, "AIBinder_Class_define:ITaskStackListener"));
1287 }
1288
1289 let owned = unsafe {
1294 let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
1295 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
1296 OwnedFd::from_raw_fd(raw)
1297 };
1298
1299 let consumer = owned.try_clone()
1300 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:task_stack"))?;
1301
1302 let userdata = Box::into_raw(Box::new(owned)) as *mut c_void;
1303 let cb_binder = unsafe { (vt.new_binder)(cb_class, userdata) };
1304 if cb_binder.is_null() {
1305 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
1307 return Err(CoreError::binder(-1, "AIBinder_new:ITaskStackListener"));
1308 }
1309 unsafe { (vt.associate_class)(cb_binder, cb_class) };
1310
1311 *GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner()) = Some(vt.get_user_data);
1314
1315 unsafe { (vt.set_thread_pool_max)(0) };
1316 let join_fn = vt.join_thread_pool;
1317 std::thread::spawn(move || unsafe { join_fn() });
1318
1319 Ok((Self {
1320 _lib: lib, vt, service, cb_binder, _atm_class: atm_class,
1321 register_code, unregister_code,
1322 }, consumer))
1323 }
1324
1325 pub fn register(&self) -> Result<(), CoreError> {
1329 let _ = transact_write(&self.vt, self.service.ptr, self.register_code, |w| {
1330 w.write_strong_binder(self.cb_binder)
1331 })?;
1332 Ok(())
1333 }
1334
1335 pub fn unregister(&self) -> Result<(), CoreError> {
1339 let _ = transact_write(&self.vt, self.service.ptr, self.unregister_code, |w| {
1340 w.write_strong_binder(self.cb_binder)
1341 })?;
1342 Ok(())
1343 }
1344 }
1345
1346 impl Drop for TaskStackListener {
1347 fn drop(&mut self) {
1352 let _ = self.unregister();
1353 }
1354 }
1355
1356 pub struct RawBinderService {
1365 _lib: DlHandle,
1366 vt: Vtable,
1367 service: OwnedBinder,
1368 }
1369 unsafe impl Send for RawBinderService {}
1370
1371 impl RawBinderService {
1372 pub fn open(service_name: &str) -> Result<Self, CoreError> {
1374 use std::ffi::CString;
1375 let handle = unsafe {
1376 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
1377 };
1378 if handle.is_null() {
1379 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
1380 }
1381 let lib = DlHandle(handle);
1382 let vt = load_vtable(handle)?;
1383 let cs = CString::new(service_name)
1384 .map_err(|_| CoreError::binder(-1, "service_name:nul_byte"))?;
1385 let raw = unsafe { (vt.get_service)(cs.as_ptr()) };
1386 if raw.is_null() {
1387 return Err(CoreError::binder(-1, "AServiceManager_getService:null"));
1388 }
1389 let service = OwnedBinder { ptr: raw, dec_strong: vt.dec_strong };
1390 Ok(Self { _lib: lib, vt, service })
1391 }
1392
1393 pub fn transact_bool(&self, code: u32) -> Result<bool, CoreError> {
1395 let out = self.raw_noarg(code)?;
1396 let r = ParcelReader { vt: &self.vt, parcel: &out };
1397 let ex = r.read_i32()?;
1398 if ex != EX_NONE { return Err(CoreError::binder(ex, "transact_bool:exception")); }
1399 if let Some(rb) = self.vt.read_bool {
1400 let mut v = false;
1401 let s = unsafe { rb(out.ptr as *const AParcel, &mut v) };
1402 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readBool")); }
1403 Ok(v)
1404 } else {
1405 Ok(r.read_i32()? != 0)
1406 }
1407 }
1408
1409 pub fn transact_i32(&self, code: u32, arg: i32) -> Result<(), CoreError> {
1411 let _ = transact_write(&self.vt, self.service.ptr, code, |w| w.write_i32(arg))?;
1412 Ok(())
1413 }
1414
1415 fn raw_noarg(&self, code: u32) -> Result<OwnedParcel, CoreError> {
1416 transact_write(&self.vt, self.service.ptr, code, |_| Ok(()))
1417 }
1418 }
1419
1420 #[cfg(test)]
1421 mod tests {
1422 use super::*;
1423
1424 fn alloc(length: i32) -> bool {
1425 let mut buf = StringBuf::new();
1426 let mut out: *mut c_char = std::ptr::null_mut();
1427 unsafe { string_alloc(&mut buf as *mut StringBuf as *mut c_void, length, &mut out) }
1428 }
1429
1430 #[test]
1431 fn string_alloc_rejects_oversized() {
1432 assert!(!alloc(MAX_BINDER_STRING_LEN as i32 + 1));
1433 }
1434
1435 #[test]
1436 fn string_alloc_rejects_negative() {
1437 assert!(!alloc(-1));
1438 }
1439
1440 #[test]
1441 fn string_alloc_accepts_valid_len_and_nul_terminates() {
1442 let mut buf = StringBuf::new();
1443 let mut out: *mut c_char = std::ptr::null_mut();
1444 let ok = unsafe {
1445 string_alloc(&mut buf as *mut StringBuf as *mut c_void, 4, &mut out)
1446 };
1447 assert!(ok);
1448 assert!(!out.is_null());
1449 {
1450 let vec = unsafe { buf.0.as_mut_vec() };
1451 b"ABCD".iter().enumerate().for_each(|(i, &b)| vec[i] = b);
1452 vec[4] = 0;
1453 }
1454 assert_eq!(buf.finish().as_deref(), Some("ABCD"));
1455 }
1456
1457 #[test]
1458 fn fps_zero_report_distinct_from_unseen() {
1459 assert_eq!(fps_from_state(false, 0), None);
1460 assert_eq!(fps_from_state(true, 0), Some(0.0));
1461 assert_eq!(fps_from_state(true, 60.0f32.to_bits()), Some(60.0));
1462 assert_eq!(fps_from_state(false, 60.0f32.to_bits()), None);
1463 }
1464
1465 #[test]
1466 fn sanitize_fps_rejects_non_finite_and_negative() {
1467 let de = |bits| f32::from_bits(sanitize_fps(bits));
1468 assert_eq!(de(0.0f32.to_bits()), 0.0);
1469 assert_eq!(de(60.0f32.to_bits()), 60.0);
1470 assert_eq!(de(f32::NAN.to_bits()), 0.0);
1471 assert_eq!(de(f32::INFINITY.to_bits()), 0.0);
1472 assert_eq!(de(f32::NEG_INFINITY.to_bits()), 0.0);
1473 assert_eq!(de((-5.0f32).to_bits()), 0.0);
1474 }
1475 }
1476}
1477
1478#[cfg(target_os = "android")]
1481pub use imp::{ActivityManagerBinder, DisplayManagerBinder, FpsListener, RawBinderService, TaskStackListener, TxCodes, last_foreground_pid, resolve_tx_codes};
1482
1483#[cfg(not(target_os = "android"))]
1486pub struct ActivityManagerBinder;
1487
1488#[cfg(not(target_os = "android"))]
1489impl ActivityManagerBinder {
1490 pub fn open() -> Result<Self, crate::CoreError> {
1491 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1492 }
1493 pub fn open_with_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1494 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1495 }
1496 pub fn open_with_fgproc_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1497 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1498 }
1499 pub fn get_focused_task(&self) -> Result<Option<(i32, Option<String>)>, crate::CoreError> {
1500 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1501 }
1502 pub fn get_focused_package(&self) -> Result<Option<String>, crate::CoreError> {
1503 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1504 }
1505 pub fn get_focused_task_id(&self) -> Result<Option<i32>, crate::CoreError> {
1506 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1507 }
1508}
1509
1510#[cfg(not(target_os = "android"))]
1511pub struct DisplayManagerBinder;
1512
1513#[cfg(not(target_os = "android"))]
1514impl DisplayManagerBinder {
1515 pub fn open_with_callback() -> Result<(Self, crate::reactor::Fd), crate::CoreError> {
1516 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1517 }
1518 pub fn is_interactive(&self) -> Result<bool, crate::CoreError> {
1519 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1520 }
1521}
1522
1523#[cfg(not(target_os = "android"))]
1524pub struct RawBinderService;
1525
1526#[cfg(not(target_os = "android"))]
1527impl RawBinderService {
1528 pub fn open(_service_name: &str) -> Result<Self, crate::CoreError> {
1529 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1530 }
1531 pub fn transact_bool(&self, _code: u32) -> Result<bool, crate::CoreError> {
1532 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1533 }
1534 pub fn transact_i32(&self, _code: u32, _arg: i32) -> Result<(), crate::CoreError> {
1535 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1536 }
1537}
1538
1539#[cfg(not(target_os = "android"))]
1540pub struct FpsListener;
1541
1542#[cfg(not(target_os = "android"))]
1543impl FpsListener {
1544 pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1545 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1546 }
1547 pub fn register(&mut self, _task_id: i32) -> Result<(), crate::CoreError> {
1548 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1549 }
1550 pub fn unregister(&mut self) -> Result<(), crate::CoreError> {
1551 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1552 }
1553 pub fn last_fps(&self) -> Option<f32> {
1554 None
1555 }
1556 pub fn task_id(&self) -> Option<i32> {
1557 None
1558 }
1559}
1560
1561#[cfg(not(target_os = "android"))]
1562pub struct TaskStackListener;
1563
1564#[cfg(not(target_os = "android"))]
1565impl TaskStackListener {
1566 pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1567 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1568 }
1569 pub fn register(&self) -> Result<(), crate::CoreError> {
1570 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1571 }
1572 pub fn unregister(&self) -> Result<(), crate::CoreError> {
1573 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1574 }
1575}
1576
1577#[cfg(not(target_os = "android"))]
1578pub struct TxCodes { pub observer_code: u32, pub query_code: u32, pub api_mode: u8, pub fg_code: u32 }
1579
1580#[cfg(not(target_os = "android"))]
1581pub fn resolve_tx_codes() -> Result<TxCodes, crate::CoreError> {
1582 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1583}
1584
1585#[cfg(not(target_os = "android"))]
1586pub fn last_foreground_pid() -> i32 {
1587 0
1588}