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