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