Skip to main content

coreshift_core/binder/
mod.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/
4
5//! NDK binder primitives for querying Android system services.
6//!
7//! Uses `dlopen` on `libbinder_ndk.so` to avoid hard-linking against a library
8//! absent from older NDK toolchains or non-Android targets.
9//!
10//! ## Transaction code resolution
11//!
12//! Transaction codes are resolved fresh from `framework.jar` DEX on each
13//! startup; no persistent cache.
14//!
15//! ## Observer mode
16//!
17//! `ActivityManager::open_with_observer` registers this process as an
18//! `IProcessObserver` with ActivityManager. Callbacks fire when foreground
19//! activities change and signal an `eventfd` that callers can poll via epoll.
20//! After the eventfd fires, call `get_focused_package` to read the new value.
21
22// ─────────────────────────────────────────────────────────────────────────────
23// Host-runnable wire model (compiled on Android — where the handoff write path
24// runs — and in `cargo test` on host, so the bundle byte math is exercised on
25// every host commit; finding 28).
26// ─────────────────────────────────────────────────────────────────────────────
27
28#[cfg(any(target_os = "android", test))]
29mod wire;
30
31// ─────────────────────────────────────────────────────────────────────────────
32// Android-only implementation
33// ─────────────────────────────────────────────────────────────────────────────
34
35#[cfg(target_os = "android")]
36mod am;
37#[cfg(target_os = "android")]
38mod display;
39#[cfg(target_os = "android")]
40mod fps;
41#[cfg(target_os = "android")]
42mod handoff;
43#[cfg(target_os = "android")]
44mod raw;
45#[cfg(target_os = "android")]
46mod serve;
47#[cfg(target_os = "android")]
48mod sys;
49#[cfg(target_os = "android")]
50mod task_stack;
51
52// ── Public re-exports ─────────────────────────────────────────────────────────
53
54#[cfg(target_os = "android")]
55pub use am::{ActivityManager, TxCodes, last_foreground_pid, last_uid_event, resolve_tx_codes};
56#[cfg(target_os = "android")]
57pub use display::{DisplayInfo, DisplayManager};
58#[cfg(target_os = "android")]
59pub use fps::FpsListener;
60#[cfg(target_os = "android")]
61pub use handoff::{Handoff, ProviderHandle};
62#[cfg(target_os = "android")]
63pub use raw::RawBinderService;
64#[cfg(target_os = "android")]
65pub use serve::{DeathRecipient, OnewaySender, ServeCall, ServeHandler, ServingBinder};
66#[cfg(target_os = "android")]
67pub use sys::{OwnedBinder, ParcelReader, ParcelWriter};
68#[cfg(target_os = "android")]
69pub use task_stack::TaskStackListener;
70
71// ── Non-Android stubs ─────────────────────────────────────────────────────────
72
73#[cfg(not(target_os = "android"))]
74pub struct ActivityManager;
75
76#[cfg(not(target_os = "android"))]
77impl ActivityManager {
78    pub fn open() -> Result<Self, crate::CoreError> {
79        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
80    }
81    pub fn open_with_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
82        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
83    }
84    pub fn open_with_fgproc_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
85        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
86    }
87    pub fn get_focused_task(&self) -> Result<Option<(i32, Option<String>)>, crate::CoreError> {
88        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
89    }
90    pub fn get_focused_package(&self) -> Result<Option<String>, crate::CoreError> {
91        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
92    }
93    pub fn get_focused_task_id(&self) -> Result<Option<i32>, crate::CoreError> {
94        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
95    }
96}
97
98#[cfg(not(target_os = "android"))]
99pub struct DisplayManager;
100
101#[cfg(not(target_os = "android"))]
102impl DisplayManager {
103    pub fn open_with_callback() -> Result<(Self, crate::fd::Fd), crate::CoreError> {
104        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
105    }
106    pub fn is_interactive(&self) -> Result<bool, crate::CoreError> {
107        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
108    }
109    pub fn info(&self, _display_id: i32) -> Result<DisplayInfo, crate::CoreError> {
110        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
111    }
112}
113
114#[cfg(not(target_os = "android"))]
115#[derive(Clone, Copy, Debug, PartialEq, Default)]
116pub struct DisplayInfo {
117    pub active_mode_id: i32,
118    pub vsync_rate: f32,
119    pub peak_refresh_rate: f32,
120    pub render_frame_rate: f32,
121    pub is_interactive: bool,
122}
123
124#[cfg(not(target_os = "android"))]
125pub struct RawBinderService;
126
127#[cfg(not(target_os = "android"))]
128impl RawBinderService {
129    pub fn open(_service_name: &str) -> Result<Self, crate::CoreError> {
130        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
131    }
132    pub fn transact_bool(&self, _code: u32) -> Result<bool, crate::CoreError> {
133        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
134    }
135    pub fn transact_i32(&self, _code: u32, _arg: i32) -> Result<(), crate::CoreError> {
136        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
137    }
138}
139
140#[cfg(not(target_os = "android"))]
141pub struct FpsListener;
142
143#[cfg(not(target_os = "android"))]
144impl FpsListener {
145    pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
146        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
147    }
148    pub fn register(&mut self, _task_id: i32) -> Result<(), crate::CoreError> {
149        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
150    }
151    pub fn unregister(&mut self) -> Result<(), crate::CoreError> {
152        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
153    }
154    pub fn last_fps(&self) -> Option<f32> {
155        None
156    }
157    pub fn task_id(&self) -> Option<i32> {
158        None
159    }
160}
161
162#[cfg(not(target_os = "android"))]
163pub struct TaskStackListener;
164
165#[cfg(not(target_os = "android"))]
166impl TaskStackListener {
167    pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
168        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
169    }
170    pub fn register(&self) -> Result<(), crate::CoreError> {
171        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
172    }
173    pub fn unregister(&self) -> Result<(), crate::CoreError> {
174        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
175    }
176}
177
178#[cfg(not(target_os = "android"))]
179pub struct Handoff;
180
181#[cfg(not(target_os = "android"))]
182impl Handoff {
183    pub fn open() -> Result<Self, crate::CoreError> {
184        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
185    }
186    pub fn acquire_provider(
187        &self,
188        _authority: &str,
189        _user_id: i32,
190    ) -> Result<ProviderHandle, crate::CoreError> {
191        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
192    }
193    pub fn send_binder(
194        &self,
195        _handle: &ProviderHandle,
196        _authority: &str,
197        _method: &str,
198        _arg: &str,
199        _service_binder: *mut std::os::raw::c_void,
200    ) -> Result<(), crate::CoreError> {
201        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
202    }
203    pub fn remove_provider(&self, _authority: &str, _user_id: i32) -> Result<(), crate::CoreError> {
204        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
205    }
206    pub fn handoff(
207        &self,
208        _authority: &str,
209        _user_id: i32,
210        _method: &str,
211        _arg: &str,
212        _service_binder: *mut std::os::raw::c_void,
213    ) -> Result<i32, crate::CoreError> {
214        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
215    }
216}
217
218#[cfg(not(target_os = "android"))]
219pub struct ProviderHandle {
220    pub uid: i32,
221    pub no_release_needed: bool,
222}
223
224#[cfg(not(target_os = "android"))]
225pub struct TxCodes {
226    pub observer_code: u32,
227    pub query_code: u32,
228    pub api_mode: u8,
229    pub fg_code: u32,
230}
231
232#[cfg(not(target_os = "android"))]
233pub fn resolve_tx_codes() -> Result<TxCodes, crate::CoreError> {
234    Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
235}
236
237#[cfg(not(target_os = "android"))]
238pub fn last_foreground_pid() -> i32 {
239    0
240}
241
242// Stub parcel cursors so handlers can be written once and type-checked on
243// non-Android builds. They can never be constructed or called there; every
244// method returns an unsupported-platform error.
245#[cfg(not(target_os = "android"))]
246pub struct ParcelReader<'a> {
247    _marker: std::marker::PhantomData<&'a ()>,
248}
249
250#[cfg(not(target_os = "android"))]
251impl<'a> ParcelReader<'a> {
252    pub fn read_i32(&self) -> Result<i32, crate::CoreError> {
253        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
254    }
255    pub fn read_string(&self) -> Result<Option<String>, crate::CoreError> {
256        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
257    }
258    pub fn read_strong_binder(&self) -> Result<Option<OwnedBinder>, crate::CoreError> {
259        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
260    }
261    pub fn read_float(&self) -> Result<f32, crate::CoreError> {
262        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
263    }
264    pub fn read_int64(&self) -> Result<i64, crate::CoreError> {
265        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
266    }
267    pub fn read_bool(&self) -> Result<bool, crate::CoreError> {
268        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
269    }
270}
271
272#[cfg(not(target_os = "android"))]
273pub struct ParcelWriter<'a> {
274    _marker: std::marker::PhantomData<&'a ()>,
275}
276
277#[cfg(not(target_os = "android"))]
278impl<'a> ParcelWriter<'a> {
279    pub fn write_i32(&self, _v: i32) -> Result<(), crate::CoreError> {
280        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
281    }
282    pub fn write_strong_binder(
283        &self,
284        _b: *mut std::os::raw::c_void,
285    ) -> Result<(), crate::CoreError> {
286        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
287    }
288    pub fn write_string(&self, _s: Option<&str>) -> Result<(), crate::CoreError> {
289        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
290    }
291}
292
293#[cfg(not(target_os = "android"))]
294pub struct OwnedBinder;
295
296#[cfg(not(target_os = "android"))]
297impl OwnedBinder {
298    pub fn as_raw(&self) -> *mut std::os::raw::c_void {
299        std::ptr::null_mut()
300    }
301}
302
303#[cfg(not(target_os = "android"))]
304pub struct ServeCall<'a> {
305    pub code: u32,
306    pub calling_uid: u32,
307    pub calling_pid: i32,
308    pub request: ParcelReader<'a>,
309    pub reply: Option<ParcelWriter<'a>>,
310}
311
312#[cfg(not(target_os = "android"))]
313pub type ServeHandler =
314    Box<dyn for<'a> FnMut(ServeCall<'a>) -> Result<(), crate::CoreError> + Send>;
315
316#[cfg(not(target_os = "android"))]
317pub struct ServingBinder;
318
319#[cfg(not(target_os = "android"))]
320impl ServingBinder {
321    pub fn open(_descriptor: &[u8], _handler: ServeHandler) -> Result<Self, crate::CoreError> {
322        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
323    }
324    pub fn open_bounded(
325        _descriptor: &[u8],
326        _handler: ServeHandler,
327        _max_inflight: usize,
328    ) -> Result<Self, crate::CoreError> {
329        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
330    }
331    pub fn as_raw(&self) -> *mut std::os::raw::c_void {
332        std::ptr::null_mut()
333    }
334    pub fn associate(&self, _target: &OwnedBinder) -> Result<(), crate::CoreError> {
335        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
336    }
337    pub fn push_oneway(
338        &self,
339        _target: &OwnedBinder,
340        _code: u32,
341        _writes: impl FnOnce(&ParcelWriter<'_>) -> Result<(), crate::CoreError>,
342    ) -> Result<(), crate::CoreError> {
343        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
344    }
345    pub fn death_recipient(&self, _on_died: Box<dyn FnMut() + Send>) -> DeathRecipient {
346        DeathRecipient {
347            _cb: Box::new(Box::new(|| {})),
348        }
349    }
350    pub fn oneway_sender(&self) -> OnewaySender {
351        OnewaySender
352    }
353}
354
355#[cfg(not(target_os = "android"))]
356#[derive(Clone, Copy)]
357pub struct OnewaySender;
358
359#[cfg(not(target_os = "android"))]
360impl OnewaySender {
361    pub fn push_oneway(
362        &self,
363        _target: &OwnedBinder,
364        _code: u32,
365        _writes: impl FnOnce(&ParcelWriter<'_>) -> Result<(), crate::CoreError>,
366    ) -> Result<(), crate::CoreError> {
367        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
368    }
369}
370
371#[cfg(not(target_os = "android"))]
372pub struct DeathRecipient {
373    _cb: Box<Box<dyn FnMut() + Send>>,
374}
375
376#[cfg(not(target_os = "android"))]
377impl DeathRecipient {
378    pub fn link(&self, _target: &OwnedBinder) -> Result<(), crate::CoreError> {
379        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
380    }
381    pub fn unlink(&self, _target: &OwnedBinder) -> Result<(), crate::CoreError> {
382        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
383    }
384}