1use crate::CoreError;
23
24#[cfg(target_os = "android")]
29mod imp {
30 use super::*;
31 use crate::android_property::android_property_get;
32 use std::os::raw::{c_char, c_void};
33
34 const STATUS_OK: i32 = 0;
37 const STATUS_UNKNOWN_TRANSACTION: i32 = -2;
38
39 const EX_NONE: i32 = 0;
41
42 const ACTIVITY_MANAGER_DESCRIPTOR: &[u8] = b"android.app.IActivityManager\0";
45 const ACTIVITY_SERVICE_NAME: &[u8] = b"activity\0";
46 const LIBBINDER_NDK_PATH: &[u8] = b"/system/lib64/libbinder_ndk.so\0";
47
48 const TX_CACHE_PATH: &str = "/data/local/tmp/coreshift/tx_code.txt";
55
56 #[derive(Clone, Copy)]
59 struct TxEntry { api: u32, code: i32, legacy: bool }
60
61 static TX_TABLE: &[TxEntry] = &[
62 TxEntry { api: 29, code: 157, legacy: true },
63 TxEntry { api: 30, code: 168, legacy: false },
64 TxEntry { api: 31, code: 176, legacy: false },
65 TxEntry { api: 32, code: 178, legacy: false },
66 TxEntry { api: 33, code: 181, legacy: false },
67 TxEntry { api: 34, code: 183, legacy: false },
68 TxEntry { api: 35, code: 187, legacy: false },
69 ];
70
71 const PROBE_WINDOW: i32 = 12;
72
73 type AIBinder = c_void;
76 #[allow(non_camel_case_types)]
77 type AIBinder_Class = c_void;
78 type AParcel = c_void;
79 type BinderStatus = i32;
80 type StringAllocator =
81 unsafe extern "C" fn(*mut c_void, i32, *mut *mut c_char) -> bool;
82
83 unsafe extern "C" fn on_create(_: *mut c_void) -> *mut c_void { std::ptr::null_mut() }
86 unsafe extern "C" fn on_destroy(_: *mut c_void) {}
87 unsafe extern "C" fn on_transact(
88 _: *mut AIBinder, _: u32, _: *const AParcel, _: *mut AParcel,
89 ) -> BinderStatus { STATUS_UNKNOWN_TRANSACTION }
90
91 unsafe extern "C" fn string_alloc(
94 cookie: *mut c_void,
95 length: i32,
96 buffer: *mut *mut c_char,
97 ) -> bool {
98 if length < 0 { return true; } let s = unsafe { &mut *(cookie as *mut StringBuf) };
100 s.0.reserve_exact(length as usize + 1);
101 unsafe { s.0.as_mut_vec().resize(length as usize + 1, 0) };
102 unsafe { *buffer = s.0.as_mut_ptr() as *mut c_char };
103 true
104 }
105
106 struct StringBuf(String);
107
108 impl StringBuf {
109 fn new() -> Self { Self(String::new()) }
110
111 fn finish(mut self) -> Option<String> {
112 if let Some(pos) = self.0.as_bytes().iter().position(|&b| b == 0) {
114 unsafe { self.0.as_mut_vec().truncate(pos) };
115 }
116 if self.0.is_empty() { None } else { Some(self.0) }
117 }
118 }
119
120 struct Vtable {
123 get_service: unsafe extern "C" fn(*const c_char) -> *mut AIBinder,
124 #[allow(dead_code)]
125 wait_for_service: unsafe extern "C" fn(*const c_char) -> *mut AIBinder,
126 class_define: unsafe extern "C" fn(
127 *const c_char,
128 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
129 unsafe extern "C" fn(*mut c_void),
130 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
131 ) -> *mut AIBinder_Class,
132 associate_class: unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool,
133 prepare_transaction: unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus,
134 transact: unsafe extern "C" fn(*mut AIBinder, u32, *mut *mut AParcel, *mut *mut AParcel, u32) -> BinderStatus,
135 dec_strong: unsafe extern "C" fn(*mut AIBinder),
136 parcel_delete: unsafe extern "C" fn(*mut AParcel),
137 read_int32: unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus,
138 #[allow(dead_code)]
139 read_bool: unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus,
140 read_string: unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus,
141 }
142
143 struct DlHandle(*mut c_void);
146 unsafe impl Send for DlHandle {}
147 impl Drop for DlHandle {
148 fn drop(&mut self) {
149 if !self.0.is_null() { unsafe { libc::dlclose(self.0) }; }
150 }
151 }
152
153 struct OwnedParcel {
154 ptr: *mut AParcel,
155 delete: unsafe extern "C" fn(*mut AParcel),
156 }
157 impl Drop for OwnedParcel {
158 fn drop(&mut self) {
159 if !self.ptr.is_null() { unsafe { (self.delete)(self.ptr) }; }
160 }
161 }
162
163 struct OwnedBinder {
164 ptr: *mut AIBinder,
165 dec_strong: unsafe extern "C" fn(*mut AIBinder),
166 }
167 unsafe impl Send for OwnedBinder {}
168 impl Drop for OwnedBinder {
169 fn drop(&mut self) {
170 if !self.ptr.is_null() { unsafe { (self.dec_strong)(self.ptr) }; }
171 }
172 }
173
174 macro_rules! dlsym_fn {
177 ($handle:expr, $name:literal, $ty:ty) => {{
178 let sym = unsafe {
179 libc::dlsym($handle, concat!($name, "\0").as_ptr() as *const c_char)
180 };
181 if sym.is_null() {
182 return Err(CoreError::binder(-1, concat!("dlsym:", $name)));
183 }
184 unsafe { std::mem::transmute::<*mut c_void, $ty>(sym) }
185 }};
186 }
187
188 fn load_vtable(handle: *mut c_void) -> Result<Vtable, CoreError> {
189 Ok(Vtable {
190 get_service: dlsym_fn!(handle, "AServiceManager_getService",
191 unsafe extern "C" fn(*const c_char) -> *mut AIBinder),
192 wait_for_service: dlsym_fn!(handle, "AServiceManager_waitForService",
193 unsafe extern "C" fn(*const c_char) -> *mut AIBinder),
194 class_define: dlsym_fn!(handle, "AIBinder_Class_define",
195 unsafe extern "C" fn(
196 *const c_char,
197 unsafe extern "C" fn(*mut c_void) -> *mut c_void,
198 unsafe extern "C" fn(*mut c_void),
199 unsafe extern "C" fn(*mut AIBinder, u32, *const AParcel, *mut AParcel) -> BinderStatus,
200 ) -> *mut AIBinder_Class),
201 associate_class: dlsym_fn!(handle, "AIBinder_associateClass",
202 unsafe extern "C" fn(*mut AIBinder, *mut AIBinder_Class) -> bool),
203 prepare_transaction: dlsym_fn!(handle, "AIBinder_prepareTransaction",
204 unsafe extern "C" fn(*mut AIBinder, *mut *mut AParcel) -> BinderStatus),
205 transact: dlsym_fn!(handle, "AIBinder_transact",
206 unsafe extern "C" fn(*mut AIBinder, u32, *mut *mut AParcel, *mut *mut AParcel, u32) -> BinderStatus),
207 dec_strong: dlsym_fn!(handle, "AIBinder_decStrong",
208 unsafe extern "C" fn(*mut AIBinder)),
209 parcel_delete: dlsym_fn!(handle, "AParcel_delete",
210 unsafe extern "C" fn(*mut AParcel)),
211 read_int32: dlsym_fn!(handle, "AParcel_readInt32",
212 unsafe extern "C" fn(*const AParcel, *mut i32) -> BinderStatus),
213 read_bool: dlsym_fn!(handle, "AParcel_readBool",
214 unsafe extern "C" fn(*const AParcel, *mut bool) -> BinderStatus),
215 read_string: dlsym_fn!(handle, "AParcel_readString",
216 unsafe extern "C" fn(*const AParcel, *mut c_void, StringAllocator) -> BinderStatus),
217 })
218 }
219
220 struct ParcelReader<'a> {
223 vt: &'a Vtable,
224 parcel: &'a OwnedParcel,
225 }
226
227 impl<'a> ParcelReader<'a> {
228 fn read_i32(&self) -> Result<i32, CoreError> {
229 let mut v = 0i32;
230 let s = unsafe { (self.vt.read_int32)(self.parcel.ptr, &mut v) };
231 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readInt32")); }
232 Ok(v)
233 }
234
235 fn read_string(&self) -> Result<Option<String>, CoreError> {
236 let mut buf = StringBuf::new();
237 let s = unsafe {
238 (self.vt.read_string)(
239 self.parcel.ptr,
240 &mut buf as *mut StringBuf as *mut c_void,
241 string_alloc,
242 )
243 };
244 if s != STATUS_OK { return Err(CoreError::binder(s, "AParcel_readString")); }
245 Ok(buf.finish())
246 }
247
248 fn skip_i32s(&self, n: usize) -> Result<(), CoreError> {
249 for _ in 0..n { self.read_i32()?; }
250 Ok(())
251 }
252
253 fn skip_int_array(&self) -> Result<(), CoreError> {
254 let count = self.read_i32()?.max(0) as usize;
255 self.skip_i32s(count)
256 }
257
258 fn read_first_package_from_names(&self) -> Result<Option<String>, CoreError> {
261 let count = self.read_i32()?.max(0) as usize;
262 let mut first: Option<String> = None;
263 for _ in 0..count {
264 let s = self.read_string()?;
265 if first.is_none() {
266 first = s.and_then(|c| c.split('/').next().map(str::to_owned));
267 }
268 }
269 Ok(first)
270 }
271 }
272
273 fn parse_root_task_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
281 let scratch = r.read_i32()?;
283 if scratch != 0 { r.skip_i32s(4)?; }
284 r.skip_int_array()?; r.read_first_package_from_names() }
287
288 fn parse_stack_info_body(r: &ParcelReader<'_>) -> Result<Option<String>, CoreError> {
290 r.skip_i32s(5)?; r.skip_int_array()?; r.read_first_package_from_names() }
294
295 fn read_tx_cache() -> Option<(i32, bool)> {
298 let text = std::fs::read_to_string(TX_CACHE_PATH).ok()?;
299 let mut parts = text.split_whitespace();
301 let _observer: i32 = parts.next()?.parse().ok()?;
302 let tx_code: i32 = parts.next()?.parse().ok()?;
303 let api_mode: i32 = parts.next()?.parse().ok()?;
304 if tx_code <= 0 { return None; }
305 Some((tx_code, api_mode == 2)) }
307
308 fn sdk_version() -> Option<u32> {
309 android_property_get("ro.build.version.sdk")
310 .and_then(|s| s.trim().parse().ok())
311 }
312
313 fn table_lookup(api: u32) -> Option<(i32, bool)> {
314 TX_TABLE.iter()
315 .filter(|e| e.api <= api)
316 .last()
317 .map(|e| (e.code, e.legacy))
318 }
319
320 fn probe_window(api: u32) -> impl Iterator<Item = (i32, bool)> {
321 let centre = table_lookup(api).map(|(c, _)| c).unwrap_or(170);
322 let legacy_threshold = 165i32;
323 ((centre - PROBE_WINDOW)..(centre + PROBE_WINDOW))
324 .map(move |c| (c, c < legacy_threshold))
325 }
326
327 pub struct ActivityManagerBinder {
330 _lib: DlHandle,
331 vt: Vtable,
332 _class: *mut AIBinder_Class,
333 service: OwnedBinder,
334 tx_code: i32,
335 legacy: bool,
336 }
337
338 unsafe impl Send for ActivityManagerBinder {}
340
341 impl ActivityManagerBinder {
342 pub fn open() -> Result<Self, CoreError> {
343 let handle = unsafe {
344 libc::dlopen(
345 LIBBINDER_NDK_PATH.as_ptr() as *const c_char,
346 libc::RTLD_NOW | libc::RTLD_LOCAL,
347 )
348 };
349 if handle.is_null() {
350 return Err(CoreError::binder(-1, "dlopen:libbinder_ndk.so"));
351 }
352 let lib = DlHandle(handle);
353 let vt = load_vtable(handle)?;
354
355 let class = unsafe {
356 (vt.class_define)(
357 ACTIVITY_MANAGER_DESCRIPTOR.as_ptr() as *const c_char,
358 on_create, on_destroy, on_transact,
359 )
360 };
361 if class.is_null() {
362 return Err(CoreError::binder(-1, "AIBinder_Class_define"));
363 }
364
365 let raw_service = unsafe {
366 (vt.get_service)(ACTIVITY_SERVICE_NAME.as_ptr() as *const c_char)
367 };
368 if raw_service.is_null() {
369 return Err(CoreError::binder(-1, "AServiceManager_getService:activity"));
370 }
371 unsafe { (vt.associate_class)(raw_service, class) };
372
373 let service = OwnedBinder { ptr: raw_service, dec_strong: vt.dec_strong };
374 let (tx_code, legacy) = Self::resolve_tx(&vt, raw_service, class)?;
375
376 Ok(Self { _lib: lib, vt, _class: class, service, tx_code, legacy })
377 }
378
379 fn resolve_tx(
380 vt: &Vtable,
381 service: *mut AIBinder,
382 _class: *mut AIBinder_Class,
383 ) -> Result<(i32, bool), CoreError> {
384 if let Some(pair) = read_tx_cache() {
385 return Ok(pair);
386 }
387
388 let api = sdk_version().unwrap_or(30);
389
390 let pair = if let Some(pair) = table_lookup(api) {
391 if Self::tx_code_valid(vt, service, pair.0) {
392 pair
393 } else {
394 probe_window(api)
395 .find(|&(code, _)| Self::tx_code_valid(vt, service, code))
396 .ok_or_else(|| CoreError::binder(-1, "tx_code_resolution"))?
397 }
398 } else {
399 probe_window(api)
400 .find(|&(code, _)| Self::tx_code_valid(vt, service, code))
401 .ok_or_else(|| CoreError::binder(-1, "tx_code_resolution"))?
402 };
403
404 let api_mode = if pair.1 { 2i32 } else { 1i32 };
408 let _ = std::fs::create_dir_all("/data/local/tmp/coreshift");
409 let _ = std::fs::write(TX_CACHE_PATH, format!("0 {} {} 0\n", pair.0, api_mode));
410
411 Ok(pair)
412 }
413
414 fn tx_code_valid(vt: &Vtable, service: *mut AIBinder, code: i32) -> bool {
415 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
416 if unsafe { (vt.prepare_transaction)(service, &mut in_ptr) } != STATUS_OK {
417 return false;
418 }
419 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
420 let s = unsafe {
421 (vt.transact)(service, code as u32, &mut in_ptr, &mut out_ptr, 0)
422 };
423 let out = OwnedParcel { ptr: out_ptr, delete: vt.parcel_delete };
424 if s != STATUS_OK { return false; }
425 let r = ParcelReader { vt, parcel: &out };
426 r.read_i32().map(|ex| ex == EX_NONE).unwrap_or(false)
427 }
429
430 fn do_transact(&self) -> Result<OwnedParcel, CoreError> {
431 let mut in_ptr: *mut AParcel = std::ptr::null_mut();
432 let s = unsafe { (self.vt.prepare_transaction)(self.service.ptr, &mut in_ptr) };
433 if s != STATUS_OK {
434 return Err(CoreError::binder(s, "AIBinder_prepareTransaction"));
435 }
436 let mut out_ptr: *mut AParcel = std::ptr::null_mut();
437 let s = unsafe {
438 (self.vt.transact)(
439 self.service.ptr, self.tx_code as u32,
440 &mut in_ptr, &mut out_ptr, 0,
441 )
442 };
443 let out = OwnedParcel { ptr: out_ptr, delete: self.vt.parcel_delete };
444 if s != STATUS_OK {
445 return Err(CoreError::binder(s, "AIBinder_transact"));
446 }
447 Ok(out)
448 }
449
450 pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
451 let out = self.do_transact()?;
452 let r = ParcelReader { vt: &self.vt, parcel: &out };
453
454 let ex = r.read_i32()?;
455 if ex != EX_NONE {
456 return Err(CoreError::binder(ex, "getFocusedTask:exception"));
457 }
458 let present = r.read_i32()?;
459 if present == 0 {
460 return Ok(None);
461 }
462 if self.legacy {
463 parse_stack_info_body(&r)
464 } else {
465 parse_root_task_info_body(&r)
466 }
467 }
469 }
470}
471
472#[cfg(target_os = "android")]
475pub use imp::ActivityManagerBinder;
476
477#[cfg(not(target_os = "android"))]
480pub struct ActivityManagerBinder;
481
482#[cfg(not(target_os = "android"))]
483impl ActivityManagerBinder {
484 pub fn open() -> Result<Self, CoreError> {
485 Err(CoreError::binder(-1, "binder:unsupported platform"))
486 }
487
488 pub fn get_focused_package(&self) -> Result<Option<String>, CoreError> {
489 Err(CoreError::binder(-1, "binder:unsupported platform"))
490 }
491}