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// Host-runnable parcel allocators (String16 / byte[]) compiled on Android —
32// where `sys` uses them — and in `cargo test` on host, so the AOSP allocator
33// length convention is verified on every host commit (D1, Phase 1).
34#[cfg(any(target_os = "android", test))]
35mod alloc;
36
37#[cfg(any(target_os = "android", test))]
38mod display_tail;
39
40// Host-runnable probe decoders (the audio-active decode is exercised on every
41// host commit; the Android wrapper that opens the service is android-only).
42#[cfg(any(target_os = "android", test))]
43mod probe;
44
45// ─────────────────────────────────────────────────────────────────────────────
46// Android-only implementation
47// ─────────────────────────────────────────────────────────────────────────────
48
49#[cfg(target_os = "android")]
50mod am;
51#[cfg(target_os = "android")]
52mod audio;
53#[cfg(target_os = "android")]
54mod display;
55#[cfg(target_os = "android")]
56mod fps;
57#[cfg(target_os = "android")]
58mod handoff;
59#[cfg(target_os = "android")]
60mod raw;
61#[cfg(target_os = "android")]
62mod serve;
63#[cfg(target_os = "android")]
64mod sys;
65#[cfg(target_os = "android")]
66mod task_stack;
67
68// ── Public re-exports ─────────────────────────────────────────────────────────
69
70#[cfg(target_os = "android")]
71pub use am::{ActivityManager, TxCodes, last_foreground_pid, last_uid_event, resolve_tx_codes};
72#[cfg(target_os = "android")]
73pub use audio::PlaybackCallback;
74#[cfg(target_os = "android")]
75pub use display::{
76    DISPLAY_EVENT_FLAG_ADDED, DISPLAY_EVENT_FLAG_CHANGED, DISPLAY_EVENT_FLAG_REFRESH_RATE,
77    DISPLAY_EVENT_FLAG_REMOVED, DISPLAY_EVENT_FLAG_STATE, DISPLAY_STATE_DOZE,
78    DISPLAY_STATE_DOZE_SUSPEND, DISPLAY_STATE_OFF, DISPLAY_STATE_ON, DISPLAY_STATE_ON_SUSPEND,
79    DISPLAY_STATE_UNKNOWN, DISPLAY_STATE_VR, DisplayInfo, DisplayManager,
80};
81#[cfg(target_os = "android")]
82pub use fps::FpsListener;
83#[cfg(target_os = "android")]
84pub use handoff::{Handoff, ProviderHandle};
85#[cfg(target_os = "android")]
86pub use probe::audio_has_active_playback;
87#[cfg(target_os = "android")]
88pub use raw::RawBinderService;
89#[cfg(target_os = "android")]
90pub use serve::{DeathRecipient, OnewaySender, ServeCall, ServeHandler, ServingBinder};
91#[cfg(target_os = "android")]
92pub use sys::{OwnedBinder, ParcelReader, ParcelWriter};
93#[cfg(target_os = "android")]
94pub use task_stack::TaskStackListener;
95
96// ── Non-Android stubs ─────────────────────────────────────────────────────────
97
98#[cfg(not(target_os = "android"))]
99pub struct ActivityManager;
100
101#[cfg(not(target_os = "android"))]
102impl ActivityManager {
103    pub fn open() -> Result<Self, crate::CoreError> {
104        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
105    }
106    pub fn open_with_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
107        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
108    }
109    pub fn open_with_fgproc_observer() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
110        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
111    }
112    pub fn get_focused_task(&self) -> Result<Option<(i32, Option<String>)>, crate::CoreError> {
113        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
114    }
115    pub fn get_focused_package(&self) -> Result<Option<String>, crate::CoreError> {
116        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
117    }
118    pub fn get_focused_task_id(&self) -> Result<Option<i32>, crate::CoreError> {
119        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
120    }
121}
122
123#[cfg(not(target_os = "android"))]
124pub struct DisplayManager;
125
126#[cfg(not(target_os = "android"))]
127impl DisplayManager {
128    pub fn open_with_callback() -> Result<(Self, crate::fd::Fd), crate::CoreError> {
129        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
130    }
131    pub fn open_with_event_mask(_mask: u64) -> Result<(Self, crate::fd::Fd), crate::CoreError> {
132        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
133    }
134    pub fn is_interactive(&self) -> Result<bool, crate::CoreError> {
135        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
136    }
137    pub fn info(&self, _display_id: i32) -> Result<DisplayInfo, crate::CoreError> {
138        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
139    }
140}
141
142#[cfg(not(target_os = "android"))]
143#[derive(Clone, Copy, Debug, PartialEq, Default)]
144pub struct DisplayInfo {
145    pub active_mode_id: i32,
146    pub vsync_rate: f32,
147    pub peak_refresh_rate: f32,
148    pub render_frame_rate: f32,
149    pub state: i32,
150    pub is_interactive: bool,
151}
152
153#[cfg(not(target_os = "android"))]
154pub struct PlaybackCallback;
155
156#[cfg(not(target_os = "android"))]
157impl PlaybackCallback {
158    pub fn open() -> Result<(Self, crate::fd::Fd), crate::CoreError> {
159        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
160    }
161    pub fn register(&self) -> Result<(), crate::CoreError> {
162        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
163    }
164    pub fn unregister(&self) -> Result<(), crate::CoreError> {
165        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
166    }
167    pub fn audio_active(&self) -> bool {
168        false
169    }
170}
171
172#[cfg(not(target_os = "android"))]
173pub struct RawBinderService;
174
175#[cfg(not(target_os = "android"))]
176impl RawBinderService {
177    pub fn open(_service_name: &str, _descriptor: &str) -> Result<Self, crate::CoreError> {
178        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
179    }
180    pub fn transact_bool(&self, _code: u32) -> Result<bool, crate::CoreError> {
181        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
182    }
183    pub fn transact_i32(&self, _code: u32, _arg: i32) -> Result<(), crate::CoreError> {
184        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
185    }
186    pub fn transact_bool_arg(&self, _code: u32, _value: bool) -> Result<(), crate::CoreError> {
187        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
188    }
189}
190
191#[cfg(not(target_os = "android"))]
192pub struct FpsListener;
193
194#[cfg(not(target_os = "android"))]
195impl FpsListener {
196    pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
197        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
198    }
199    pub fn register(&mut self, _task_id: i32) -> Result<(), crate::CoreError> {
200        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
201    }
202    pub fn unregister(&mut self) -> Result<(), crate::CoreError> {
203        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
204    }
205    pub fn last_fps(&self) -> Option<f32> {
206        None
207    }
208    pub fn task_id(&self) -> Option<i32> {
209        None
210    }
211}
212
213#[cfg(not(target_os = "android"))]
214pub struct TaskStackListener;
215
216#[cfg(not(target_os = "android"))]
217impl TaskStackListener {
218    pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
219        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
220    }
221    pub fn register(&self) -> Result<(), crate::CoreError> {
222        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
223    }
224    pub fn unregister(&self) -> Result<(), crate::CoreError> {
225        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
226    }
227}
228
229#[cfg(not(target_os = "android"))]
230pub struct Handoff;
231
232#[cfg(not(target_os = "android"))]
233impl Handoff {
234    pub fn open() -> Result<Self, crate::CoreError> {
235        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
236    }
237    pub fn acquire_provider(
238        &self,
239        _authority: &str,
240        _user_id: i32,
241    ) -> Result<ProviderHandle, crate::CoreError> {
242        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
243    }
244    pub fn send_binder(
245        &self,
246        _handle: &ProviderHandle,
247        _authority: &str,
248        _method: &str,
249        _arg: &str,
250        _service_binder: *mut std::os::raw::c_void,
251    ) -> Result<(), crate::CoreError> {
252        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
253    }
254    pub fn remove_provider(&self, _authority: &str, _user_id: i32) -> Result<(), crate::CoreError> {
255        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
256    }
257    pub fn handoff(
258        &self,
259        _authority: &str,
260        _user_id: i32,
261        _method: &str,
262        _arg: &str,
263        _service_binder: *mut std::os::raw::c_void,
264    ) -> Result<i32, crate::CoreError> {
265        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
266    }
267}
268
269#[cfg(not(target_os = "android"))]
270pub struct ProviderHandle {
271    pub uid: i32,
272    pub no_release_needed: bool,
273}
274
275#[cfg(not(target_os = "android"))]
276pub struct TxCodes {
277    pub observer_code: u32,
278    pub query_code: u32,
279    pub api_mode: u8,
280    pub fg_code: u32,
281}
282
283#[cfg(not(target_os = "android"))]
284pub fn resolve_tx_codes() -> Result<TxCodes, crate::CoreError> {
285    Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
286}
287
288#[cfg(not(target_os = "android"))]
289pub fn last_foreground_pid() -> i32 {
290    0
291}
292
293// Stub parcel cursors so handlers can be written once and type-checked on
294// non-Android builds. They can never be constructed or called there; every
295// method returns an unsupported-platform error.
296#[cfg(not(target_os = "android"))]
297pub struct ParcelReader<'a> {
298    _marker: std::marker::PhantomData<&'a ()>,
299}
300
301#[cfg(not(target_os = "android"))]
302impl<'a> ParcelReader<'a> {
303    pub fn read_i32(&self) -> Result<i32, crate::CoreError> {
304        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
305    }
306    pub fn read_string(&self) -> Result<Option<String>, crate::CoreError> {
307        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
308    }
309    pub fn read_bytes(&self) -> Result<Option<Vec<u8>>, crate::CoreError> {
310        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
311    }
312    pub fn read_strong_binder(&self) -> Result<Option<OwnedBinder>, crate::CoreError> {
313        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
314    }
315    pub fn read_float(&self) -> Result<f32, crate::CoreError> {
316        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
317    }
318    pub fn read_int64(&self) -> Result<i64, crate::CoreError> {
319        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
320    }
321    pub fn read_bool(&self) -> Result<bool, crate::CoreError> {
322        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
323    }
324}
325
326#[cfg(not(target_os = "android"))]
327pub struct ParcelWriter<'a> {
328    _marker: std::marker::PhantomData<&'a ()>,
329}
330
331#[cfg(not(target_os = "android"))]
332impl<'a> ParcelWriter<'a> {
333    pub fn write_i32(&self, _v: i32) -> Result<(), crate::CoreError> {
334        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
335    }
336    pub fn write_strong_binder(
337        &self,
338        _b: *mut std::os::raw::c_void,
339    ) -> Result<(), crate::CoreError> {
340        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
341    }
342    pub fn write_string(&self, _s: Option<&str>) -> Result<(), crate::CoreError> {
343        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
344    }
345    pub fn write_bytes(&self, _b: Option<&[u8]>) -> Result<(), crate::CoreError> {
346        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
347    }
348}
349
350#[cfg(not(target_os = "android"))]
351pub struct OwnedBinder;
352
353#[cfg(not(target_os = "android"))]
354impl OwnedBinder {
355    pub fn as_raw(&self) -> *mut std::os::raw::c_void {
356        std::ptr::null_mut()
357    }
358}
359
360#[cfg(not(target_os = "android"))]
361pub struct ServeCall<'a> {
362    pub code: u32,
363    pub calling_uid: u32,
364    pub calling_pid: i32,
365    pub request: ParcelReader<'a>,
366    pub reply: Option<ParcelWriter<'a>>,
367}
368
369#[cfg(not(target_os = "android"))]
370pub type ServeHandler =
371    Box<dyn for<'a> FnMut(ServeCall<'a>) -> Result<(), crate::CoreError> + Send>;
372
373#[cfg(not(target_os = "android"))]
374pub struct ServingBinder;
375
376#[cfg(not(target_os = "android"))]
377impl ServingBinder {
378    pub fn open(_descriptor: &[u8], _handler: ServeHandler) -> Result<Self, crate::CoreError> {
379        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
380    }
381    pub fn open_bounded(
382        _descriptor: &[u8],
383        _handler: ServeHandler,
384        _max_inflight: usize,
385    ) -> Result<Self, crate::CoreError> {
386        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
387    }
388    pub fn as_raw(&self) -> *mut std::os::raw::c_void {
389        std::ptr::null_mut()
390    }
391    pub fn associate(&self, _target: &OwnedBinder) -> Result<(), crate::CoreError> {
392        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
393    }
394    pub fn push_oneway(
395        &self,
396        _target: &OwnedBinder,
397        _code: u32,
398        _writes: impl FnOnce(&ParcelWriter<'_>) -> Result<(), crate::CoreError>,
399    ) -> Result<(), crate::CoreError> {
400        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
401    }
402    pub fn death_recipient(&self, _on_died: Box<dyn FnMut() + Send>) -> DeathRecipient {
403        DeathRecipient {
404            _cb: Box::new(Box::new(|| {})),
405        }
406    }
407    pub fn oneway_sender(&self) -> OnewaySender {
408        OnewaySender
409    }
410}
411
412#[cfg(not(target_os = "android"))]
413#[derive(Clone, Copy)]
414pub struct OnewaySender;
415
416#[cfg(not(target_os = "android"))]
417impl OnewaySender {
418    pub fn push_oneway(
419        &self,
420        _target: &OwnedBinder,
421        _code: u32,
422        _writes: impl FnOnce(&ParcelWriter<'_>) -> Result<(), crate::CoreError>,
423    ) -> Result<(), crate::CoreError> {
424        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
425    }
426}
427
428#[cfg(not(target_os = "android"))]
429pub struct DeathRecipient {
430    _cb: Box<Box<dyn FnMut() + Send>>,
431}
432
433#[cfg(not(target_os = "android"))]
434impl DeathRecipient {
435    pub fn link(&self, _target: &OwnedBinder) -> Result<(), crate::CoreError> {
436        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
437    }
438    pub fn unlink(&self, _target: &OwnedBinder) -> Result<(), crate::CoreError> {
439        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
440    }
441}