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    pub fn transact_bool_arg(&self, _code: u32, _value: bool) -> Result<(), crate::CoreError> {
157        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
158    }
159}
160
161#[cfg(not(target_os = "android"))]
162pub struct FpsListener;
163
164#[cfg(not(target_os = "android"))]
165impl FpsListener {
166    pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
167        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
168    }
169    pub fn register(&mut self, _task_id: i32) -> Result<(), crate::CoreError> {
170        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
171    }
172    pub fn unregister(&mut self) -> Result<(), crate::CoreError> {
173        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
174    }
175    pub fn last_fps(&self) -> Option<f32> {
176        None
177    }
178    pub fn task_id(&self) -> Option<i32> {
179        None
180    }
181}
182
183#[cfg(not(target_os = "android"))]
184pub struct TaskStackListener;
185
186#[cfg(not(target_os = "android"))]
187impl TaskStackListener {
188    pub fn open() -> Result<(Self, std::os::fd::OwnedFd), crate::CoreError> {
189        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
190    }
191    pub fn register(&self) -> Result<(), crate::CoreError> {
192        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
193    }
194    pub fn unregister(&self) -> Result<(), crate::CoreError> {
195        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
196    }
197}
198
199#[cfg(not(target_os = "android"))]
200pub struct Handoff;
201
202#[cfg(not(target_os = "android"))]
203impl Handoff {
204    pub fn open() -> Result<Self, crate::CoreError> {
205        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
206    }
207    pub fn acquire_provider(
208        &self,
209        _authority: &str,
210        _user_id: i32,
211    ) -> Result<ProviderHandle, crate::CoreError> {
212        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
213    }
214    pub fn send_binder(
215        &self,
216        _handle: &ProviderHandle,
217        _authority: &str,
218        _method: &str,
219        _arg: &str,
220        _service_binder: *mut std::os::raw::c_void,
221    ) -> Result<(), crate::CoreError> {
222        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
223    }
224    pub fn remove_provider(&self, _authority: &str, _user_id: i32) -> Result<(), crate::CoreError> {
225        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
226    }
227    pub fn handoff(
228        &self,
229        _authority: &str,
230        _user_id: i32,
231        _method: &str,
232        _arg: &str,
233        _service_binder: *mut std::os::raw::c_void,
234    ) -> Result<i32, crate::CoreError> {
235        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
236    }
237}
238
239#[cfg(not(target_os = "android"))]
240pub struct ProviderHandle {
241    pub uid: i32,
242    pub no_release_needed: bool,
243}
244
245#[cfg(not(target_os = "android"))]
246pub struct TxCodes {
247    pub observer_code: u32,
248    pub query_code: u32,
249    pub api_mode: u8,
250    pub fg_code: u32,
251}
252
253#[cfg(not(target_os = "android"))]
254pub fn resolve_tx_codes() -> Result<TxCodes, crate::CoreError> {
255    Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
256}
257
258#[cfg(not(target_os = "android"))]
259pub fn last_foreground_pid() -> i32 {
260    0
261}
262
263// Stub parcel cursors so handlers can be written once and type-checked on
264// non-Android builds. They can never be constructed or called there; every
265// method returns an unsupported-platform error.
266#[cfg(not(target_os = "android"))]
267pub struct ParcelReader<'a> {
268    _marker: std::marker::PhantomData<&'a ()>,
269}
270
271#[cfg(not(target_os = "android"))]
272impl<'a> ParcelReader<'a> {
273    pub fn read_i32(&self) -> Result<i32, crate::CoreError> {
274        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
275    }
276    pub fn read_string(&self) -> Result<Option<String>, crate::CoreError> {
277        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
278    }
279    pub fn read_bytes(&self) -> Result<Option<Vec<u8>>, crate::CoreError> {
280        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
281    }
282    pub fn read_strong_binder(&self) -> Result<Option<OwnedBinder>, crate::CoreError> {
283        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
284    }
285    pub fn read_float(&self) -> Result<f32, crate::CoreError> {
286        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
287    }
288    pub fn read_int64(&self) -> Result<i64, crate::CoreError> {
289        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
290    }
291    pub fn read_bool(&self) -> Result<bool, crate::CoreError> {
292        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
293    }
294}
295
296#[cfg(not(target_os = "android"))]
297pub struct ParcelWriter<'a> {
298    _marker: std::marker::PhantomData<&'a ()>,
299}
300
301#[cfg(not(target_os = "android"))]
302impl<'a> ParcelWriter<'a> {
303    pub fn write_i32(&self, _v: i32) -> Result<(), crate::CoreError> {
304        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
305    }
306    pub fn write_strong_binder(
307        &self,
308        _b: *mut std::os::raw::c_void,
309    ) -> Result<(), crate::CoreError> {
310        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
311    }
312    pub fn write_string(&self, _s: Option<&str>) -> Result<(), crate::CoreError> {
313        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
314    }
315    pub fn write_bytes(&self, _b: Option<&[u8]>) -> Result<(), crate::CoreError> {
316        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
317    }
318}
319
320#[cfg(not(target_os = "android"))]
321pub struct OwnedBinder;
322
323#[cfg(not(target_os = "android"))]
324impl OwnedBinder {
325    pub fn as_raw(&self) -> *mut std::os::raw::c_void {
326        std::ptr::null_mut()
327    }
328}
329
330#[cfg(not(target_os = "android"))]
331pub struct ServeCall<'a> {
332    pub code: u32,
333    pub calling_uid: u32,
334    pub calling_pid: i32,
335    pub request: ParcelReader<'a>,
336    pub reply: Option<ParcelWriter<'a>>,
337}
338
339#[cfg(not(target_os = "android"))]
340pub type ServeHandler =
341    Box<dyn for<'a> FnMut(ServeCall<'a>) -> Result<(), crate::CoreError> + Send>;
342
343#[cfg(not(target_os = "android"))]
344pub struct ServingBinder;
345
346#[cfg(not(target_os = "android"))]
347impl ServingBinder {
348    pub fn open(_descriptor: &[u8], _handler: ServeHandler) -> Result<Self, crate::CoreError> {
349        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
350    }
351    pub fn open_bounded(
352        _descriptor: &[u8],
353        _handler: ServeHandler,
354        _max_inflight: usize,
355    ) -> Result<Self, crate::CoreError> {
356        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
357    }
358    pub fn as_raw(&self) -> *mut std::os::raw::c_void {
359        std::ptr::null_mut()
360    }
361    pub fn associate(&self, _target: &OwnedBinder) -> Result<(), crate::CoreError> {
362        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
363    }
364    pub fn push_oneway(
365        &self,
366        _target: &OwnedBinder,
367        _code: u32,
368        _writes: impl FnOnce(&ParcelWriter<'_>) -> Result<(), crate::CoreError>,
369    ) -> Result<(), crate::CoreError> {
370        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
371    }
372    pub fn death_recipient(&self, _on_died: Box<dyn FnMut() + Send>) -> DeathRecipient {
373        DeathRecipient {
374            _cb: Box::new(Box::new(|| {})),
375        }
376    }
377    pub fn oneway_sender(&self) -> OnewaySender {
378        OnewaySender
379    }
380}
381
382#[cfg(not(target_os = "android"))]
383#[derive(Clone, Copy)]
384pub struct OnewaySender;
385
386#[cfg(not(target_os = "android"))]
387impl OnewaySender {
388    pub fn push_oneway(
389        &self,
390        _target: &OwnedBinder,
391        _code: u32,
392        _writes: impl FnOnce(&ParcelWriter<'_>) -> Result<(), crate::CoreError>,
393    ) -> Result<(), crate::CoreError> {
394        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
395    }
396}
397
398#[cfg(not(target_os = "android"))]
399pub struct DeathRecipient {
400    _cb: Box<Box<dyn FnMut() + Send>>,
401}
402
403#[cfg(not(target_os = "android"))]
404impl DeathRecipient {
405    pub fn link(&self, _target: &OwnedBinder) -> Result<(), crate::CoreError> {
406        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
407    }
408    pub fn unlink(&self, _target: &OwnedBinder) -> Result<(), crate::CoreError> {
409        Err(crate::CoreError::binder(-1, "binder:unsupported platform"))
410    }
411}