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::{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 unsafe extern "C" fn string_alloc(
190 cookie: *mut c_void, length: i32, buffer: *mut *mut c_char,
191 ) -> bool {
192 if length < 0 { return true; }
193 let s = unsafe { &mut *(cookie as *mut StringBuf) };
194 s.0.reserve_exact(length as usize + 1);
195 unsafe { s.0.as_mut_vec().resize(length as usize + 1, 0) };
196 unsafe { *buffer = s.0.as_mut_ptr() as *mut c_char };
197 true
198 }
199
200 struct StringBuf(String);
201 impl StringBuf {
202 fn new() -> Self { Self(String::new()) }
203 fn finish(mut self) -> Option<String> {
204 if let Some(pos) = self.0.as_bytes().iter().position(|&b| b == 0) {
205 unsafe { self.0.as_mut_vec().truncate(pos) };
206 }
207 if self.0.is_empty() { None } else { Some(self.0) }
208 }
209 }
210
211 struct Vtable {
214 get_service: unsafe extern "C" fn(*const c_char) -> *mut AIBinder,
215 class_define: unsafe extern "C" fn(
216 *const c_char,
217 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
218 unsafe extern "C" fn(*mut c_void),
219 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
220 ) -> *mut AIBinder_Class,
221 associate_class: unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool,
222 new_binder: unsafe extern "C" fn(*const AIBinder_Class, *mut c_void) -> *mut AIBinder,
223 prepare_transaction: unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus,
224 transact: unsafe extern "C" fn(*mut AIBinder, u32, *mut *mut AParcel, *mut *mut AParcel, u32) -> BinderStatus,
225 dec_strong: unsafe extern "C" fn(*mut AIBinder),
226 parcel_delete: unsafe extern "C" fn(*mut AParcel),
227 read_int32: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus,
228 read_string: unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus,
229 write_strong_binder: unsafe extern "C" fn(*mut AParcel, *mut AIBinder) -> BinderStatus,
230 set_thread_pool_max: unsafe extern "C" fn(u32),
231 join_thread_pool: unsafe extern "C" fn(),
232 write_int32: unsafe extern "C" fn(*mut AParcel, i32) -> BinderStatus,
233 read_bool: Option<unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus>,
235 }
236
237 struct DlHandle(*mut c_void);
240 unsafe impl Send for DlHandle {}
241 impl Drop for DlHandle {
242 fn drop(&mut self) {
243 }
249 }
250
251 struct OwnedParcel { ptr: *mut AParcel, delete: unsafe extern "C" fn(*mut AParcel) }
252 impl Drop for OwnedParcel {
253 fn drop(&mut self) { if !self.ptr.is_null() { unsafe { (self.delete)(self.ptr) }; } }
254 }
255
256 struct OwnedBinder { ptr: *mut AIBinder, dec_strong: unsafe extern "C" fn(*mut AIBinder) }
257 unsafe impl Send for OwnedBinder {}
258 impl Drop for OwnedBinder {
259 fn drop(&mut self) { if !self.ptr.is_null() { unsafe { (self.dec_strong)(self.ptr) }; } }
260 }
261
262 macro_rules! dlsym_fn {
265 ($handle:expr, $name:literal, $ty:ty) => {{
266 let sym = unsafe {
267 libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char)
268 };
269 if sym.is_null() {
270 return Err(CoreError::binder(-1, concat!("dlsym:", $name)));
271 }
272 unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }
273 }};
274 }
275
276 macro_rules! dlsym_opt {
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() { None }
282 else { Some(unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }) }
283 }};
284 }
285
286 fn load_vtable(handle: *mut c_void) -> Result<Vtable, CoreError> {
287 Ok(Vtable {
288 get_service: dlsym_fn!(handle, "AServiceManager_getService",
289 unsafe extern "C" fn(*const c_char) -> *mut AIBinder),
290 class_define: dlsym_fn!(handle, "AIBinder_Class_define",
291 unsafe extern "C" fn(
292 *const c_char,
293 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
294 unsafe extern "C" fn(*mut c_void),
295 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
296 ) -> *mut AIBinder_Class),
297 associate_class: dlsym_fn!(handle, "AIBinder_associateClass",
298 unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool),
299 new_binder: dlsym_fn!(handle, "AIBinder_new",
300 unsafe extern "C" fn(*const AIBinder_Class, *mut c_void) -> *mut AIBinder),
301 prepare_transaction: dlsym_fn!(handle, "AIBinder_prepareTransaction",
302 unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus),
303 transact: dlsym_fn!(handle, "AIBinder_transact",
304 unsafe extern "C" fn(*mut AIBinder, u32, *mut *mut AParcel, *mut *mut AParcel, u32) -> BinderStatus),
305 dec_strong: dlsym_fn!(handle, "AIBinder_decStrong",
306 unsafe extern "C" fn(*mut AIBinder)),
307 parcel_delete: dlsym_fn!(handle, "AParcel_delete",
308 unsafe extern "C" fn(*mut AParcel)),
309 read_int32: dlsym_fn!(handle, "AParcel_readInt32",
310 unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus),
311 read_string: dlsym_fn!(handle, "AParcel_readString",
312 unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus),
313 write_strong_binder: dlsym_fn!(handle, "AParcel_writeStrongBinder",
314 unsafe extern "C" fn(*mut AParcel, *mut AIBinder) -> BinderStatus),
315 set_thread_pool_max: dlsym_fn!(handle, "ABinderProcess_setThreadPoolMaxThreadCount",
316 unsafe extern "C" fn(u32)),
317 join_thread_pool: dlsym_fn!(handle, "ABinderProcess_joinThreadPool",
318 unsafe extern "C" fn()),
319 write_int32: dlsym_fn!(handle, "AParcel_writeInt32",
320 unsafe extern "C" fn(*mut AParcel, i32) -> BinderStatus),
321 read_bool: dlsym_opt!(handle, "AParcel_readBool",
322 unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus),
323 })
324 }
325
326 struct ParcelReader<'a> { vt: &'a Vtable, parcel: &'a OwnedParcel }
329
330 impl<'a> ParcelReader<'a> {
331 fn read_i32(&self) -> Result<i32, CoreError> {
332 let mut v = 0i32;
333 let s = unsafe { (self.vt.read_int32)(self.parcel.ptr, &mut v) };
334 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readInt32")); }
335 Ok(v)
336 }
337 fn read_string(&self) -> Result<Option<String>, CoreError> {
338 let mut buf = StringBuf::new();
339 let s = unsafe {
340 (self.vt.read_string)(self.parcel.ptr, &mut buf as *mut StringBuf as *mut c_void, string_alloc)
341 };
342 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readString")); }
343 Ok(buf.finish())
344 }
345 fn skip_i32s(&self, n: usize) -> Result<(), CoreError> {
346 for _ in 0..n { self.read_i32()?; }
347 Ok(())
348 }
349 fn skip_int_array(&self) -> Result<(), CoreError> {
350 let count = self.read_i32()?.max(0) as usize;
351 self.skip_i32s(count)
352 }
353 fn read_first_package_from_names(&self) -> Result<Option<String>, CoreError> {
354 let count = self.read_i32()?.max(0) as usize;
355 let mut first: Option<String> = None;
356 for _ in 0..count {
357 let s = self.read_string()?;
358 if first.is_none() {
359 first = s.and_then(|c| c.split('/').next().map(str::to_owned));
360 }
361 }
362 Ok(first)
363 }
364 }
365
366 fn parse_root_task_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
369 let scratch = r.read_i32()?;
370 if scratch != 0 { r.skip_i32s(4)?; }
371 r.skip_int_array()?;
372 r.read_first_package_from_names()
373 }
374
375 fn parse_stack_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
376 r.skip_i32s(5)?;
377 r.skip_int_array()?;
378 r.read_first_package_from_names()
379 }
380
381 fn parse_root_task_info_task_id(r: &ParcelReader<'_>) -> Result<Option<i32>, CoreError> {
386 let scratch = r.read_i32()?;
387 if scratch != 0 { r.skip_i32s(4)?; }
388 r.skip_int_array()?;
389 r.read_first_package_from_names()?; let bounds_count = r.read_i32()?;
392 let n = if bounds_count < 0 { 0 } else { bounds_count as usize };
393 for _ in 0..n {
394 let entry = r.read_i32()?;
395 if entry != 0 { r.skip_i32s(4)?; }
396 }
397 r.skip_int_array()?; r.skip_i32s(2)?; r.skip_i32s(1)?; let task_id = r.read_i32()?;
401 Ok(Some(task_id))
402 }
403
404 pub struct TxCodes {
407 pub observer_code: u32,
408 pub query_code: u32,
409 pub api_mode: u8, pub fg_code: u32,
411 }
412
413 pub fn resolve_tx_codes() -> Result<TxCodes, CoreError> {
414 let (obs, query, api, fg) = dex::resolve_tx_codes_from_dex()
415 .ok_or_else(|| CoreError::binder(-1, "tx_code_resolution:dex_parse_failed"))?;
416 Ok(TxCodes { observer_code: obs, query_code: query, api_mode: api, fg_code: fg })
417 }
418
419 pub struct ActivityManagerBinder {
422 _lib: DlHandle,
423 vt: Vtable,
424 _class: *mut AIBinder_Class,
425 service: OwnedBinder,
426 tx_code: u32,
427 legacy: bool,
428 }
429 unsafe impl Send for ActivityManagerBinder {}
430
431 impl ActivityManagerBinder {
432 fn open_inner(handle: *mut c_void) -> Result<(DlHandle, Vtable, *mut AIBinder_Class, OwnedBinder), CoreError> {
433 let lib = DlHandle(handle);
434 let vt = load_vtable(handle)?;
435
436 let am_class = unsafe {
437 (vt.class_define)(
438 AM_DESCRIPTOR.as_ptr() as *const c_char,
439 am_on_create, am_on_destroy, am_on_transact,
440 )
441 };
442 if am_class.is_null() { return Err(CoreError::binder(-1, "AIBinder_Class_define:AM")); }
443
444 let raw = unsafe { (vt.get_service)(ACTIVITY_SERVICE.as_ptr() as *const c_char) };
445 if raw.is_null() { return Err(CoreError::binder(-1, "AServiceManager_getService:activity")); }
446 unsafe { (vt.associate_class)(raw, am_class) };
447
448 let service = OwnedBinder { ptr: raw, dec_strong: vt.dec_strong };
449 Ok((lib, vt, am_class, service))
450 }
451
452 fn dlopen_libbinder() -> Result<*mut c_void, CoreError> {
453 use std::os::raw::c_char;
454 let handle = unsafe {
455 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
456 };
457 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
458 Ok(handle)
459 }
460
461 pub fn open() -> Result<Self, CoreError> {
464 let handle = Self::dlopen_libbinder()?;
465 let (lib, vt, class, service) = Self::open_inner(handle)?;
466 let codes = resolve_tx_codes()?;
467 let legacy = codes.api_mode == 2;
468 Ok(Self { _lib: lib, vt, _class: class, service, tx_code: codes.query_code, legacy })
469 }
470
471 pub fn open_with_observer() -> Result<(Self, OwnedFd), CoreError> {
480 let handle = Self::dlopen_libbinder()?;
481 let (lib, vt, am_class, service) = Self::open_inner(handle)?;
482 let codes = resolve_tx_codes()?;
483 let legacy = codes.api_mode == 2;
484
485 let owned = unsafe {
488 let raw = libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC);
489 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
490 OwnedFd::from_raw_fd(raw)
491 };
492
493 let obs_class = unsafe {
495 (vt.class_define)(
496 OBS_DESCRIPTOR.as_ptr() as *const c_char,
497 obs_on_create, obs_on_destroy, obs_on_transact,
498 )
499 };
500 if obs_class.is_null() {
501 return Err(CoreError::binder(-1, "AIBinder_Class_define:Observer"));
502 }
503
504 let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
506 if obs_binder.is_null() {
507 return Err(CoreError::binder(-1, "AIBinder_new:Observer"));
508 }
509 unsafe { (vt.associate_class)(obs_binder, obs_class) };
510
511 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
513 let s = unsafe { (vt.prepare_transaction)(service.ptr, &mut in_ptr) };
514 if s != STATUS_OK {
515 return Err(CoreError::binder(s, "prepareTransaction:registerObserver"));
516 }
517 unsafe { (vt.write_strong_binder)(in_ptr, obs_binder) };
518 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
519 let s = unsafe {
520 (vt.transact)(service.ptr, codes.observer_code, &mut in_ptr, &mut out_ptr, 0)
521 };
522 if !out_ptr.is_null() { unsafe { (vt.parcel_delete)(out_ptr) }; }
523 if s != STATUS_OK {
524 return Err(CoreError::binder(s, "transact:registerProcessObserver"));
525 }
526
527 let consumer = owned.try_clone()
530 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:observer"))?;
531
532 OBS_FG_CODE.store(codes.fg_code, Ordering::Relaxed);
534 *obs_eventfd_guard() = Some(owned);
535
536 unsafe { (vt.set_thread_pool_max)(0) };
538 let join_fn = vt.join_thread_pool;
539 std::thread::spawn(move || unsafe { join_fn() });
540
541 let binder = Self { _lib: lib, vt, _class: am_class, service, tx_code: codes.query_code, legacy };
542 Ok((binder, consumer))
543 }
544
545 pub fn open_with_fgproc_observer() -> Result<(Self, OwnedFd), CoreError> {
569 let handle = Self::dlopen_libbinder()?;
570 let (lib, vt, am_class, service) = Self::open_inner(handle)?;
571
572 let (register_code, fgproc_code, mode, descriptor): (u32, u32, u32, &[u8]) =
577 match crate::dex::resolve_fgproc_codes() {
578 Some((r, c)) => (r, c, 0, FGPROC_DESCRIPTOR),
579 None => match crate::dex::resolve_fgproc_codes_fallback() {
580 Some((r, c)) => (r, c, 1, OBS_DESCRIPTOR),
581 None => {
582 return Err(CoreError::binder(-1, "tx_code_resolution:fgproc_dex_parse_failed"));
583 }
584 },
585 };
586
587 let owned = unsafe {
590 let raw = libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC);
591 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
592 OwnedFd::from_raw_fd(raw)
593 };
594
595 let obs_class = unsafe {
598 (vt.class_define)(
599 descriptor.as_ptr() as *const c_char,
600 fgproc_on_create, fgproc_on_destroy, fgproc_on_transact,
601 )
602 };
603 if obs_class.is_null() {
604 return Err(CoreError::binder(-1, "AIBinder_Class_define:FGProcessObserver"));
605 }
606
607 let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
609 if obs_binder.is_null() {
610 return Err(CoreError::binder(-1, "AIBinder_new:FGProcessObserver"));
611 }
612 unsafe { (vt.associate_class)(obs_binder, obs_class) };
613
614 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
617 let s = unsafe { (vt.prepare_transaction)(service.ptr, &mut in_ptr) };
618 if s != STATUS_OK {
619 return Err(CoreError::binder(s, "prepareTransaction:registerForegroundProcessObserver"));
620 }
621 unsafe { (vt.write_strong_binder)(in_ptr, obs_binder) };
622 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
623 let s = unsafe {
624 (vt.transact)(service.ptr, register_code, &mut in_ptr, &mut out_ptr, 0)
625 };
626 if !out_ptr.is_null() { unsafe { (vt.parcel_delete)(out_ptr) }; }
627 if s != STATUS_OK {
628 return Err(CoreError::binder(s, "transact:registerForegroundProcessObserver"));
629 }
630
631 let consumer = owned.try_clone()
634 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:fgproc_observer"))?;
635
636 FGPROC_READ_I32.store(vt.read_int32 as usize, Ordering::Relaxed);
641 FGPROC_IPROC_MODE.store(mode, Ordering::Relaxed);
642 FGPROC_FG_CODE.store(fgproc_code, Ordering::Relaxed);
643 FGPROC_PID.store(0, Ordering::Relaxed);
644 *fgproc_eventfd_guard() = Some(owned);
645
646 unsafe { (vt.set_thread_pool_max)(0) };
648 let join_fn = vt.join_thread_pool;
649 std::thread::spawn(move || unsafe { join_fn() });
650
651 let binder = Self { _lib: lib, vt, _class: am_class, service, tx_code: 0, legacy: false };
652 Ok((binder, consumer))
653 }
654
655 fn do_transact(&self) -> Result<OwnedParcel, CoreError> {
656 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
657 let s = unsafe { (self.vt.prepare_transaction)(self.service.ptr, &mut in_ptr) };
658 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_prepareTransaction")); }
659 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
660 let s = unsafe {
661 (self.vt.transact)(self.service.ptr, self.tx_code, &mut in_ptr, &mut out_ptr, 0)
662 };
663 let out = OwnedParcel { ptr: out_ptr, delete: self.vt.parcel_delete };
664 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_transact")); }
665 Ok(out)
666 }
667
668 pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
669 let out = self.do_transact()?;
670 let r = ParcelReader { vt: &self.vt, parcel: &out };
671 let ex = r.read_i32()?;
672 if ex != EX_NONE { return Err(CoreError::binder(ex, "getFocusedTask:exception")); }
673 let present = r.read_i32()?;
674 if present == 0 { return Ok(None); }
675 if self.legacy { parse_stack_info_body(&r) } else { parse_root_task_info_body(&r) }
676 }
677
678 pub fn get_focused_task_id(&self) -> Result<Option<i32>, CoreError> {
682 if self.legacy {
683 return Ok(None);
686 }
687 let out = self.do_transact()?;
688 let r = ParcelReader { vt: &self.vt, parcel: &out };
689 let ex = r.read_i32()?;
690 if ex != EX_NONE { return Err(CoreError::binder(ex, "getFocusedTaskId:exception")); }
691 let present = r.read_i32()?;
692 if present == 0 { return Ok(None); }
693 parse_root_task_info_task_id(&r)
694 }
695 }
696
697 const DISPLAY_SERVICE: &[u8] = b"display\0";
700 const DISPLAY_DESCRIPTOR: &[u8] = b"android.hardware.display.IDisplayManager\0";
701 const CALLBACK_DESCRIPTOR: &[u8] = b"android.hardware.display.IDisplayManagerCallback\0";
702 const POWER_SERVICE: &[u8] = b"power\0";
703
704 const TX_DISPLAY_REGISTER_CALLBACK: u32 = 4;
705
706 static DISP_EVENTFD: Mutex<Option<OwnedFd>> = Mutex::new(None);
709
710 fn disp_eventfd_guard() -> std::sync::MutexGuard<'static, Option<OwnedFd>> {
711 DISP_EVENTFD.lock().unwrap_or_else(|p| p.into_inner())
712 }
713
714 unsafe extern "C" fn disp_cb_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
715 unsafe extern "C" fn disp_cb_on_destroy(_: *mut c_void) {}
716 unsafe extern "C" fn disp_cb_on_transact(
717 _: *mut AIBinder, code: u32, _: *const AParcel, _: *mut AParcel,
718 ) -> BinderStatus {
719 if code == 1 {
720 if let Some(fd) = disp_eventfd_guard().as_ref() {
721 let val: u64 = 1;
722 unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
723 }
724 }
725 STATUS_OK
726 }
727
728 pub struct DisplayManagerBinder {
729 _lib: DlHandle,
730 vt: Vtable,
731 display: OwnedBinder,
732 power: Option<OwnedBinder>,
733 is_interactive_tx: u32,
734 }
735 unsafe impl Send for DisplayManagerBinder {}
736
737 impl DisplayManagerBinder {
738 pub fn open_with_callback() -> Result<(Self, crate::reactor::Fd), CoreError> {
739 let handle = unsafe {
740 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
741 };
742 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
743 let lib = DlHandle(handle);
744 let vt = load_vtable(handle)?;
745
746 let owned = unsafe {
750 let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
751 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
752 OwnedFd::from_raw_fd(raw)
753 };
754
755 let raw_display = unsafe { (vt.get_service)(DISPLAY_SERVICE.as_ptr() as *const c_char) };
757 if raw_display.is_null() {
758 return Err(CoreError::binder(-1, "AServiceManager_getService:display"));
759 }
760 let display = OwnedBinder { ptr: raw_display, dec_strong: vt.dec_strong };
761
762 let cb_class = unsafe {
764 (vt.class_define)(
765 CALLBACK_DESCRIPTOR.as_ptr() as *const c_char,
766 disp_cb_on_create, disp_cb_on_destroy, disp_cb_on_transact,
767 )
768 };
769 if cb_class.is_null() {
770 return Err(CoreError::binder(-1, "AIBinder_Class_define:DisplayCallback"));
771 }
772
773 let cb_binder = unsafe { (vt.new_binder)(cb_class, std::ptr::null_mut()) };
774 if cb_binder.is_null() {
775 return Err(CoreError::binder(-1, "AIBinder_new:DisplayCallback"));
776 }
777
778 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
780 let s = unsafe { (vt.prepare_transaction)(display.ptr, &mut in_ptr) };
781 if s != STATUS_OK {
782 return Err(CoreError::binder(s, "prepareTransaction:registerCallback"));
783 }
784 unsafe { (vt.write_strong_binder)(in_ptr, cb_binder) };
785 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
786 let s = unsafe {
787 (vt.transact)(display.ptr, TX_DISPLAY_REGISTER_CALLBACK, &mut in_ptr, &mut out_ptr, 0)
788 };
789 if !out_ptr.is_null() { unsafe { (vt.parcel_delete)(out_ptr) }; }
790 if s != STATUS_OK {
791 return Err(CoreError::binder(s, "transact:registerCallback"));
792 }
793
794 let power = {
796 let raw = unsafe { (vt.get_service)(POWER_SERVICE.as_ptr() as *const c_char) };
797 if raw.is_null() { None } else { Some(OwnedBinder { ptr: raw, dec_strong: vt.dec_strong }) }
798 };
799
800 let is_interactive_tx = crate::dex::resolve_is_interactive_tx()
802 .ok_or_else(|| CoreError::binder(-1, "dex:TRANSACTION_isInteractive not found"))?;
803
804 let efd_owned = owned.try_clone()
807 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:display"))
808 .and_then(|dup| unsafe {
809 crate::reactor::Fd::from_owned_raw_fd(dup.into_raw_fd(), "display.efd")
810 .map_err(|_| CoreError::binder(-1, "Fd::from_owned_raw_fd:display.efd"))
811 })?;
812
813 *disp_eventfd_guard() = Some(owned);
815
816 unsafe { (vt.set_thread_pool_max)(0) };
818 let join_fn = vt.join_thread_pool;
819 std::thread::spawn(move || unsafe { join_fn() });
820
821 Ok((Self { _lib: lib, vt, display, power, is_interactive_tx }, efd_owned))
822 }
823
824 pub fn is_interactive(&self) -> Result<bool, CoreError> {
825 let power = self.power.as_ref()
826 .ok_or_else(|| CoreError::binder(-1, "power:unavailable"))?;
827 let mut inp: *mut AParcel = std::ptr::null_mut();
828 let s = unsafe { (self.vt.prepare_transaction)(power.ptr, &mut inp) };
829 if s != STATUS_OK { return Err(CoreError::binder(s, "prepareTransaction:isInteractive")); }
830 let mut out: *mut AParcel = std::ptr::null_mut();
831 let s = unsafe {
832 (self.vt.transact)(power.ptr, self.is_interactive_tx, &mut inp, &mut out, 0)
833 };
834 let out = OwnedParcel { ptr: out, delete: self.vt.parcel_delete };
835 if s != STATUS_OK { return Err(CoreError::binder(s, "transact:isInteractive")); }
836 let r = ParcelReader { vt: &self.vt, parcel: &out };
837 let ex = r.read_i32()?;
838 if ex != EX_NONE { return Err(CoreError::binder(ex, "isInteractive:exception")); }
839 if let Some(rb) = self.vt.read_bool {
840 let mut v = false;
841 let s = unsafe { rb(out.ptr as *const AParcel, &mut v) };
842 if s != STATUS_OK { return Err(CoreError::binder(s, "readBool:isInteractive")); }
843 Ok(v)
844 } else {
845 Ok(r.read_i32()? != 0)
846 }
847 }
848 }
849
850 const WINDOW_SERVICE: &[u8] = b"window\0";
853 const WM_DESCRIPTOR: &[u8] = b"android.view.IWindowManager\0";
854 const FPS_DESCRIPTOR: &[u8] = b"android.window.ITaskFpsCallback\0";
855 static FPS_EVENTFD: Mutex<Option<OwnedFd>> = Mutex::new(None);
860 static FPS_VALUE: AtomicU32 = AtomicU32::new(0);
861 static FPS_CODE: AtomicU32 = AtomicU32::new(0);
862 static FPS_READ_I32: AtomicUsize = AtomicUsize::new(0);
863
864 fn fps_eventfd_guard() -> std::sync::MutexGuard<'static, Option<OwnedFd>> {
865 FPS_EVENTFD.lock().unwrap_or_else(|p| p.into_inner())
866 }
867
868 unsafe extern "C" fn wm_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
872 unsafe extern "C" fn wm_on_destroy(_: *mut c_void) {}
873 unsafe extern "C" fn wm_on_transact(
874 _: *mut AIBinder, _: u32, _: *const AParcel, _: *mut AParcel,
875 ) -> BinderStatus { STATUS_OK }
876
877 unsafe extern "C" fn fps_on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
878 unsafe extern "C" fn fps_on_destroy(_: *mut c_void) {}
879 unsafe extern "C" fn fps_on_transact(
880 _: *mut AIBinder, code: u32, in_parcel: *const AParcel, _: *mut AParcel,
881 ) -> BinderStatus {
882 if code != FPS_CODE.load(Ordering::Relaxed) {
883 return STATUS_UNKNOWN_TRANSACTION;
884 }
885 let read_addr = FPS_READ_I32.load(Ordering::Relaxed);
888 if read_addr != 0 {
889 let read_fn: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus =
890 unsafe { std::mem::transmute(read_addr) };
891 let mut bits: i32 = 0;
892 if unsafe { read_fn(in_parcel, &mut bits) } == STATUS_OK {
893 FPS_VALUE.store(bits as u32, Ordering::Relaxed);
896 if let Some(fd) = fps_eventfd_guard().as_ref() {
897 let val: u64 = 1;
898 unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
899 }
900 }
901 }
902 STATUS_OK
903 }
904
905 pub struct FpsListener {
919 _lib: DlHandle,
920 vt: Vtable,
921 window: OwnedBinder,
922 cb_binder: *mut AIBinder,
923 _wm_class: *mut AIBinder_Class,
924 register_code: u32,
925 unregister_code: u32,
926 task_id: i32,
927 }
928 unsafe impl Send for FpsListener {}
929
930 impl FpsListener {
931 pub fn open() -> Result<(Self, OwnedFd), CoreError> {
937 let handle = unsafe {
938 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
939 };
940 if handle.is_null() { return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so")); }
941 let lib = DlHandle(handle);
942 let vt = load_vtable(handle)?;
943
944 let (register_code, unregister_code, on_fps_code) =
945 crate::dex::resolve_fps_codes()
946 .ok_or_else(|| CoreError::binder(-1, "dex:TRANSACTION_registerTaskFpsCallback not found"))?;
947
948 let window = {
949 let raw = unsafe { (vt.get_service)(WINDOW_SERVICE.as_ptr() as *const c_char) };
950 if raw.is_null() { return Err(CoreError::binder(-1, "AServiceManager_getService:window")); }
951 OwnedBinder { ptr: raw, dec_strong: vt.dec_strong }
952 };
953
954 let wm_class = unsafe {
957 (vt.class_define)(
958 WM_DESCRIPTOR.as_ptr() as *const c_char,
959 wm_on_create, wm_on_destroy, wm_on_transact,
960 )
961 };
962 if wm_class.is_null() {
963 return Err(CoreError::binder(-1, "AIBinder_Class_define:IWindowManager"));
964 }
965 unsafe { (vt.associate_class)(window.ptr, wm_class) };
966
967 let cb_class = unsafe {
968 (vt.class_define)(
969 FPS_DESCRIPTOR.as_ptr() as *const c_char,
970 fps_on_create, fps_on_destroy, fps_on_transact,
971 )
972 };
973 if cb_class.is_null() {
974 return Err(CoreError::binder(-1, "AIBinder_Class_define:ITaskFpsCallback"));
975 }
976
977 let cb_binder = unsafe { (vt.new_binder)(cb_class, std::ptr::null_mut()) };
978 if cb_binder.is_null() {
979 return Err(CoreError::binder(-1, "AIBinder_new:ITaskFpsCallback"));
980 }
981 unsafe { (vt.associate_class)(cb_binder, cb_class) };
982
983 let owned = unsafe {
986 let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
987 if raw < 0 { return Err(CoreError::sys(*libc::__errno(), "eventfd")); }
988 OwnedFd::from_raw_fd(raw)
989 };
990
991 let consumer = owned.try_clone()
992 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:fps"))?;
993
994 FPS_READ_I32.store(vt.read_int32 as usize, Ordering::Relaxed);
997 FPS_CODE.store(on_fps_code, Ordering::Relaxed);
998 FPS_VALUE.store(0, Ordering::Relaxed);
999 *fps_eventfd_guard() = Some(owned);
1000
1001 unsafe { (vt.set_thread_pool_max)(0) };
1002 let join_fn = vt.join_thread_pool;
1003 std::thread::spawn(move || unsafe { join_fn() });
1004
1005 Ok((Self {
1006 _lib: lib, vt, window, cb_binder, _wm_class: wm_class,
1007 register_code, unregister_code, task_id: -1,
1008 }, consumer))
1009 }
1010
1011 pub fn register(&mut self, task_id: i32) -> Result<(), CoreError> {
1015 if self.task_id == task_id {
1016 return Ok(());
1017 }
1018 if self.task_id >= 0 {
1019 let _ = self.unregister();
1020 }
1021
1022 let mut inp: *mut AParcel = std::ptr::null_mut();
1023 let s = unsafe { (self.vt.prepare_transaction)(self.window.ptr, &mut inp) };
1024 if s != STATUS_OK { return Err(CoreError::binder(s, "prepareTransaction:registerTaskFpsCallback")); }
1025 let s = unsafe { (self.vt.write_int32)(inp, task_id) };
1026 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_writeInt32:taskId")); }
1027 let s = unsafe { (self.vt.write_strong_binder)(inp, self.cb_binder) };
1028 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_writeStrongBinder")); }
1029 let mut out: *mut AParcel = std::ptr::null_mut();
1030 let s = unsafe {
1031 (self.vt.transact)(self.window.ptr, self.register_code, &mut inp, &mut out, 0)
1032 };
1033 if !out.is_null() { unsafe { (self.vt.parcel_delete)(out) }; }
1034 if s != STATUS_OK {
1035 return Err(CoreError::binder(s, "transact:registerTaskFpsCallback"));
1036 }
1037 self.task_id = task_id;
1038 Ok(())
1039 }
1040
1041 pub fn unregister(&mut self) -> Result<(), CoreError> {
1044 if self.task_id < 0 {
1045 return Ok(());
1046 }
1047 let mut inp: *mut AParcel = std::ptr::null_mut();
1048 let s = unsafe { (self.vt.prepare_transaction)(self.window.ptr, &mut inp) };
1049 if s != STATUS_OK { return Err(CoreError::binder(s, "prepareTransaction:unregisterTaskFpsCallback")); }
1050 let s = unsafe { (self.vt.write_strong_binder)(inp, self.cb_binder) };
1051 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_writeStrongBinder")); }
1052 let mut out: *mut AParcel = std::ptr::null_mut();
1053 let s = unsafe {
1054 (self.vt.transact)(self.window.ptr, self.unregister_code, &mut inp, &mut out, 0)
1055 };
1056 if !out.is_null() { unsafe { (self.vt.parcel_delete)(out) }; }
1057 if s != STATUS_OK {
1058 return Err(CoreError::binder(s, "transact:unregisterTaskFpsCallback"));
1059 }
1060 self.task_id = -1;
1061 Ok(())
1062 }
1063
1064 pub fn last_fps(&self) -> Option<f32> {
1068 let bits = FPS_VALUE.load(Ordering::Relaxed);
1069 if bits == 0 { None } else { Some(f32::from_bits(bits)) }
1070 }
1071
1072 pub fn task_id(&self) -> Option<i32> {
1074 (self.task_id >= 0).then_some(self.task_id)
1075 }
1076 }
1077
1078 pub struct RawBinderService {
1087 _lib: DlHandle,
1088 vt: Vtable,
1089 service: OwnedBinder,
1090 }
1091 unsafe impl Send for RawBinderService {}
1092
1093 impl RawBinderService {
1094 pub fn open(service_name: &str) -> Result<Self, CoreError> {
1096 use std::ffi::CString;
1097 let handle = unsafe {
1098 libc::dlopen(LIBBINDER_PATH.as_ptr() as *const c_char, libc::RTLD_NOW | libc::RTLD_LOCAL)
1099 };
1100 if handle.is_null() {
1101 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
1102 }
1103 let lib = DlHandle(handle);
1104 let vt = load_vtable(handle)?;
1105 let cs = CString::new(service_name)
1106 .map_err(|_| CoreError::binder(-1, "service_name:nul_byte"))?;
1107 let raw = unsafe { (vt.get_service)(cs.as_ptr()) };
1108 if raw.is_null() {
1109 return Err(CoreError::binder(-1, "AServiceManager_getService:null"));
1110 }
1111 let service = OwnedBinder { ptr: raw, dec_strong: vt.dec_strong };
1112 Ok(Self { _lib: lib, vt, service })
1113 }
1114
1115 pub fn transact_bool(&self, code: u32) -> Result<bool, CoreError> {
1117 let out = self.raw_noarg(code)?;
1118 let r = ParcelReader { vt: &self.vt, parcel: &out };
1119 let ex = r.read_i32()?;
1120 if ex != EX_NONE { return Err(CoreError::binder(ex, "transact_bool:exception")); }
1121 if let Some(rb) = self.vt.read_bool {
1122 let mut v = false;
1123 let s = unsafe { rb(out.ptr as *const AParcel, &mut v) };
1124 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readBool")); }
1125 Ok(v)
1126 } else {
1127 Ok(r.read_i32()? != 0)
1128 }
1129 }
1130
1131 pub fn transact_i32(&self, code: u32, arg: i32) -> Result<(), CoreError> {
1133 let mut inp: *mut AParcel = std::ptr::null_mut();
1134 let s = unsafe { (self.vt.prepare_transaction)(self.service.ptr, &mut inp) };
1135 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_prepareTransaction")); }
1136 let s = unsafe { (self.vt.write_int32)(inp, arg) };
1137 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_writeInt32")); }
1138 let mut out: *mut AParcel = std::ptr::null_mut();
1139 let s = unsafe { (self.vt.transact)(self.service.ptr, code, &mut inp, &mut out, 0) };
1140 if !out.is_null() { unsafe { (self.vt.parcel_delete)(out) }; }
1141 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_transact")); }
1142 Ok(())
1143 }
1144
1145 fn raw_noarg(&self, code: u32) -> Result<OwnedParcel, CoreError> {
1146 let mut inp: *mut AParcel = std::ptr::null_mut();
1147 let s = unsafe { (self.vt.prepare_transaction)(self.service.ptr, &mut inp) };
1148 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_prepareTransaction")); }
1149 let mut out: *mut AParcel = std::ptr::null_mut();
1150 let s = unsafe { (self.vt.transact)(self.service.ptr, code, &mut inp, &mut out, 0) };
1151 let out = OwnedParcel { ptr: out, delete: self.vt.parcel_delete };
1152 if s != STATUS_OK { return Err(CoreError::binder(s, "AIBinder_transact")); }
1153 Ok(out)
1154 }
1155 }
1156}
1157
1158#[cfg(target_os = "android")]
1161pub use imp::{ActivityManagerBinder, DisplayManagerBinder, FpsListener, RawBinderService, TxCodes, last_foreground_pid, resolve_tx_codes};
1162
1163#[cfg(not(target_os = "android"))]
1166pub struct ActivityManagerBinder;
1167
1168#[cfg(not(target_os = "android"))]
1169impl ActivityManagerBinder {
1170 pub fn open() -> Result<Self, crate::CoreError> {
1171 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1172 }
1173 pub fn open_with_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1174 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1175 }
1176 pub fn open_with_fgproc_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1177 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1178 }
1179 pub fn get_focused_package(&self) -> Result<Option<String>, crate::CoreError> {
1180 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1181 }
1182 pub fn get_focused_task_id(&self) -> Result<Option<i32>, crate::CoreError> {
1183 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1184 }
1185}
1186
1187#[cfg(not(target_os = "android"))]
1188pub struct DisplayManagerBinder;
1189
1190#[cfg(not(target_os = "android"))]
1191impl DisplayManagerBinder {
1192 pub fn open_with_callback() -> Result<(Self, crate::reactor::Fd), crate::CoreError> {
1193 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1194 }
1195 pub fn is_interactive(&self) -> Result<bool, crate::CoreError> {
1196 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1197 }
1198}
1199
1200#[cfg(not(target_os = "android"))]
1201pub struct RawBinderService;
1202
1203#[cfg(not(target_os = "android"))]
1204impl RawBinderService {
1205 pub fn open(_service_name: &str) -> Result<Self, crate::CoreError> {
1206 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1207 }
1208 pub fn transact_bool(&self, _code: u32) -> Result<bool, crate::CoreError> {
1209 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1210 }
1211 pub fn transact_i32(&self, _code: u32, _arg: i32) -> Result<(), crate::CoreError> {
1212 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1213 }
1214}
1215
1216#[cfg(not(target_os = "android"))]
1217pub struct FpsListener;
1218
1219#[cfg(not(target_os = "android"))]
1220impl FpsListener {
1221 pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
1222 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1223 }
1224 pub fn register(&mut self, _task_id: i32) -> Result<(), crate::CoreError> {
1225 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1226 }
1227 pub fn unregister(&mut self) -> Result<(), crate::CoreError> {
1228 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1229 }
1230 pub fn last_fps(&self) -> Option<f32> {
1231 None
1232 }
1233 pub fn task_id(&self) -> Option<i32> {
1234 None
1235 }
1236}
1237
1238#[cfg(not(target_os = "android"))]
1239pub struct TxCodes { pub observer_code: u32, pub query_code: u32, pub api_mode: u8, pub fg_code: u32 }
1240
1241#[cfg(not(target_os = "android"))]
1242pub fn resolve_tx_codes() -> Result<TxCodes, crate::CoreError> {
1243 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
1244}
1245
1246#[cfg(not(target_os = "android"))]
1247pub fn last_foreground_pid() -> i32 {
1248 0
1249}