1use crate::CoreError;
23
24#[cfg(target_os = "android")]
29mod imp {
30 use super::*;
31 use crate::android_property::android_property_get;
32
33
34 const STATUS_OK: i32 = 0;
37 const STATUS_UNKNOWN_TRANSACTION: i32 = -2;
39
40 const EX_NONE: i32 = 0;
44
45 const ACTIVITY_MANAGER_DESCRIPTOR: &[u8] = b"android.app.IActivityManager\0";
48 const ACTIVITY_SERVICE_NAME: &[u8] = b"activity\0";
49 const LIBBINDER_NDK_PATH: &[u8] = b"/system/lib64/libbinder_ndk.so\0";
50
51 const TX_CACHE_PATH: &str = "/data/local/tmp/watcher_tx_code.txt";
54
55 #[derive(Clone, Copy)]
67 struct TxEntry {
68 api: u32,
69 code: i32,
70 legacy: bool,
71 }
72
73 static TX_TABLE: &[TxEntry] = &[
74 TxEntry { api: 29, code: 157, legacy: true },
75 TxEntry { api: 30, code: 168, legacy: false },
76 TxEntry { api: 31, code: 176, legacy: false },
77 TxEntry { api: 32, code: 178, legacy: false },
78 TxEntry { api: 33, code: 181, legacy: false },
79 TxEntry { api: 34, code: 183, legacy: false },
80 TxEntry { api: 35, code: 187, legacy: false },
81 ];
82
83 const PROBE_WINDOW: i32 = 12;
84 use std::os::raw::{c_char, c_void};
85
86 type AIBinder = c_void;
89 #[allow(non_camel_case_types)]
90 type AIBinder_Class = c_void;
91 type AParcel = c_void;
92
93 type BinderStatus = i32;
94
95 type StringAllocator =
98 unsafe extern "C" fn(string_data: *mut c_void, length: i32, buffer: *mut *mut c_char)
99 -> bool;
100
101 unsafe extern "C" fn on_create(_args: *mut c_void) -> *mut c_void {
103 std::ptr::null_mut()
104 }
105 unsafe extern "C" fn on_destroy(_user_data: *mut c_void) {}
106 unsafe extern "C" fn on_transact(
107 _binder: *mut AIBinder,
108 _code: u32,
109 _in_parcel: *const AParcel,
110 _out_parcel: *mut AParcel,
111 ) -> BinderStatus {
112 STATUS_UNKNOWN_TRANSACTION
113 }
114
115 unsafe extern "C" fn string_alloc(
118 string_data: *mut c_void,
119 length: i32,
120 buffer: *mut *mut c_char,
121 ) -> bool {
122 if length < 0 {
123 return true;
125 }
126 let s = unsafe { &mut *(string_data as *mut StringBuf) };
127 s.buf.resize((length as usize) + 1, 0u8);
128 unsafe { *buffer = s.buf.as_mut_ptr() as *mut c_char };
129 true
130 }
131
132 struct StringBuf {
133 buf: Vec<u8>,
134 }
135
136 impl StringBuf {
137 fn new() -> Self {
138 Self { buf: Vec::new() }
139 }
140
141 fn as_str(&self) -> Option<&str> {
142 if self.buf.is_empty() {
143 return None;
144 }
145 let len = self.buf.iter().position(|&b| b == 0).unwrap_or(self.buf.len());
146 std::str::from_utf8(&self.buf[..len]).ok()
147 }
148 }
149
150 struct Vtable {
153 get_service: unsafe extern "C" fn(*const c_char) -> *mut AIBinder,
155 #[allow(dead_code)]
156 wait_for_service: unsafe extern "C" fn(*const c_char) -> *mut AIBinder,
157 class_define: unsafe extern "C" fn(
159 descriptor: *const c_char,
160 on_create: unsafe extern "C" fn(*mut c_void) -> *mut c_void,
161 on_destroy: unsafe extern "C" fn(*mut c_void),
162 on_transact: unsafe extern "C" fn(
163 *mut AIBinder,
164 u32,
165 *const AParcel,
166 *mut AParcel,
167 ) -> BinderStatus,
168 ) -> *mut AIBinder_Class,
169 associate_class:
170 unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool,
171 prepare_transaction:
173 unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus,
174 transact: unsafe extern "C" fn(
175 *mut AIBinder,
176 u32,
177 *mut *mut AParcel,
178 *mut *mut AParcel,
179 u32,
180 ) -> BinderStatus,
181 dec_strong: unsafe extern "C" fn(*mut AIBinder),
182 parcel_delete: unsafe extern "C" fn(*mut AParcel),
184 read_int32: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus,
185 #[allow(dead_code)]
186 read_bool: unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus,
187 read_string: unsafe extern "C" fn(
188 *const AParcel,
189 *mut c_void,
190 StringAllocator,
191 ) -> BinderStatus,
192 }
193
194 struct DlHandle(*mut c_void);
195 unsafe impl Send for DlHandle {}
196 impl Drop for DlHandle {
197 fn drop(&mut self) {
198 if !self.0.is_null() {
199 unsafe { libc::dlclose(self.0) };
200 }
201 }
202 }
203
204 macro_rules! dlsym_fn {
205 ($handle:expr, $name:literal, $ty:ty) => {{
206 let sym = unsafe {
207 libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char)
208 };
209 if sym.is_null() {
210 return Err(CoreError::binder(-1, concat!("dlsym:", $name)));
211 }
212 unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }
213 }};
214 }
215
216 fn load_vtable(handle: *mut c_void) -> Result<Vtable, CoreError> {
217 Ok(Vtable {
218 get_service: dlsym_fn!(
219 handle,
220 "AServiceManager_getService",
221 unsafe extern "C" fn(*const c_char) -> *mut AIBinder
222 ),
223 wait_for_service: dlsym_fn!(
224 handle,
225 "AServiceManager_waitForService",
226 unsafe extern "C" fn(*const c_char) -> *mut AIBinder
227 ),
228 class_define: dlsym_fn!(
229 handle,
230 "AIBinder_Class_define",
231 unsafe extern "C" fn(
232 *const c_char,
233 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
234 unsafe extern "C" fn(*mut c_void),
235 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel)
236 -> BinderStatus,
237 ) -> *mut AIBinder_Class
238 ),
239 associate_class: dlsym_fn!(
240 handle,
241 "AIBinder_associateClass",
242 unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool
243 ),
244 prepare_transaction: dlsym_fn!(
245 handle,
246 "AIBinder_prepareTransaction",
247 unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus
248 ),
249 transact: dlsym_fn!(
250 handle,
251 "AIBinder_transact",
252 unsafe extern "C" fn(
253 *mut AIBinder,
254 u32,
255 *mut *mut AParcel,
256 *mut *mut AParcel,
257 u32,
258 ) -> BinderStatus
259 ),
260 dec_strong: dlsym_fn!(
261 handle,
262 "AIBinder_decStrong",
263 unsafe extern "C" fn(*mut AIBinder)
264 ),
265 parcel_delete: dlsym_fn!(
266 handle,
267 "AParcel_delete",
268 unsafe extern "C" fn(*mut AParcel)
269 ),
270 read_int32: dlsym_fn!(
271 handle,
272 "AParcel_readInt32",
273 unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus
274 ),
275 read_bool: dlsym_fn!(
276 handle,
277 "AParcel_readBool",
278 unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus
279 ),
280 read_string: dlsym_fn!(
281 handle,
282 "AParcel_readString",
283 unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus
284 ),
285 })
286 }
287
288 struct ParcelReader<'a> {
291 vt: &'a Vtable,
292 parcel: *const AParcel,
293 }
294
295 impl<'a> ParcelReader<'a> {
296 fn read_i32(&self) -> Result<i32, CoreError> {
297 let mut v = 0i32;
298 let s = unsafe { (self.vt.read_int32)(self.parcel, &mut v) };
299 if s != STATUS_OK {
300 return Err(CoreError::binder(s, "AParcel_readInt32"));
301 }
302 Ok(v)
303 }
304
305 #[allow(dead_code)]
306 fn read_bool(&self) -> Result<bool, CoreError> {
307 let mut v = false;
308 let s = unsafe { (self.vt.read_bool)(self.parcel, &mut v) };
309 if s != STATUS_OK {
310 return Err(CoreError::binder(s, "AParcel_readBool"));
311 }
312 Ok(v)
313 }
314
315 fn read_string(&self) -> Result<Option<String>, CoreError> {
316 let mut buf = StringBuf::new();
317 let s = unsafe {
318 (self.vt.read_string)(
319 self.parcel,
320 &mut buf as *mut StringBuf as *mut c_void,
321 string_alloc,
322 )
323 };
324 if s != STATUS_OK {
325 return Err(CoreError::binder(s, "AParcel_readString"));
326 }
327 Ok(buf.as_str().map(str::to_owned))
328 }
329
330 fn skip_nullable_rect(&self) -> Result<(), CoreError> {
332 let present = self.read_i32()?;
333 if present != 0 {
334 for _ in 0..4 {
335 self.read_i32()?;
336 }
337 }
338 Ok(())
339 }
340
341 fn skip_int_array(&self) -> Result<(), CoreError> {
343 let count = self.read_i32()?;
344 for _ in 0..count.max(0) {
345 self.read_i32()?;
346 }
347 Ok(())
348 }
349
350 fn skip_string_array(&self) -> Result<(), CoreError> {
352 let count = self.read_i32()?;
353 for _ in 0..count.max(0) {
354 self.read_string()?;
355 }
356 Ok(())
357 }
358
359 fn skip_rect_array(&self) -> Result<(), CoreError> {
361 let count = self.read_i32()?;
362 for _ in 0..count.max(0) {
363 self.skip_nullable_rect()?;
365 }
366 Ok(())
367 }
368
369 fn read_component_name(&self) -> Result<Option<(String, String)>, CoreError> {
371 let present = self.read_i32()?;
372 if present == 0 {
373 return Ok(None);
374 }
375 let pkg = self.read_string()?.unwrap_or_default();
376 let cls = self.read_string()?.unwrap_or_default();
377 if pkg.is_empty() {
378 return Ok(None);
379 }
380 Ok(Some((pkg, cls)))
381 }
382 }
383
384 fn parse_root_task_info(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
391 let ex = r.read_i32()?;
392 if ex != EX_NONE {
393 return Err(CoreError::binder(ex, "getFocusedRootTaskInfo:exception"));
394 }
395 let has_info = r.read_i32()?;
396 if has_info == 0 {
397 return Ok(None);
398 }
399 Ok(r.read_component_name()?.map(|(pkg, _)| pkg))
400 }
401
402 fn parse_stack_info(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
412 let ex = r.read_i32()?;
413 if ex != EX_NONE {
414 return Err(CoreError::binder(ex, "getFocusedStackInfo:exception"));
415 }
416 r.read_i32()?; r.skip_nullable_rect()?; r.skip_int_array()?; r.skip_string_array()?; r.skip_rect_array()?; r.skip_int_array()?; Ok(r.read_component_name()?.map(|(pkg, _)| pkg))
423 }
424
425 fn read_tx_cache() -> Option<(i32, bool)> {
428 let text = std::fs::read_to_string(TX_CACHE_PATH).ok()?;
429 let mut parts = text.split_whitespace();
430 let root: i32 = parts.next()?.parse().ok()?;
431 let stack: i32 = parts.next()?.parse().ok()?;
432 if root > 0 {
434 Some((root, false))
435 } else if stack > 0 {
436 Some((stack, true))
437 } else {
438 None
439 }
440 }
441
442 fn sdk_version() -> Option<u32> {
443 android_property_get("ro.build.version.sdk")
444 .and_then(|s| s.trim().parse().ok())
445 }
446
447 fn table_lookup(api: u32) -> Option<(i32, bool)> {
448 let mut best: Option<&TxEntry> = None;
451 for entry in TX_TABLE {
452 if entry.api <= api {
453 best = Some(entry);
454 }
455 }
456 best.map(|e| (e.code, e.legacy))
457 }
458
459 fn probe_window(api: u32) -> std::ops::Range<i32> {
460 let centre = table_lookup(api).map(|(c, _)| c).unwrap_or(170);
462 (centre - PROBE_WINDOW)..(centre + PROBE_WINDOW)
463 }
464
465 pub struct ActivityManagerBinder {
468 _lib: DlHandle,
469 vt: Vtable,
470 _class: *mut AIBinder_Class,
471 service: *mut AIBinder,
472 tx_code: i32,
473 legacy: bool,
474 }
475
476 unsafe impl Send for ActivityManagerBinder {}
478
479 impl ActivityManagerBinder {
480 pub fn open() -> Result<Self, CoreError> {
481 let handle = unsafe {
483 libc::dlopen(
484 LIBBINDER_NDK_PATH.as_ptr() as *const c_char,
485 libc::RTLD_NOW | libc::RTLD_LOCAL,
486 )
487 };
488 if handle.is_null() {
489 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
490 }
491 let lib = DlHandle(handle);
492 let vt = load_vtable(handle)?;
493
494 let class = unsafe {
496 (vt.class_define)(
497 ACTIVITY_MANAGER_DESCRIPTOR.as_ptr() as *const c_char,
498 on_create,
499 on_destroy,
500 on_transact,
501 )
502 };
503 if class.is_null() {
504 return Err(CoreError::binder(-1, "AIBinder_Class_define"));
505 }
506
507 let service = unsafe {
509 (vt.get_service)(ACTIVITY_SERVICE_NAME.as_ptr() as *const c_char)
510 };
511 if service.is_null() {
512 return Err(CoreError::binder(-1, "AServiceManager_getService:activity"));
513 }
514
515 unsafe { (vt.associate_class)(service, class) };
517
518 let (tx_code, legacy) = Self::resolve_tx(&vt, service, class)?;
520
521 Ok(Self { _lib: lib, vt, _class: class, service, tx_code, legacy })
522 }
523
524 fn resolve_tx(
525 vt: &Vtable,
526 service: *mut AIBinder,
527 _class: *mut AIBinder_Class,
528 ) -> Result<(i32, bool), CoreError> {
529 if let Some(pair) = read_tx_cache() {
531 return Ok(pair);
532 }
533
534 let api = sdk_version().unwrap_or(30);
536 if let Some(pair) = table_lookup(api) {
537 if Self::tx_code_valid(vt, service, pair.0, pair.1) {
539 return Ok(pair);
540 }
541 }
542
543 let window = probe_window(api);
545 for code in window {
546 let is_legacy = code < 165; if Self::tx_code_valid(vt, service, code, is_legacy) {
548 return Ok((code, is_legacy));
549 }
550 }
551
552 Err(CoreError::binder(-1, "tx_code_resolution"))
553 }
554
555 fn tx_code_valid(
556 vt: &Vtable,
557 service: *mut AIBinder,
558 code: i32,
559 _legacy: bool,
560 ) -> bool {
561 let mut in_parcel: *mut AParcel = std::ptr::null_mut();
562 let s = unsafe { (vt.prepare_transaction)(service, &mut in_parcel) };
563 if s != STATUS_OK {
564 return false;
565 }
566
567 let mut out_parcel: *mut AParcel = std::ptr::null_mut();
568 let s = unsafe {
569 (vt.transact)(service, code as u32, &mut in_parcel, &mut out_parcel, 0)
570 };
571 if s != STATUS_OK {
572 if !out_parcel.is_null() {
573 unsafe { (vt.parcel_delete)(out_parcel) };
574 }
575 return false;
576 }
577
578 let r = ParcelReader { vt, parcel: out_parcel };
579 let ex = r.read_i32().unwrap_or(-1);
580 unsafe { (vt.parcel_delete)(out_parcel) };
581
582 ex == EX_NONE
586 }
587
588 fn do_transact(&self) -> Result<*mut AParcel, CoreError> {
589 let mut in_parcel: *mut AParcel = std::ptr::null_mut();
590 let s = unsafe { (self.vt.prepare_transaction)(self.service, &mut in_parcel) };
591 if s != STATUS_OK {
592 return Err(CoreError::binder(s, "AIBinder_prepareTransaction"));
593 }
594
595 let mut out_parcel: *mut AParcel = std::ptr::null_mut();
596 let s = unsafe {
597 (self.vt.transact)(
598 self.service,
599 self.tx_code as u32,
600 &mut in_parcel,
601 &mut out_parcel,
602 0,
603 )
604 };
605 if s != STATUS_OK {
606 if !out_parcel.is_null() {
607 unsafe { (self.vt.parcel_delete)(out_parcel) };
608 }
609 return Err(CoreError::binder(s, "AIBinder_transact"));
610 }
611
612 Ok(out_parcel)
613 }
614
615 pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
616 let out = self.do_transact()?;
617 let r = ParcelReader { vt: &self.vt, parcel: out };
618 let result = if self.legacy {
619 parse_stack_info(&r)
620 } else {
621 parse_root_task_info(&r)
622 };
623 unsafe { (self.vt.parcel_delete)(out) };
624 result
625 }
626 }
627
628 impl Drop for ActivityManagerBinder {
629 fn drop(&mut self) {
630 unsafe { (self.vt.dec_strong)(self.service) };
631 }
632 }
633}
634
635#[cfg(target_os = "android")]
638pub use imp::ActivityManagerBinder;
639
640#[cfg(not(target_os = "android"))]
643pub struct ActivityManagerBinder;
644
645#[cfg(not(target_os = "android"))]
646impl ActivityManagerBinder {
647 pub fn open() -> Result<Self, CoreError> {
648 Err(CoreError::binder(-1, "binder:unsupported platform"))
649 }
650
651 pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
652 Err(CoreError::binder(-1, "binder:unsupported platform"))
653 }
654}