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