1#[cfg(target_os = "android")]
27mod imp {
28 use crate::CoreError;
29 use crate::android::dex;
30 use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd};
31 use std::os::raw::{c_char, c_void};
32 use std::sync::Mutex;
33 use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU32, AtomicUsize, Ordering};
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 {
103 std::ptr::null_mut()
104 }
105 unsafe extern "C" fn am_on_destroy(_: *mut c_void) {}
106 unsafe extern "C" fn am_on_transact(
107 _: *mut AIBinder,
108 _: u32,
109 _: *const AParcel,
110 _: *mut AParcel,
111 ) -> BinderStatus {
112 STATUS_UNKNOWN_TRANSACTION
113 }
114
115 unsafe extern "C" fn obs_on_create(_: *mut c_void) -> *mut c_void {
117 std::ptr::null_mut()
118 }
119 unsafe extern "C" fn obs_on_destroy(_: *mut c_void) {}
120 unsafe extern "C" fn obs_on_transact(
121 _: *mut AIBinder,
122 code: u32,
123 _: *const AParcel,
124 _: *mut AParcel,
125 ) -> BinderStatus {
126 if code == OBS_FG_CODE.load(Ordering::Relaxed) {
127 if let Some(fd) = obs_eventfd_guard().as_ref() {
130 let val: u64 = 1;
131 unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
132 }
133 }
134 STATUS_OK
135 }
136
137 unsafe extern "C" fn fgproc_on_create(_: *mut c_void) -> *mut c_void {
146 std::ptr::null_mut()
147 }
148 unsafe extern "C" fn fgproc_on_destroy(_: *mut c_void) {}
149 unsafe extern "C" fn fgproc_on_transact(
150 _: *mut AIBinder,
151 code: u32,
152 in_parcel: *const AParcel,
153 _: *mut AParcel,
154 ) -> BinderStatus {
155 if code != FGPROC_FG_CODE.load(Ordering::Relaxed) {
156 return STATUS_UNKNOWN_TRANSACTION;
157 }
158 let read_addr = FGPROC_READ_I32.load(Ordering::Relaxed);
161 if read_addr != 0 {
162 let read_fn: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus =
163 unsafe { std::mem::transmute(read_addr) };
164 if FGPROC_IPROC_MODE.load(Ordering::Relaxed) == 1 {
165 let mut pid: i32 = 0;
167 let mut _uid: i32 = 0;
168 let mut fg: i32 = 0;
169 let mut ok = unsafe { read_fn(in_parcel, &mut pid) } == STATUS_OK;
170 ok &= unsafe { read_fn(in_parcel, &mut _uid) } == STATUS_OK;
171 ok &= unsafe { read_fn(in_parcel, &mut fg) } == STATUS_OK;
172 if ok {
173 FGPROC_PID.store(pid, Ordering::Relaxed);
174 if fg == 0 {
177 return STATUS_OK;
178 }
179 } else {
180 return STATUS_OK;
181 }
182 } else {
183 let mut pid: i32 = 0;
184 if unsafe { read_fn(in_parcel, &mut pid) } == STATUS_OK {
185 FGPROC_PID.store(pid, Ordering::Relaxed);
186 }
187 }
188 }
189 if let Some(fd) = fgproc_eventfd_guard().as_ref() {
192 let val: u64 = 1;
193 unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
194 }
195 STATUS_OK
196 }
197
198 pub fn last_foreground_pid() -> i32 {
201 FGPROC_PID.load(Ordering::Relaxed)
202 }
203
204 const MAX_BINDER_STRING_LEN: usize = 1024 * 1024;
211
212 unsafe extern "C" fn string_alloc(
213 cookie: *mut c_void,
214 length: i32,
215 buffer: *mut *mut c_char,
216 ) -> bool {
217 if length == -1 {
225 return true;
226 }
227 if length < 0 {
228 return false;
229 }
230 let len = length as usize;
231 if len > MAX_BINDER_STRING_LEN {
232 return false;
233 }
234 let s = unsafe { &mut *(cookie as *mut StringBuf) };
235 s.0.reserve_exact(len + 1);
236 unsafe { s.0.as_mut_vec().resize(len + 1, 0) };
237 unsafe { *buffer = s.0.as_mut_ptr() as *mut c_char };
238 true
239 }
240
241 struct StringBuf(String);
242 impl StringBuf {
243 fn new() -> Self {
244 Self(String::new())
245 }
246 fn finish(mut self) -> Option<String> {
247 if let Some(pos) = self.0.as_bytes().iter().position(|&b| b == 0) {
248 unsafe { self.0.as_mut_vec().truncate(pos) };
249 }
250 if self.0.is_empty() {
251 None
252 } else {
253 Some(self.0)
254 }
255 }
256 }
257
258 struct Vtable {
261 get_service: unsafe extern "C" fn(*const c_char) -> *mut AIBinder,
262 class_define: unsafe extern "C" fn(
263 *const c_char,
264 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
265 unsafe extern "C" fn(*mut c_void),
266 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
267 ) -> *mut AIBinder_Class,
268 associate_class: unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool,
269 new_binder: unsafe extern "C" fn(*const AIBinder_Class, *mut c_void) -> *mut AIBinder,
270 prepare_transaction: unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus,
271 transact: unsafe extern "C" fn(
272 *mut AIBinder,
273 u32,
274 *mut *mut AParcel,
275 *mut *mut AParcel,
276 u32,
277 ) -> BinderStatus,
278 dec_strong: unsafe extern "C" fn(*mut AIBinder),
279 parcel_delete: unsafe extern "C" fn(*mut AParcel),
280 read_int32: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus,
281 read_string:
282 unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus,
283 write_strong_binder: unsafe extern "C" fn(*mut AParcel, *mut AIBinder) -> BinderStatus,
284 set_thread_pool_max: unsafe extern "C" fn(u32),
285 join_thread_pool: unsafe extern "C" fn(),
286 get_user_data: unsafe extern "C" fn(*const AIBinder) -> *mut c_void,
287 write_int32: unsafe extern "C" fn(*mut AParcel, i32) -> BinderStatus,
288 read_float: Option<unsafe extern "C" fn(*const AParcel, *mut f32) -> BinderStatus>,
289 read_int64: Option<unsafe extern "C" fn(*const AParcel, *mut i64) -> BinderStatus>,
290 read_bool: Option<unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus>,
292 }
293
294 struct DlHandle;
297 unsafe impl Send for DlHandle {}
298 impl Drop for DlHandle {
299 fn drop(&mut self) {
300 }
306 }
307
308 struct OwnedParcel {
309 ptr: *mut AParcel,
310 delete: unsafe extern "C" fn(*mut AParcel),
311 }
312 impl Drop for OwnedParcel {
313 fn drop(&mut self) {
314 if !self.ptr.is_null() {
315 unsafe { (self.delete)(self.ptr) };
316 }
317 }
318 }
319
320 struct OwnedBinder {
321 ptr: *mut AIBinder,
322 dec_strong: unsafe extern "C" fn(*mut AIBinder),
323 }
324 unsafe impl Send for OwnedBinder {}
325 impl Drop for OwnedBinder {
326 fn drop(&mut self) {
327 if !self.ptr.is_null() {
328 unsafe { (self.dec_strong)(self.ptr) };
329 }
330 }
331 }
332
333 macro_rules! dlsym_fn {
336 ($handle:expr, $name:literal, $ty:ty) => {{
337 let sym =
338 unsafe { libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char) };
339 if sym.is_null() {
340 return Err(CoreError::binder(-1, concat!("dlsym:", $name)));
341 }
342 unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }
343 }};
344 }
345
346 macro_rules! dlsym_opt {
347 ($handle:expr, $name:literal, $ty:ty) => {{
348 let sym =
349 unsafe { libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char) };
350 if sym.is_null() {
351 None
352 } else {
353 Some(unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) })
354 }
355 }};
356 }
357
358 fn load_vtable(handle: *mut c_void) -> Result<Vtable, CoreError> {
359 Ok(Vtable {
360 get_service: dlsym_fn!(
361 handle,
362 "AServiceManager_getService",
363 unsafe extern "C" fn(*const c_char) -> *mut AIBinder
364 ),
365 class_define: dlsym_fn!(
366 handle,
367 "AIBinder_Class_define",
368 unsafe extern "C" fn(
369 *const c_char,
370 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
371 unsafe extern "C" fn(*mut c_void),
372 unsafe extern "C" fn(
373 *mut AIBinder,
374 u32,
375 *const AParcel,
376 *mut AParcel,
377 ) -> BinderStatus,
378 ) -> *mut AIBinder_Class
379 ),
380 associate_class: dlsym_fn!(
381 handle,
382 "AIBinder_associateClass",
383 unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool
384 ),
385 new_binder: dlsym_fn!(
386 handle,
387 "AIBinder_new",
388 unsafe extern "C" fn(*const AIBinder_Class, *mut c_void) -> *mut AIBinder
389 ),
390 prepare_transaction: dlsym_fn!(
391 handle,
392 "AIBinder_prepareTransaction",
393 unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus
394 ),
395 transact: dlsym_fn!(
396 handle,
397 "AIBinder_transact",
398 unsafe extern "C" fn(
399 *mut AIBinder,
400 u32,
401 *mut *mut AParcel,
402 *mut *mut AParcel,
403 u32,
404 ) -> BinderStatus
405 ),
406 dec_strong: dlsym_fn!(
407 handle,
408 "AIBinder_decStrong",
409 unsafe extern "C" fn(*mut AIBinder)
410 ),
411 parcel_delete: dlsym_fn!(handle, "AParcel_delete", unsafe extern "C" fn(*mut AParcel)),
412 read_int32: dlsym_fn!(
413 handle,
414 "AParcel_readInt32",
415 unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus
416 ),
417 read_string: dlsym_fn!(
418 handle,
419 "AParcel_readString",
420 unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus
421 ),
422 write_strong_binder: dlsym_fn!(
423 handle,
424 "AParcel_writeStrongBinder",
425 unsafe extern "C" fn(*mut AParcel, *mut AIBinder) -> BinderStatus
426 ),
427 set_thread_pool_max: dlsym_fn!(
428 handle,
429 "ABinderProcess_setThreadPoolMaxThreadCount",
430 unsafe extern "C" fn(u32)
431 ),
432 join_thread_pool: dlsym_fn!(
433 handle,
434 "ABinderProcess_joinThreadPool",
435 unsafe extern "C" fn()
436 ),
437 get_user_data: dlsym_fn!(
438 handle,
439 "AIBinder_getUserData",
440 unsafe extern "C" fn(*const AIBinder) -> *mut c_void
441 ),
442 write_int32: dlsym_fn!(
443 handle,
444 "AParcel_writeInt32",
445 unsafe extern "C" fn(*mut AParcel, i32) -> BinderStatus
446 ),
447 read_bool: dlsym_opt!(
448 handle,
449 "AParcel_readBool",
450 unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus
451 ),
452 read_float: dlsym_opt!(
453 handle,
454 "AParcel_readFloat",
455 unsafe extern "C" fn(*const AParcel, *mut f32) -> BinderStatus
456 ),
457 read_int64: dlsym_opt!(
458 handle,
459 "AParcel_readInt64",
460 unsafe extern "C" fn(*const AParcel, *mut i64) -> BinderStatus
461 ),
462 })
463 }
464
465 struct ParcelReader<'a> {
468 vt: &'a Vtable,
469 parcel: &'a OwnedParcel,
470 }
471
472 impl<'a> ParcelReader<'a> {
473 fn read_i32(&self) -> Result<i32, CoreError> {
474 let mut v = 0i32;
475 let s = unsafe { (self.vt.read_int32)(self.parcel.ptr, &mut v) };
476 if s != STATUS_OK {
477 return Err(CoreError::binder(s, "AParcel_readInt32"));
478 }
479 Ok(v)
480 }
481 fn read_string(&self) -> Result<Option<String>, CoreError> {
487 let mut buf = StringBuf::new();
488 let s = unsafe {
489 (self.vt.read_string)(
490 self.parcel.ptr,
491 &mut buf as *mut StringBuf as *mut c_void,
492 string_alloc,
493 )
494 };
495 if s != STATUS_OK {
496 return Err(CoreError::binder(s, "AParcel_readString"));
497 }
498 Ok(buf.finish())
499 }
500 fn read_float(&self) -> Result<f32, CoreError> {
501 let r = self
502 .vt
503 .read_float
504 .ok_or_else(|| CoreError::binder(-1, "AParcel_readFloat:unavailable"))?;
505 let mut v = 0f32;
506 let s = unsafe { r(self.parcel.ptr, &mut v) };
507 if s != STATUS_OK {
508 return Err(CoreError::binder(s, "AParcel_readFloat"));
509 }
510 Ok(v)
511 }
512 fn read_int64(&self) -> Result<i64, CoreError> {
513 let r = self
514 .vt
515 .read_int64
516 .ok_or_else(|| CoreError::binder(-1, "AParcel_readInt64:unavailable"))?;
517 let mut v = 0i64;
518 let s = unsafe { r(self.parcel.ptr, &mut v) };
519 if s != STATUS_OK {
520 return Err(CoreError::binder(s, "AParcel_readInt64"));
521 }
522 Ok(v)
523 }
524 fn read_bool(&self) -> Result<bool, CoreError> {
525 if let Some(rb) = self.vt.read_bool {
526 let mut v = false;
527 let s = unsafe { rb(self.parcel.ptr, &mut v) };
528 if s != STATUS_OK {
529 return Err(CoreError::binder(s, "AParcel_readBool"));
530 }
531 Ok(v)
532 } else {
533 Ok(self.read_i32()? != 0)
534 }
535 }
536 fn skip_i32s(&self, n: usize) -> Result<(), CoreError> {
537 for _ in 0..n {
538 self.read_i32()?;
539 }
540 Ok(())
541 }
542 fn skip_int_array(&self) -> Result<(), CoreError> {
543 let count = self.read_i32()?.max(0) as usize;
544 self.skip_i32s(count)
545 }
546 fn skip_bytes(&self, n: usize) -> Result<(), CoreError> {
550 self.skip_i32s(n.div_ceil(4))
551 }
552 fn skip_string16(&self) -> Result<bool, CoreError> {
558 let len = self.read_i32()?;
559 if len < 0 {
560 return Ok(false);
561 }
562 let bytes = ((len as usize).saturating_add(1)).saturating_mul(2);
565 self.skip_bytes(bytes)?;
566 Ok(true)
567 }
568 fn skip_string8(&self) -> Result<bool, CoreError> {
574 let len = self.read_i32()?;
575 if len < 0 {
576 return Ok(false);
577 }
578 let bytes = (len as usize).saturating_add(1);
579 self.skip_bytes(bytes)?;
580 Ok(true)
581 }
582 fn skip_value(&self) -> Result<(), CoreError> {
590 let tag = self.read_i32()?;
591 match tag {
592 -1 => Ok(()),
594 0 => self.skip_string16().map(|_| ()),
596 1 | 5 | 9 | 20 | 29 => self.read_i32().map(|_| ()),
599 6 => self.read_int64().map(|_| ()),
601 7 => self.read_float().map(|_| ()),
603 8 => {
605 self.read_i32()?;
606 self.read_i32()?;
607 Ok(())
608 }
609 26 => self.skip_i32s(2),
611 27 => {
613 self.read_float()?;
614 self.read_float()?;
615 Ok(())
616 }
617 4 => {
621 let len = self.read_i32()?;
622 if len < 0 {
623 return Ok(());
624 }
625 self.skip_bytes(len as usize)
626 }
627 _ => Err(CoreError::binder(
628 tag,
629 "display_info:unsupported readValue tag",
630 )),
631 }
632 }
633 fn skip_typed_rect(&self) -> Result<(), CoreError> {
637 match self.read_i32()? {
638 0 => Ok(()),
639 1 => self.skip_i32s(4),
640 m => Err(CoreError::binder(m, "display_info:bad typed Rect marker")),
641 }
642 }
643 fn read_first_package_from_names(&self) -> Result<Option<String>, CoreError> {
644 let count = self.read_i32()?.max(0) as usize;
645 let mut first: Option<String> = None;
646 for _ in 0..count {
647 let s = self.read_string()?;
648 if first.is_none() {
649 first = s.and_then(|c| c.split('/').next().map(str::to_owned));
650 }
651 }
652 Ok(first)
653 }
654 }
655
656 struct ParcelWriter<'a> {
659 vt: &'a Vtable,
660 parcel: &'a OwnedParcel,
661 }
662
663 impl<'a> ParcelWriter<'a> {
664 fn write_i32(&self, v: i32) -> Result<(), CoreError> {
665 let s = unsafe { (self.vt.write_int32)(self.parcel.ptr, v) };
666 if s != STATUS_OK {
667 return Err(CoreError::binder(s, "AParcel_writeInt32"));
668 }
669 Ok(())
670 }
671 fn write_strong_binder(&self, b: *mut AIBinder) -> Result<(), CoreError> {
672 let s = unsafe { (self.vt.write_strong_binder)(self.parcel.ptr, b) };
673 if s != STATUS_OK {
674 return Err(CoreError::binder(s, "AParcel_writeStrongBinder"));
675 }
676 Ok(())
677 }
678 }
679
680 fn transact_write(
687 vt: &Vtable,
688 binder: *mut AIBinder,
689 code: u32,
690 writes: impl FnOnce(&ParcelWriter<'_>) -> Result<(), CoreError>,
691 ) -> Result<OwnedParcel, CoreError> {
692 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
693 let s = unsafe { (vt.prepare_transaction)(binder, &mut in_ptr) };
694 if s != STATUS_OK {
695 return Err(CoreError::binder(s, "AIBinder_prepareTransaction"));
696 }
697 let mut inp = OwnedParcel {
698 ptr: in_ptr,
699 delete: vt.parcel_delete,
700 };
701 {
702 let writer = ParcelWriter { vt, parcel: &inp };
703 writes(&writer)?;
704 }
705 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
706 let s = unsafe { (vt.transact)(binder, code, &mut inp.ptr, &mut out_ptr, 0) };
707 inp.ptr = std::ptr::null_mut();
709 let out = OwnedParcel {
710 ptr: out_ptr,
711 delete: vt.parcel_delete,
712 };
713 if s != STATUS_OK {
714 return Err(CoreError::binder(s, "AIBinder_transact"));
715 }
716 Ok(out)
717 }
718
719 fn parse_stack_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
722 r.skip_i32s(5)?;
723 r.skip_int_array()?;
724 r.read_first_package_from_names()
725 }
726
727 fn parse_root_task_info_task(r: &ParcelReader<'_>) -> Result<(i32, Option<String>), CoreError> {
734 let scratch = r.read_i32()?;
735 if scratch != 0 {
736 r.skip_i32s(4)?;
737 }
738 r.skip_int_array()?; let pkg = r.read_first_package_from_names()?; let bounds_count = r.read_i32()?;
742 let n = if bounds_count < 0 {
743 0
744 } else {
745 bounds_count as usize
746 };
747 for _ in 0..n {
748 let entry = r.read_i32()?;
749 if entry != 0 {
750 r.skip_i32s(4)?;
751 }
752 }
753 r.skip_int_array()?; r.skip_i32s(2)?; r.skip_i32s(1)?; let task_id = r.read_i32()?;
757 Ok((task_id, pkg))
758 }
759
760 struct ParsedDisplayInfo {
763 active_mode_id: i32,
764 vsync_rate: f32,
765 peak_refresh_rate: f32,
766 render_frame_rate: f32,
767 }
768
769 fn parse_display_info(r: &ParcelReader<'_>) -> Result<ParsedDisplayInfo, CoreError> {
791 r.skip_i32s(5)?;
794
795 if let Some(addr_class) = r.read_string()? {
801 if addr_class.ends_with("$Physical") {
802 r.read_int64()?;
803 } else if addr_class.ends_with("$Network") {
804 r.skip_string16()?;
805 } else {
806 return Err(CoreError::binder(
807 -1,
808 "display_info:unsupported DisplayAddress",
809 ));
810 }
811 }
812
813 if let Some(_dpi_class) = r.read_string()? {
821 r.skip_string16()?; r.skip_string16()?; r.skip_value()?; r.skip_value()?; r.skip_value()?; r.read_i32()?; }
828
829 r.skip_string8()?;
832
833 r.skip_i32s(8)?;
837
838 let cutout_marker = r.read_i32()?;
844 if cutout_marker == 1 {
845 r.skip_typed_rect()?; let bounds = r.read_i32()?; if bounds >= 0 {
848 for _ in 0..bounds {
849 r.skip_typed_rect()?;
850 }
851 }
852 r.skip_typed_rect()?; r.skip_i32s(4)?; r.read_float()?; r.skip_string16()?; r.read_i32()?; r.read_float()?; r.read_float()?; }
860
861 r.read_i32()?; let active_mode_id = r.read_i32()?;
865 let render_frame_rate = {
866 let v = r.read_float()?;
867 if v.is_finite() && v >= 0.0 { v } else { 0.0 }
868 };
869 r.read_i32()?; let n_modes = r.read_i32()?.max(0) as usize;
871
872 let mut vsync_rate: f32 = 0.0;
876 let mut peak_refresh_rate: f32 = 0.0;
877 for _ in 0..n_modes {
878 let mode_id = r.read_i32()?;
879 r.read_i32()?; r.read_i32()?; let refresh_rate = {
882 let v = r.read_float()?;
883 if v.is_finite() && v >= 0.0 { v } else { 0.0 }
886 };
887 let alt = r.read_i32()?.max(0) as usize;
889 for _ in 0..alt {
890 let _f = r.read_float()?;
891 }
892 let hdr = r.read_i32()?.max(0) as usize;
894 for _ in 0..hdr {
895 r.read_i32()?;
896 }
897 peak_refresh_rate = peak_refresh_rate.max(refresh_rate);
898 if mode_id == active_mode_id {
899 vsync_rate = refresh_rate.max(vsync_rate);
900 }
901 }
902
903 Ok(ParsedDisplayInfo {
904 active_mode_id,
905 vsync_rate,
906 peak_refresh_rate,
907 render_frame_rate,
908 })
909 }
910
911 pub struct TxCodes {
914 pub observer_code: u32,
915 pub query_code: u32,
916 pub api_mode: u8, pub fg_code: u32,
918 }
919
920 pub fn resolve_tx_codes() -> Result<TxCodes, CoreError> {
921 let (obs, query, api, fg) = dex::resolve_tx_codes_from_dex()
922 .ok_or_else(|| CoreError::binder(-1, "tx_code_resolution:dex_parse_failed"))?;
923 Ok(TxCodes {
924 observer_code: obs,
925 query_code: query,
926 api_mode: api,
927 fg_code: fg,
928 })
929 }
930
931 pub struct ActivityManager {
934 _lib: DlHandle,
935 vt: Vtable,
936 _class: *mut AIBinder_Class,
937 service: OwnedBinder,
938 tx_code: u32,
939 legacy: bool,
940 }
941 unsafe impl Send for ActivityManager {}
942
943 impl ActivityManager {
944 fn open_inner(
945 handle: *mut c_void,
946 ) -> Result<(DlHandle, Vtable, *mut AIBinder_Class, OwnedBinder), CoreError> {
947 let lib = DlHandle;
948 let vt = load_vtable(handle)?;
949
950 let am_class = unsafe {
951 (vt.class_define)(
952 AM_DESCRIPTOR.as_ptr() as *const c_char,
953 am_on_create,
954 am_on_destroy,
955 am_on_transact,
956 )
957 };
958 if am_class.is_null() {
959 return Err(CoreError::binder(-1, "AIBinder_Class_define:AM"));
960 }
961
962 let raw = unsafe { (vt.get_service)(ACTIVITY_SERVICE.as_ptr() as *const c_char) };
963 if raw.is_null() {
964 return Err(CoreError::binder(-1, "AServiceManager_getService:activity"));
965 }
966 unsafe { (vt.associate_class)(raw, am_class) };
967
968 let service = OwnedBinder {
969 ptr: raw,
970 dec_strong: vt.dec_strong,
971 };
972 Ok((lib, vt, am_class, service))
973 }
974
975 fn dlopen_libbinder() -> Result<*mut c_void, CoreError> {
976 use std::os::raw::c_char;
977 let handle = unsafe {
978 libc::dlopen(
979 LIBBINDER_PATH.as_ptr() as *const c_char,
980 libc::RTLD_NOW | libc::RTLD_LOCAL,
981 )
982 };
983 if handle.is_null() {
984 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
985 }
986 Ok(handle)
987 }
988
989 pub fn open() -> Result<Self, CoreError> {
992 let handle = Self::dlopen_libbinder()?;
993 let (lib, vt, class, service) = Self::open_inner(handle)?;
994 let codes = resolve_tx_codes()?;
995 let legacy = codes.api_mode == 2;
996 Ok(Self {
997 _lib: lib,
998 vt,
999 _class: class,
1000 service,
1001 tx_code: codes.query_code,
1002 legacy,
1003 })
1004 }
1005
1006 pub fn open_with_observer() -> Result<(Self, OwnedFd), CoreError> {
1015 let handle = Self::dlopen_libbinder()?;
1016 let (lib, vt, am_class, service) = Self::open_inner(handle)?;
1017 let codes = resolve_tx_codes()?;
1018 let legacy = codes.api_mode == 2;
1019
1020 let owned = unsafe {
1023 let raw = libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC);
1024 if raw < 0 {
1025 return Err(CoreError::sys(*libc::__errno(), "eventfd"));
1026 }
1027 OwnedFd::from_raw_fd(raw)
1028 };
1029
1030 let obs_class = unsafe {
1032 (vt.class_define)(
1033 OBS_DESCRIPTOR.as_ptr() as *const c_char,
1034 obs_on_create,
1035 obs_on_destroy,
1036 obs_on_transact,
1037 )
1038 };
1039 if obs_class.is_null() {
1040 return Err(CoreError::binder(-1, "AIBinder_Class_define:Observer"));
1041 }
1042
1043 let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
1045 if obs_binder.is_null() {
1046 return Err(CoreError::binder(-1, "AIBinder_new:Observer"));
1047 }
1048 unsafe { (vt.associate_class)(obs_binder, obs_class) };
1049
1050 let _ = transact_write(&vt, service.ptr, codes.observer_code, |w| {
1052 w.write_strong_binder(obs_binder)
1053 })?;
1054
1055 let consumer = owned
1058 .try_clone()
1059 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:observer"))?;
1060
1061 OBS_FG_CODE.store(codes.fg_code, Ordering::Relaxed);
1063 *obs_eventfd_guard() = Some(owned);
1064
1065 unsafe { (vt.set_thread_pool_max)(0) };
1067 let join_fn = vt.join_thread_pool;
1068 std::thread::spawn(move || unsafe { join_fn() });
1069
1070 let binder = Self {
1071 _lib: lib,
1072 vt,
1073 _class: am_class,
1074 service,
1075 tx_code: codes.query_code,
1076 legacy,
1077 };
1078 Ok((binder, consumer))
1079 }
1080
1081 pub fn open_with_fgproc_observer() -> Result<(Self, OwnedFd), CoreError> {
1105 let handle = Self::dlopen_libbinder()?;
1106 let (lib, vt, am_class, service) = Self::open_inner(handle)?;
1107
1108 let (register_code, fgproc_code, mode, descriptor): (u32, u32, u32, &[u8]) =
1113 match crate::android::dex::resolve_fgproc_codes() {
1114 Some((r, c)) => (r, c, 0, FGPROC_DESCRIPTOR),
1115 None => match crate::android::dex::resolve_fgproc_codes_fallback() {
1116 Some((r, c)) => (r, c, 1, OBS_DESCRIPTOR),
1117 None => {
1118 return Err(CoreError::binder(
1119 -1,
1120 "tx_code_resolution:fgproc_dex_parse_failed",
1121 ));
1122 }
1123 },
1124 };
1125
1126 let owned = unsafe {
1129 let raw = libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC);
1130 if raw < 0 {
1131 return Err(CoreError::sys(*libc::__errno(), "eventfd"));
1132 }
1133 OwnedFd::from_raw_fd(raw)
1134 };
1135
1136 let obs_class = unsafe {
1139 (vt.class_define)(
1140 descriptor.as_ptr() as *const c_char,
1141 fgproc_on_create,
1142 fgproc_on_destroy,
1143 fgproc_on_transact,
1144 )
1145 };
1146 if obs_class.is_null() {
1147 return Err(CoreError::binder(
1148 -1,
1149 "AIBinder_Class_define:FGProcessObserver",
1150 ));
1151 }
1152
1153 let obs_binder = unsafe { (vt.new_binder)(obs_class, std::ptr::null_mut()) };
1155 if obs_binder.is_null() {
1156 return Err(CoreError::binder(-1, "AIBinder_new:FGProcessObserver"));
1157 }
1158 unsafe { (vt.associate_class)(obs_binder, obs_class) };
1159
1160 let _ = transact_write(&vt, service.ptr, register_code, |w| {
1163 w.write_strong_binder(obs_binder)
1164 })?;
1165
1166 let consumer = owned.try_clone().map_err(|e| {
1169 CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:fgproc_observer")
1170 })?;
1171
1172 FGPROC_READ_I32.store(vt.read_int32 as usize, Ordering::Relaxed);
1177 FGPROC_IPROC_MODE.store(mode, Ordering::Relaxed);
1178 FGPROC_FG_CODE.store(fgproc_code, Ordering::Relaxed);
1179 FGPROC_PID.store(0, Ordering::Relaxed);
1180 *fgproc_eventfd_guard() = Some(owned);
1181
1182 unsafe { (vt.set_thread_pool_max)(0) };
1184 let join_fn = vt.join_thread_pool;
1185 std::thread::spawn(move || unsafe { join_fn() });
1186
1187 let binder = Self {
1188 _lib: lib,
1189 vt,
1190 _class: am_class,
1191 service,
1192 tx_code: 0,
1193 legacy: false,
1194 };
1195 Ok((binder, consumer))
1196 }
1197
1198 fn do_transact(&self) -> Result<OwnedParcel, CoreError> {
1199 transact_write(&self.vt, self.service.ptr, self.tx_code, |_| Ok(()))
1200 }
1201
1202 pub fn get_focused_task(&self) -> Result<Option<(i32, Option<String>)>, CoreError> {
1209 if self.legacy {
1210 return Ok(None);
1212 }
1213 let out = self.do_transact()?;
1214 let r = ParcelReader {
1215 vt: &self.vt,
1216 parcel: &out,
1217 };
1218 let ex = r.read_i32()?;
1219 if ex != EX_NONE {
1220 return Err(CoreError::binder(ex, "getFocusedTask:exception"));
1221 }
1222 let present = r.read_i32()?;
1223 if present == 0 {
1224 return Ok(None);
1225 }
1226 Ok(Some(parse_root_task_info_task(&r)?))
1227 }
1228
1229 pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
1233 if self.legacy {
1234 let out = self.do_transact()?;
1235 let r = ParcelReader {
1236 vt: &self.vt,
1237 parcel: &out,
1238 };
1239 let ex = r.read_i32()?;
1240 if ex != EX_NONE {
1241 return Err(CoreError::binder(ex, "getFocusedTask:exception"));
1242 }
1243 let present = r.read_i32()?;
1244 if present == 0 {
1245 return Ok(None);
1246 }
1247 return parse_stack_info_body(&r);
1248 }
1249 Ok(self.get_focused_task()?.and_then(|(_, pkg)| pkg))
1250 }
1251
1252 pub fn get_focused_task_id(&self) -> Result<Option<i32>, CoreError> {
1256 Ok(self.get_focused_task()?.map(|(task_id, _)| task_id))
1257 }
1258 }
1259
1260 const DISPLAY_SERVICE: &[u8] = b"display\0";
1263 const DISPLAY_DESCRIPTOR: &[u8] = b"android.hardware.display.IDisplayManager\0";
1264 const CALLBACK_DESCRIPTOR: &[u8] = b"android.hardware.display.IDisplayManagerCallback\0";
1265 const POWER_SERVICE: &[u8] = b"power\0";
1266 const POWER_DESCRIPTOR: &[u8] = b"android.os.IPowerManager\0";
1267
1268 const TX_DISPLAY_REGISTER_CALLBACK: u32 = 4;
1269
1270 static DISP_EVENTFD: Mutex<Option<OwnedFd>> = Mutex::new(None);
1273
1274 fn disp_eventfd_guard() -> std::sync::MutexGuard<'static, Option<OwnedFd>> {
1275 DISP_EVENTFD.lock().unwrap_or_else(|p| p.into_inner())
1276 }
1277
1278 unsafe extern "C" fn disp_cb_on_create(_: *mut c_void) -> *mut c_void {
1279 std::ptr::null_mut()
1280 }
1281 unsafe extern "C" fn disp_cb_on_destroy(_: *mut c_void) {}
1282 unsafe extern "C" fn disp_cb_on_transact(
1283 _: *mut AIBinder,
1284 code: u32,
1285 _: *const AParcel,
1286 _: *mut AParcel,
1287 ) -> BinderStatus {
1288 if code == 1 {
1289 if let Some(fd) = disp_eventfd_guard().as_ref() {
1290 let val: u64 = 1;
1291 unsafe { libc::write(fd.as_raw_fd(), &val as *const u64 as *const c_void, 8) };
1292 }
1293 }
1294 STATUS_OK
1295 }
1296 unsafe extern "C" fn disp_client_on_create(_: *mut c_void) -> *mut c_void {
1304 std::ptr::null_mut()
1305 }
1306 unsafe extern "C" fn disp_client_on_destroy(_: *mut c_void) {}
1307 unsafe extern "C" fn disp_client_on_transact(
1308 _: *mut AIBinder,
1309 _: u32,
1310 _: *const AParcel,
1311 _: *mut AParcel,
1312 ) -> BinderStatus {
1313 STATUS_UNKNOWN_TRANSACTION
1314 }
1315 #[derive(Clone, Copy, Debug, PartialEq, Default)]
1322 pub struct DisplayInfo {
1323 pub active_mode_id: i32,
1325 pub vsync_rate: f32,
1327 pub peak_refresh_rate: f32,
1329 pub render_frame_rate: f32,
1331 pub is_interactive: bool,
1333 }
1334
1335 pub struct DisplayManager {
1336 _lib: DlHandle,
1337 vt: Vtable,
1338 display: Option<OwnedBinder>,
1339 display_info_tx: Option<u32>,
1340 power: Option<OwnedBinder>,
1341 is_interactive_tx: u32,
1342 }
1343 unsafe impl Send for DisplayManager {}
1344
1345 impl DisplayManager {
1346 pub fn open_with_callback() -> Result<(Self, crate::fd::Fd), CoreError> {
1347 let handle = unsafe {
1348 libc::dlopen(
1349 LIBBINDER_PATH.as_ptr() as *const c_char,
1350 libc::RTLD_NOW | libc::RTLD_LOCAL,
1351 )
1352 };
1353 if handle.is_null() {
1354 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
1355 }
1356 let lib = DlHandle;
1357 let vt = load_vtable(handle)?;
1358
1359 let owned = unsafe {
1363 let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
1364 if raw < 0 {
1365 return Err(CoreError::sys(*libc::__errno(), "eventfd"));
1366 }
1367 OwnedFd::from_raw_fd(raw)
1368 };
1369
1370 let raw_display =
1374 unsafe { (vt.get_service)(DISPLAY_SERVICE.as_ptr() as *const c_char) };
1375 if raw_display.is_null() {
1376 return Err(CoreError::binder(-1, "AServiceManager_getService:display"));
1377 }
1378 let display_class = unsafe {
1379 (vt.class_define)(
1380 DISPLAY_DESCRIPTOR.as_ptr() as *const c_char,
1381 disp_client_on_create,
1382 disp_client_on_destroy,
1383 disp_client_on_transact,
1384 )
1385 };
1386 if display_class.is_null() {
1387 return Err(CoreError::binder(
1388 -1,
1389 "AIBinder_Class_define:IDisplayManager",
1390 ));
1391 }
1392 unsafe { (vt.associate_class)(raw_display, display_class) };
1393 let display = OwnedBinder {
1394 ptr: raw_display,
1395 dec_strong: vt.dec_strong,
1396 };
1397
1398 let cb_class = unsafe {
1400 (vt.class_define)(
1401 CALLBACK_DESCRIPTOR.as_ptr() as *const c_char,
1402 disp_cb_on_create,
1403 disp_cb_on_destroy,
1404 disp_cb_on_transact,
1405 )
1406 };
1407 if cb_class.is_null() {
1408 return Err(CoreError::binder(
1409 -1,
1410 "AIBinder_Class_define:DisplayCallback",
1411 ));
1412 }
1413
1414 let cb_binder = unsafe { (vt.new_binder)(cb_class, std::ptr::null_mut()) };
1415 if cb_binder.is_null() {
1416 return Err(CoreError::binder(-1, "AIBinder_new:DisplayCallback"));
1417 }
1418
1419 let _ = transact_write(&vt, display.ptr, TX_DISPLAY_REGISTER_CALLBACK, |w| {
1421 w.write_strong_binder(cb_binder)
1422 })?;
1423
1424 let power_class = unsafe {
1427 (vt.class_define)(
1428 POWER_DESCRIPTOR.as_ptr() as *const c_char,
1429 disp_client_on_create,
1430 disp_client_on_destroy,
1431 disp_client_on_transact,
1432 )
1433 };
1434 let power = if power_class.is_null() {
1435 None
1436 } else {
1437 let raw = unsafe { (vt.get_service)(POWER_SERVICE.as_ptr() as *const c_char) };
1438 if raw.is_null() {
1439 None
1440 } else {
1441 unsafe { (vt.associate_class)(raw, power_class) };
1442 Some(OwnedBinder {
1443 ptr: raw,
1444 dec_strong: vt.dec_strong,
1445 })
1446 }
1447 };
1448
1449 let is_interactive_tx = crate::android::dex::resolve_is_interactive_tx()
1451 .ok_or_else(|| CoreError::binder(-1, "dex:TRANSACTION_isInteractive not found"))?;
1452
1453 let display_info_tx = crate::android::dex::resolve_display_info_tx();
1456
1457 let efd_owned = owned
1460 .try_clone()
1461 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:display"))
1462 .and_then(|dup| unsafe {
1463 crate::fd::Fd::from_owned_raw_fd(dup.into_raw_fd(), "display.efd")
1464 .map_err(|_| CoreError::binder(-1, "Fd::from_owned_raw_fd:display.efd"))
1465 })?;
1466
1467 *disp_eventfd_guard() = Some(owned);
1469
1470 unsafe { (vt.set_thread_pool_max)(0) };
1472 let join_fn = vt.join_thread_pool;
1473 std::thread::spawn(move || unsafe { join_fn() });
1474
1475 Ok((
1476 Self {
1477 _lib: lib,
1478 vt,
1479 display: Some(display),
1480 display_info_tx,
1481 power,
1482 is_interactive_tx,
1483 },
1484 efd_owned,
1485 ))
1486 }
1487
1488 pub fn is_interactive(&self) -> Result<bool, CoreError> {
1489 let power = self
1490 .power
1491 .as_ref()
1492 .ok_or_else(|| CoreError::binder(-1, "power:unavailable"))?;
1493 let out = transact_write(&self.vt, power.ptr, self.is_interactive_tx, |_| Ok(()))?;
1494 let r = ParcelReader {
1495 vt: &self.vt,
1496 parcel: &out,
1497 };
1498 let ex = r.read_i32()?;
1499 if ex != EX_NONE {
1500 return Err(CoreError::binder(ex, "isInteractive:exception"));
1501 }
1502 r.read_bool()
1503 }
1504
1505 pub fn info(&self, display_id: i32) -> Result<DisplayInfo, CoreError> {
1520 let display = self
1521 .display
1522 .as_ref()
1523 .ok_or_else(|| CoreError::binder(-1, "display:unavailable"))?;
1524 let tx = self
1525 .display_info_tx
1526 .ok_or_else(|| CoreError::binder(-1, "display_info:tx unavailable"))?;
1527 let out = transact_write(&self.vt, display.ptr, tx, |w| {
1528 w.write_i32(display_id)
1529 })?;
1530 let r = ParcelReader {
1531 vt: &self.vt,
1532 parcel: &out,
1533 };
1534
1535 let ex = r.read_i32()?;
1536 if ex != EX_NONE {
1537 return Err(CoreError::binder(ex, "getDisplayInfo:exception"));
1538 }
1539 let parsed = parse_display_info(&r)?;
1547
1548 let interactive = self.is_interactive().unwrap_or(false);
1549 Ok(DisplayInfo {
1550 active_mode_id: parsed.active_mode_id,
1551 vsync_rate: parsed.vsync_rate,
1552 peak_refresh_rate: parsed.peak_refresh_rate,
1553 render_frame_rate: parsed.render_frame_rate,
1554 is_interactive: interactive,
1555 })
1556 }
1557 }
1558
1559 const WINDOW_SERVICE: &[u8] = b"window\0";
1562 const WM_DESCRIPTOR: &[u8] = b"android.view.IWindowManager\0";
1563 const FPS_DESCRIPTOR: &[u8] = b"android.window.ITaskFpsCallback\0";
1564 static FPS_VALUE: AtomicU32 = AtomicU32::new(0);
1571 static FPS_SEEN: AtomicBool = AtomicBool::new(false);
1576 static FPS_CODE: AtomicU32 = AtomicU32::new(0);
1577 static FPS_READ_I32: AtomicUsize = AtomicUsize::new(0);
1578
1579 unsafe extern "C" fn wm_on_create(_: *mut c_void) -> *mut c_void {
1583 std::ptr::null_mut()
1584 }
1585 unsafe extern "C" fn wm_on_destroy(_: *mut c_void) {}
1586 unsafe extern "C" fn wm_on_transact(
1587 _: *mut AIBinder,
1588 _: u32,
1589 _: *const AParcel,
1590 _: *mut AParcel,
1591 ) -> BinderStatus {
1592 STATUS_OK
1593 }
1594
1595 unsafe extern "C" fn fps_on_create(userdata: *mut c_void) -> *mut c_void {
1601 userdata
1602 }
1603 unsafe extern "C" fn fps_on_destroy(userdata: *mut c_void) {
1604 if !userdata.is_null() {
1605 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
1606 }
1607 }
1608 unsafe extern "C" fn fps_on_transact(
1609 binder: *mut AIBinder,
1610 code: u32,
1611 in_parcel: *const AParcel,
1612 _: *mut AParcel,
1613 ) -> BinderStatus {
1614 if code != FPS_CODE.load(Ordering::Relaxed) {
1615 return STATUS_UNKNOWN_TRANSACTION;
1616 }
1617 let read_addr = FPS_READ_I32.load(Ordering::Relaxed);
1620 if read_addr != 0 {
1621 let read_fn: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus =
1622 unsafe { std::mem::transmute(read_addr) };
1623 let mut bits: i32 = 0;
1624 if unsafe { read_fn(in_parcel, &mut bits) } == STATUS_OK {
1625 FPS_VALUE.store(sanitize_fps(bits as u32), Ordering::Relaxed);
1630 FPS_SEEN.store(true, Ordering::Release);
1631 let get_user_data = GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner());
1637 if let Some(get_user_data) = *get_user_data {
1638 let userdata = unsafe { get_user_data(binder) };
1639 if !userdata.is_null() {
1640 let efd = userdata as *mut OwnedFd;
1641 let val: u64 = 1;
1642 unsafe {
1643 libc::write((*efd).as_raw_fd(), &val as *const u64 as *const c_void, 8)
1644 };
1645 }
1646 }
1647 }
1648 }
1649 STATUS_OK
1650 }
1651
1652 pub struct FpsListener {
1666 _lib: DlHandle,
1667 vt: Vtable,
1668 window: OwnedBinder,
1669 cb_binder: *mut AIBinder,
1670 _wm_class: *mut AIBinder_Class,
1671 register_code: u32,
1672 unregister_code: u32,
1673 task_id: i32,
1674 }
1675 unsafe impl Send for FpsListener {}
1676
1677 impl FpsListener {
1678 pub fn open() -> Result<(Self, OwnedFd), CoreError> {
1684 let handle = unsafe {
1685 libc::dlopen(
1686 LIBBINDER_PATH.as_ptr() as *const c_char,
1687 libc::RTLD_NOW | libc::RTLD_LOCAL,
1688 )
1689 };
1690 if handle.is_null() {
1691 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
1692 }
1693 let lib = DlHandle;
1694 let vt = load_vtable(handle)?;
1695
1696 let (register_code, unregister_code, on_fps_code) =
1697 crate::android::dex::resolve_fps_codes().ok_or_else(|| {
1698 CoreError::binder(-1, "dex:TRANSACTION_registerTaskFpsCallback not found")
1699 })?;
1700
1701 let window = {
1702 let raw = unsafe { (vt.get_service)(WINDOW_SERVICE.as_ptr() as *const c_char) };
1703 if raw.is_null() {
1704 return Err(CoreError::binder(-1, "AServiceManager_getService:window"));
1705 }
1706 OwnedBinder {
1707 ptr: raw,
1708 dec_strong: vt.dec_strong,
1709 }
1710 };
1711
1712 let wm_class = unsafe {
1715 (vt.class_define)(
1716 WM_DESCRIPTOR.as_ptr() as *const c_char,
1717 wm_on_create,
1718 wm_on_destroy,
1719 wm_on_transact,
1720 )
1721 };
1722 if wm_class.is_null() {
1723 return Err(CoreError::binder(
1724 -1,
1725 "AIBinder_Class_define:IWindowManager",
1726 ));
1727 }
1728 unsafe { (vt.associate_class)(window.ptr, wm_class) };
1729
1730 let cb_class = unsafe {
1731 (vt.class_define)(
1732 FPS_DESCRIPTOR.as_ptr() as *const c_char,
1733 fps_on_create,
1734 fps_on_destroy,
1735 fps_on_transact,
1736 )
1737 };
1738 if cb_class.is_null() {
1739 return Err(CoreError::binder(
1740 -1,
1741 "AIBinder_Class_define:ITaskFpsCallback",
1742 ));
1743 }
1744
1745 let owned = unsafe {
1753 let raw = libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC);
1754 if raw < 0 {
1755 return Err(CoreError::sys(*libc::__errno(), "eventfd"));
1756 }
1757 OwnedFd::from_raw_fd(raw)
1758 };
1759
1760 let consumer = owned
1761 .try_clone()
1762 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:fps"))?;
1763
1764 let userdata = Box::into_raw(Box::new(owned)) as *mut c_void;
1765 let cb_binder = unsafe { (vt.new_binder)(cb_class, userdata) };
1766 if cb_binder.is_null() {
1767 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
1769 return Err(CoreError::binder(-1, "AIBinder_new:ITaskFpsCallback"));
1770 }
1771 unsafe { (vt.associate_class)(cb_binder, cb_class) };
1772
1773 FPS_READ_I32.store(vt.read_int32 as usize, Ordering::Relaxed);
1776 FPS_SEEN.store(false, Ordering::Relaxed);
1777 FPS_CODE.store(on_fps_code, Ordering::Relaxed);
1778 FPS_VALUE.store(0, Ordering::Relaxed);
1779 *GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner()) = Some(vt.get_user_data);
1782
1783 unsafe { (vt.set_thread_pool_max)(0) };
1784 let join_fn = vt.join_thread_pool;
1785 std::thread::spawn(move || unsafe { join_fn() });
1786
1787 Ok((
1788 Self {
1789 _lib: lib,
1790 vt,
1791 window,
1792 cb_binder,
1793 _wm_class: wm_class,
1794 register_code,
1795 unregister_code,
1796 task_id: -1,
1797 },
1798 consumer,
1799 ))
1800 }
1801
1802 pub fn register(&mut self, task_id: i32) -> Result<(), CoreError> {
1806 if self.task_id == task_id {
1807 return Ok(());
1808 }
1809 if self.task_id >= 0 {
1810 let _ = self.unregister();
1811 }
1812
1813 let _ = transact_write(&self.vt, self.window.ptr, self.register_code, |w| {
1814 w.write_i32(task_id)?;
1815 w.write_strong_binder(self.cb_binder)
1816 })?;
1817 self.task_id = task_id;
1818 Ok(())
1819 }
1820
1821 pub fn unregister(&mut self) -> Result<(), CoreError> {
1824 if self.task_id < 0 {
1825 return Ok(());
1826 }
1827 let _ = transact_write(&self.vt, self.window.ptr, self.unregister_code, |w| {
1828 w.write_strong_binder(self.cb_binder)
1829 })?;
1830 self.task_id = -1;
1831 Ok(())
1832 }
1833
1834 pub fn last_fps(&self) -> Option<f32> {
1839 fps_from_state(
1840 FPS_SEEN.load(Ordering::Acquire),
1841 FPS_VALUE.load(Ordering::Relaxed),
1842 )
1843 }
1844
1845 pub fn task_id(&self) -> Option<i32> {
1847 (self.task_id >= 0).then_some(self.task_id)
1848 }
1849 }
1850
1851 impl Drop for FpsListener {
1852 fn drop(&mut self) {
1860 let _ = self.unregister();
1861 }
1862 }
1863
1864 fn fps_from_state(seen: bool, bits: u32) -> Option<f32> {
1869 if seen {
1870 Some(f32::from_bits(bits))
1871 } else {
1872 None
1873 }
1874 }
1875
1876 fn sanitize_fps(bits: u32) -> u32 {
1881 let v = f32::from_bits(bits);
1882 if v.is_finite() && v >= 0.0 {
1883 bits
1884 } else {
1885 0.0f32.to_bits()
1886 }
1887 }
1888
1889 const TASK_SERVICE: &[u8] = b"activity_task\0";
1892 const ATM_DESCRIPTOR: &[u8] = b"android.app.IActivityTaskManager\0";
1893 const TASK_STACK_DESCRIPTOR: &[u8] = b"android.app.ITaskStackListener\0";
1894
1895 unsafe extern "C" fn atm_on_create(_: *mut c_void) -> *mut c_void {
1899 std::ptr::null_mut()
1900 }
1901 unsafe extern "C" fn atm_on_destroy(_: *mut c_void) {}
1902 unsafe extern "C" fn atm_on_transact(
1903 _: *mut AIBinder,
1904 _: u32,
1905 _: *const AParcel,
1906 _: *mut AParcel,
1907 ) -> BinderStatus {
1908 STATUS_OK
1909 }
1910
1911 static GET_USER_DATA: std::sync::Mutex<
1927 Option<unsafe extern "C" fn(*const AIBinder) -> *mut c_void>,
1928 > = std::sync::Mutex::new(None);
1929
1930 unsafe extern "C" fn task_stack_on_create(userdata: *mut c_void) -> *mut c_void {
1931 userdata
1932 }
1933 unsafe extern "C" fn task_stack_on_destroy(userdata: *mut c_void) {
1934 if !userdata.is_null() {
1935 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
1936 }
1937 }
1938 unsafe extern "C" fn task_stack_on_transact(
1939 binder: *mut AIBinder,
1940 _code: u32,
1941 _in_parcel: *const AParcel,
1942 _reply: *mut AParcel,
1943 ) -> BinderStatus {
1944 let get_user_data = GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner());
1945 if let Some(get_user_data) = *get_user_data {
1946 let userdata = unsafe { get_user_data(binder) };
1947 if !userdata.is_null() {
1948 let efd = userdata as *mut OwnedFd;
1949 let val: u64 = 1;
1950 unsafe { libc::write((*efd).as_raw_fd(), &val as *const u64 as *const c_void, 8) };
1951 }
1952 }
1953 STATUS_OK
1954 }
1955
1956 pub struct TaskStackListener {
1976 _lib: DlHandle,
1977 vt: Vtable,
1978 service: OwnedBinder,
1979 cb_binder: *mut AIBinder,
1980 _atm_class: *mut AIBinder_Class,
1981 register_code: u32,
1982 unregister_code: u32,
1983 }
1984 unsafe impl Send for TaskStackListener {}
1985
1986 impl TaskStackListener {
1987 pub fn open() -> Result<(Self, OwnedFd), CoreError> {
1991 let handle = unsafe {
1992 libc::dlopen(
1993 LIBBINDER_PATH.as_ptr() as *const c_char,
1994 libc::RTLD_NOW | libc::RTLD_LOCAL,
1995 )
1996 };
1997 if handle.is_null() {
1998 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
1999 }
2000 let lib = DlHandle;
2001 let vt = load_vtable(handle)?;
2002
2003 let (register_code, unregister_code) = crate::android::dex::resolve_task_stack_codes()
2004 .ok_or_else(|| {
2005 CoreError::binder(-1, "dex:TRANSACTION_registerTaskStackListener not found")
2006 })?;
2007
2008 let service = {
2009 let raw = unsafe { (vt.get_service)(TASK_SERVICE.as_ptr() as *const c_char) };
2010 if raw.is_null() {
2011 return Err(CoreError::binder(
2012 -1,
2013 "AServiceManager_getService:activity_task",
2014 ));
2015 }
2016 OwnedBinder {
2017 ptr: raw,
2018 dec_strong: vt.dec_strong,
2019 }
2020 };
2021
2022 let atm_class = unsafe {
2025 (vt.class_define)(
2026 ATM_DESCRIPTOR.as_ptr() as *const c_char,
2027 atm_on_create,
2028 atm_on_destroy,
2029 atm_on_transact,
2030 )
2031 };
2032 if atm_class.is_null() {
2033 return Err(CoreError::binder(
2034 -1,
2035 "AIBinder_Class_define:IActivityTaskManager",
2036 ));
2037 }
2038 unsafe { (vt.associate_class)(service.ptr, atm_class) };
2039
2040 let cb_class = unsafe {
2041 (vt.class_define)(
2042 TASK_STACK_DESCRIPTOR.as_ptr() as *const c_char,
2043 task_stack_on_create,
2044 task_stack_on_destroy,
2045 task_stack_on_transact,
2046 )
2047 };
2048 if cb_class.is_null() {
2049 return Err(CoreError::binder(
2050 -1,
2051 "AIBinder_Class_define:ITaskStackListener",
2052 ));
2053 }
2054
2055 let owned = unsafe {
2060 let raw = libc::eventfd(0, libc::EFD_CLOEXEC);
2061 if raw < 0 {
2062 return Err(CoreError::sys(*libc::__errno(), "eventfd"));
2063 }
2064 OwnedFd::from_raw_fd(raw)
2065 };
2066
2067 let consumer = owned
2068 .try_clone()
2069 .map_err(|e| CoreError::sys(e.raw_os_error().unwrap_or(-1), "dup:task_stack"))?;
2070
2071 let userdata = Box::into_raw(Box::new(owned)) as *mut c_void;
2072 let cb_binder = unsafe { (vt.new_binder)(cb_class, userdata) };
2073 if cb_binder.is_null() {
2074 unsafe { drop(Box::from_raw(userdata as *mut OwnedFd)) };
2076 return Err(CoreError::binder(-1, "AIBinder_new:ITaskStackListener"));
2077 }
2078 unsafe { (vt.associate_class)(cb_binder, cb_class) };
2079
2080 *GET_USER_DATA.lock().unwrap_or_else(|p| p.into_inner()) = Some(vt.get_user_data);
2083
2084 unsafe { (vt.set_thread_pool_max)(0) };
2085 let join_fn = vt.join_thread_pool;
2086 std::thread::spawn(move || unsafe { join_fn() });
2087
2088 Ok((
2089 Self {
2090 _lib: lib,
2091 vt,
2092 service,
2093 cb_binder,
2094 _atm_class: atm_class,
2095 register_code,
2096 unregister_code,
2097 },
2098 consumer,
2099 ))
2100 }
2101
2102 pub fn register(&self) -> Result<(), CoreError> {
2106 let _ = transact_write(&self.vt, self.service.ptr, self.register_code, |w| {
2107 w.write_strong_binder(self.cb_binder)
2108 })?;
2109 Ok(())
2110 }
2111
2112 pub fn unregister(&self) -> Result<(), CoreError> {
2116 let _ = transact_write(&self.vt, self.service.ptr, self.unregister_code, |w| {
2117 w.write_strong_binder(self.cb_binder)
2118 })?;
2119 Ok(())
2120 }
2121 }
2122
2123 impl Drop for TaskStackListener {
2124 fn drop(&mut self) {
2129 let _ = self.unregister();
2130 }
2131 }
2132
2133 pub struct RawBinderService {
2142 _lib: DlHandle,
2143 vt: Vtable,
2144 service: OwnedBinder,
2145 }
2146 unsafe impl Send for RawBinderService {}
2147
2148 impl RawBinderService {
2149 pub fn open(service_name: &str) -> Result<Self, CoreError> {
2151 use std::ffi::CString;
2152 let handle = unsafe {
2153 libc::dlopen(
2154 LIBBINDER_PATH.as_ptr() as *const c_char,
2155 libc::RTLD_NOW | libc::RTLD_LOCAL,
2156 )
2157 };
2158 if handle.is_null() {
2159 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
2160 }
2161 let lib = DlHandle;
2162 let vt = load_vtable(handle)?;
2163 let cs = CString::new(service_name)
2164 .map_err(|_| CoreError::binder(-1, "service_name:nul_byte"))?;
2165 let raw = unsafe { (vt.get_service)(cs.as_ptr()) };
2166 if raw.is_null() {
2167 return Err(CoreError::binder(-1, "AServiceManager_getService:null"));
2168 }
2169 let service = OwnedBinder {
2170 ptr: raw,
2171 dec_strong: vt.dec_strong,
2172 };
2173 Ok(Self {
2174 _lib: lib,
2175 vt,
2176 service,
2177 })
2178 }
2179
2180 pub fn transact_bool(&self, code: u32) -> Result<bool, CoreError> {
2182 let out = self.raw_noarg(code)?;
2183 let r = ParcelReader {
2184 vt: &self.vt,
2185 parcel: &out,
2186 };
2187 let ex = r.read_i32()?;
2188 if ex != EX_NONE {
2189 return Err(CoreError::binder(ex, "transact_bool:exception"));
2190 }
2191 if let Some(rb) = self.vt.read_bool {
2192 let mut v = false;
2193 let s = unsafe { rb(out.ptr as *const AParcel, &mut v) };
2194 if s != STATUS_OK {
2195 return Err(CoreError::binder(s, "AParcel_readBool"));
2196 }
2197 Ok(v)
2198 } else {
2199 Ok(r.read_i32()? != 0)
2200 }
2201 }
2202
2203 pub fn transact_i32(&self, code: u32, arg: i32) -> Result<(), CoreError> {
2205 let _ = transact_write(&self.vt, self.service.ptr, code, |w| w.write_i32(arg))?;
2206 Ok(())
2207 }
2208
2209 fn raw_noarg(&self, code: u32) -> Result<OwnedParcel, CoreError> {
2210 transact_write(&self.vt, self.service.ptr, code, |_| Ok(()))
2211 }
2212 }
2213
2214 #[cfg(test)]
2215 mod tests {
2216 use super::*;
2217
2218 fn alloc(length: i32) -> bool {
2219 let mut buf = StringBuf::new();
2220 let mut out: *mut c_char = std::ptr::null_mut();
2221 unsafe { string_alloc(&mut buf as *mut StringBuf as *mut c_void, length, &mut out) }
2222 }
2223
2224 #[test]
2225 fn string_alloc_rejects_oversized() {
2226 assert!(!alloc(MAX_BINDER_STRING_LEN as i32 + 1));
2227 }
2228
2229 #[test]
2230 fn string_alloc_accepts_null_marker_rejects_other_negative() {
2231 assert!(alloc(-1));
2232 assert!(!alloc(-2));
2233 }
2234
2235 #[test]
2236 fn string_alloc_accepts_valid_len_and_nul_terminates() {
2237 let mut buf = StringBuf::new();
2238 let mut out: *mut c_char = std::ptr::null_mut();
2239 let ok =
2240 unsafe { string_alloc(&mut buf as *mut StringBuf as *mut c_void, 4, &mut out) };
2241 assert!(ok);
2242 assert!(!out.is_null());
2243 {
2244 let vec = unsafe { buf.0.as_mut_vec() };
2245 b"ABCD".iter().enumerate().for_each(|(i, &b)| vec[i] = b);
2246 vec[4] = 0;
2247 }
2248 assert_eq!(buf.finish().as_deref(), Some("ABCD"));
2249 }
2250
2251 #[test]
2252 fn fps_zero_report_distinct_from_unseen() {
2253 assert_eq!(fps_from_state(false, 0), None);
2254 assert_eq!(fps_from_state(true, 0), Some(0.0));
2255 assert_eq!(fps_from_state(true, 60.0f32.to_bits()), Some(60.0));
2256 assert_eq!(fps_from_state(false, 60.0f32.to_bits()), None);
2257 }
2258
2259 #[test]
2260 fn sanitize_fps_rejects_non_finite_and_negative() {
2261 let de = |bits| f32::from_bits(sanitize_fps(bits));
2262 assert_eq!(de(0.0f32.to_bits()), 0.0);
2263 assert_eq!(de(60.0f32.to_bits()), 60.0);
2264 assert_eq!(de(f32::NAN.to_bits()), 0.0);
2265 assert_eq!(de(f32::INFINITY.to_bits()), 0.0);
2266 assert_eq!(de(f32::NEG_INFINITY.to_bits()), 0.0);
2267 assert_eq!(de((-5.0f32).to_bits()), 0.0);
2268 }
2269 }
2270}
2271
2272#[cfg(target_os = "android")]
2275pub use imp::{
2276 ActivityManager, DisplayInfo, DisplayManager, FpsListener, RawBinderService, TaskStackListener,
2277 TxCodes, last_foreground_pid, resolve_tx_codes,
2278};
2279
2280#[cfg(not(target_os = "android"))]
2283pub struct ActivityManager;
2284
2285#[cfg(not(target_os = "android"))]
2286impl ActivityManager {
2287 pub fn open() -> Result<Self, crate::CoreError> {
2288 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2289 }
2290 pub fn open_with_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
2291 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2292 }
2293 pub fn open_with_fgproc_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
2294 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2295 }
2296 pub fn get_focused_task(&self) -> Result<Option<(i32, Option<String>)>, crate::CoreError> {
2297 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2298 }
2299 pub fn get_focused_package(&self) -> Result<Option<String>, crate::CoreError> {
2300 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2301 }
2302 pub fn get_focused_task_id(&self) -> Result<Option<i32>, crate::CoreError> {
2303 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2304 }
2305}
2306
2307#[cfg(not(target_os = "android"))]
2308pub struct DisplayManager;
2309
2310#[cfg(not(target_os = "android"))]
2311impl DisplayManager {
2312 pub fn open_with_callback() -> Result<(Self, crate::fd::Fd), crate::CoreError> {
2313 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2314 }
2315 pub fn is_interactive(&self) -> Result<bool, crate::CoreError> {
2316 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2317 }
2318 pub fn info(&self, _display_id: i32) -> Result<DisplayInfo, crate::CoreError> {
2319 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2320 }
2321}
2322
2323#[cfg(not(target_os = "android"))]
2324#[derive(Clone, Copy, Debug, PartialEq, Default)]
2325pub struct DisplayInfo {
2326 pub active_mode_id: i32,
2327 pub vsync_rate: f32,
2328 pub peak_refresh_rate: f32,
2329 pub render_frame_rate: f32,
2330 pub is_interactive: bool,
2331}
2332
2333#[cfg(not(target_os = "android"))]
2334pub struct RawBinderService;
2335
2336#[cfg(not(target_os = "android"))]
2337impl RawBinderService {
2338 pub fn open(_service_name: &str) -> Result<Self, crate::CoreError> {
2339 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2340 }
2341 pub fn transact_bool(&self, _code: u32) -> Result<bool, crate::CoreError> {
2342 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2343 }
2344 pub fn transact_i32(&self, _code: u32, _arg: i32) -> Result<(), crate::CoreError> {
2345 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2346 }
2347}
2348
2349#[cfg(not(target_os = "android"))]
2350pub struct FpsListener;
2351
2352#[cfg(not(target_os = "android"))]
2353impl FpsListener {
2354 pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
2355 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2356 }
2357 pub fn register(&mut self, _task_id: i32) -> Result<(), crate::CoreError> {
2358 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2359 }
2360 pub fn unregister(&mut self) -> Result<(), crate::CoreError> {
2361 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2362 }
2363 pub fn last_fps(&self) -> Option<f32> {
2364 None
2365 }
2366 pub fn task_id(&self) -> Option<i32> {
2367 None
2368 }
2369}
2370
2371#[cfg(not(target_os = "android"))]
2372pub struct TaskStackListener;
2373
2374#[cfg(not(target_os = "android"))]
2375impl TaskStackListener {
2376 pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
2377 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2378 }
2379 pub fn register(&self) -> Result<(), crate::CoreError> {
2380 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2381 }
2382 pub fn unregister(&self) -> Result<(), crate::CoreError> {
2383 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2384 }
2385}
2386
2387#[cfg(not(target_os = "android"))]
2388pub struct TxCodes {
2389 pub observer_code: u32,
2390 pub query_code: u32,
2391 pub api_mode: u8,
2392 pub fg_code: u32,
2393}
2394
2395#[cfg(not(target_os = "android"))]
2396pub fn resolve_tx_codes() -> Result<TxCodes, crate::CoreError> {
2397 Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
2398}
2399
2400#[cfg(not(target_os = "android"))]
2401pub fn last_foreground_pid() -> i32 {
2402 0
2403}