plat/lib.rs
1// plat -- the platform layer: one module per OS with the same functions [src/plat]
2//
3// process: entry point (calls the app's jfgui_main), args(), arg_value(name), exit(code),
4// std_start() (feature std: the start of a program with std, from its fn main),
5// write_stdout / write_stderr, time_us(), sleep_ms(ms), date()
6// environment: env(name) (= getenv), setenv(name, Some / None), config_dir(), temp_dir(), cwd()
7// folders: user_dir(DIR_DOCUMENTS ..) (desktop, documents, downloads, pictures, music,
8// videos: Known Folders / XDG user dirs), log_dir() (dirs.rs)
9// files: read_file(path), write_file(path, data) (native: exclusive sibling + rename),
10// File::open(path, FO_*) / open_temp(dir) -> read_at / write_at / size / sync,
11// file_exists(path) (0 / 1 file / 2 dir), mkdir (with parents), delete, rename,
12// trash (into the recycle bin / freedesktop trash; trash.rs),
13// file_exists_checked(path) (Some(0) missing, None error), FileLock::acquire(path),
14// AtomicFile::create(path) -> write_at / commit (write_file in pieces),
15// dir_list(path, f(name, is_dir, size_lo)) -- checked against the app's
16// permissions first (guarded.rs); a refused path behaves like a missing one
17// policy: the app's permissions (apps/NAME/PERMISSIONS): install, the fs / process /
18// url / plugin / print checks, grants for the user's files (policy.rs)
19// boot: the app's name, app:// and its manifest at start-up (rt::main! through
20// rt::boot; ui::main! calls the parts itself) (boot.rs)
21// vfs: "scheme://path" names in every file function: app:// (the bundled assets),
22// config:// data:// cache:// logs:// (the app's folders), documents:// and the
23// other user folders, mem://, mounted providers
24// (MemFs, DirFs, Overlay, Sub, Bundle); data_dir(), cache_dir() (vfs.rs);
25// display_name(path); Android content:// (ContentFs, DocHost) (content.rs);
26// persistent_name(path): a chosen file's name that lasts across restarts (Flatpak's
27// documents portal: linux_docs.rs)
28// secret: secret_set / secret_get / secret_delete / secret_available: passwords, tokens and
29// keys in the system's store (Credential Manager + DPAPI, Secret Service; needs
30// `secrets` in the manifest) (secret.rs)
31// instance: claim(app) -> Primary / Forwarded / Alone, take() -> requests of later starts
32// (the app's single instance; pipe / abstract socket per user) (instance.rs)
33// spell: sys_spell_find / sys_spell_languages, SysSpeller (check, suggest): the system's
34// spell checker (Windows ISpellChecker; elsewhere none) (spell.rs)
35// tray: tray_set / tray_remove (the symbol in the notification area, its menu), notify /
36// notify_close (system notifications), tray_take() -> events (tray.rs)
37// power: inhibit(reason, INHIBIT_SUSPEND | INHIBIT_IDLE) -> Option<Inhibit> (no standby /
38// screen saver while the guard lives), inhibited() (power.rs)
39// autostart: autostart_set(on, args) / autostart_get() / autostart_entry() (Run key, XDG
40// autostart, Background portal, MSIX StartupTask; needs `autostart` in the manifest)
41// (autostart.rs)
42// pkg: packaged() (MSIX, Flatpak, AppImage, Snap or a plain program), msix_updates (App
43// Installer), FlatpakMonitor / flatpak_spawn_latest (the Flatpak portal),
44// restart_appimage (pkg.rs)
45// taskbar: taskbar_progress / taskbar_badge / taskbar_tasks (the taskbar button: progress,
46// overlay / count, jump list; ITaskbarList3, Unity LauncherEntry), app_user_model_id
47// / set_app_user_model_id (Windows: the app's explicit id) (taskbar.rs)
48// assoc: assoc_register / assoc_conflicts / assoc_unregister: the app's PACKAGE file types
49// and URL schemes for this program without a setup (HKCU\Software\Classes; .desktop,
50// shared-mime-info, mimeapps.list), file_uri_path (assoc.rs)
51// recent: recent_add / recent_list / recent_remove / recent_clear: the system's recent files
52// (SHAddToRecentDocs and the jump list; recently-used.xbel) (recent.rs)
53// audio: Stream (open / open_fill, write, start / pause / stop, volume, latency, the default
54// device followed), play / play_file (WAV, Ogg Vorbis), sound(SOUND_*): the system's
55// sounds (WASAPI, PulseAudio protocol, WebAudio, AAudio) (audio.rs)
56// screen: monitors() (rect, work area, dpi, refresh, primary; SET_MONITORS), pick_start (a
57// pixel's colour anywhere), capture_start (pictures of the screen) (screen.rs)
58// hotkey: hotkey_register / hotkey_unregister / hotkey_take: global shortcuts (RegisterHotKey,
59// XGrabKey, the GlobalShortcuts portal) (hotkey.rs)
60// threads: thread_spawn(stack, f) -> Thread (join), thread_yield(), Sem (post / wait),
61// wake() (any thread: E_WAKE on the UI thread), wait_events(deadline, on_event)
62// (headless), cpu_count(), mem_total()
63// pool: thr_init / thr_count / thr_shutdown / thr_self, parallel_for, Job (pool.rs)
64// task: async execution: Executor (ui() in the event loop, new() / block_on), Task,
65// spawn_blocking (a pool for blocking work), sleep, CancelToken, Progress, join /
66// select (task.rs)
67// aio: files without blocking: read_file / write_file / copy_file with progress and
68// cancellation, Reader / Writer chunk by chunk (AtomicFile underneath) (aio.rs)
69// sync: Mutex, Condvar, RwLock, channel (futex / WaitOnAddress) (sync.rs)
70// rand: fill_random, random_bytes, random_u64 (the OS CSPRNG) (rand.rs)
71// net: TcpListener, TcpStream, UdpSocket, SocketAddr, resolve (net.rs)
72// fs: stat / lstat / read_dir / links / set_times / free_space /
73// write_file_private / local_zone_id (fs.rs)
74// cpu: cpu_features() (CPU_*), cpu_brand() (cpu.rs)
75// crash: crash_hook(Some(f)): f(&CrashInfo) before exit code 3 -- hardware faults (VEH /
76// signals, the stderr line of ASMLIB) and panics; crash_test() crashes on purpose
77// windows: the window-indexed API of the assembly (win_create / win_show / win_present /
78// wait ..., popups, clipboard, drops, pen, cursors; consts.rs, evq.rs, pwin0.rs)
79// dnd: drag and drop between programs: DragData (files, text, URLs, HTML, image),
80// the drop target hook, the pending drop, drag_start (dragging out) (dnd.rs)
81// (plat-shared) print(job) + page layout / PDF writer (print.rs; win_print.rs,
82// linux_print.rs), plugin libraries lib_open / lib_sym / lib_close / lib_seg and
83// the crash guard guard_call / guard_run / guard_tag (plib.rs; win_lib.rs,
84// linux_elfload.rs, linux_guard.rs), monitor_icc / monitor_key (icc.rs), the
85// portal's file dialog / OpenURI / Print (linux_portal.rs)
86// (jxl-module) the loadable JPEG XL writer module: jxlenc_set_path / jxlenc_ready /
87// jxlenc_encode (modhost.rs; the records in modabi.rs)
88//
89// The layer knows events, pixel rows, files and threads only -- no UI, no gfx. One of the
90// four crates that may contain `unsafe` (rt, simd, plat, plugin); nothing unsafe leaves it.
91#![no_std]
92#[cfg(feature = "std")]
93extern crate std;
94
95extern crate alloc;
96
97/// Owned native child processes with pipes and process-tree lifetime management.
98#[cfg(any(windows, target_os = "linux"))]
99pub mod process;
100/// Mutex, Condvar, RwLock and bounded channels for worker threads.
101#[cfg(any(windows, target_os = "linux"))]
102pub mod sync;
103/// TCP and UDP sockets (IPv4 / IPv6) with timeouts, numeric names.
104#[cfg(any(windows, target_os = "linux"))]
105pub mod net;
106/// Metadata, directory listings, links, times, free space, owner-only files, the local zone.
107#[cfg(any(windows, target_os = "linux"))]
108pub mod fs;
109/// Running as a system service (Windows service control manager, systemd units).
110#[cfg(any(windows, target_os = "linux"))]
111pub mod service;
112/// Changes below folders as they happen (continuous data protection).
113#[cfg(any(windows, target_os = "linux"))]
114pub mod watch;
115/// The operating system's trusted certificate authorities (TLS clients of public servers).
116#[cfg(any(windows, target_os = "linux"))]
117pub mod certs;
118#[cfg(any(windows, target_os = "linux"))]
119mod rand;
120#[cfg(any(windows, target_os = "linux"))]
121pub use rand::*;
122
123use alloc::string::String;
124
125#[cfg(not(any(jfgui_glibc, feature = "std")))] pub use rt::os::exit; pub use rt::os::{write_stderr, write_stdout};
126// a program with std (feature std): its exit and the symbol its fn main calls
127#[cfg(feature = "std")]
128mod hosted;
129#[cfg(feature = "std")]
130pub use hosted::{exit, jfgui_std_start};
131#[cfg(all(feature = "std", any(target_arch = "wasm32", target_os = "android")))]
132pub use hosted::std_start;
133// the library's version (the root Cargo.toml, docs/VERSIONING.md); the app's own: rt::app_version!()
134pub use rt::{VERSION, VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH};
135
136mod cpu;
137mod capabilities;
138pub use capabilities::*;
139/// The app's permissions (apps/NAME/PERMISSIONS) and their checks.
140pub mod policy;
141/// OS sandbox derived from the manifest: Landlock + seccomp (Linux), mitigation policies (Windows).
142pub mod sandbox;
143#[cfg(target_os = "linux")]
144#[path = "linux_sandbox.rs"]
145mod linux_sandbox;
146#[cfg(windows)]
147#[path = "win_sandbox.rs"]
148mod win_sandbox;
149/// What build_rs.py builds into a program (name, assets, manifest), set up at start-up.
150pub mod boot;
151/// One file namespace: app://, config://, data://, cache://, mem:// and mounted providers.
152pub mod vfs;
153pub use vfs::display_name;
154/// The documents of other apps as files: Android's content:// names (the name logic on all
155/// platforms, tested with a host in memory).
156pub mod content;
157/// Passwords, tokens and keys in the system's secret store (Credential Manager, Secret Service).
158pub mod secret;
159/// One running instance per app and user; later starts hand over their arguments.
160pub mod instance;
161/// The system's spell checker (Windows ISpellChecker); Hunspell files are the spell crate's.
162pub mod spell;
163/// The app's symbol in the notification area and system notifications.
164pub mod tray;
165/// Keeping the computer awake: no standby, no screen saver while a guard lives.
166pub mod power;
167pub use power::{INHIBIT_IDLE, INHIBIT_SUSPEND, Inhibit, inhibit, inhibited};
168
169pub mod sensors;
170
171/// Android: while `on`, the back key reaches the app as Esc (a page of the app goes back, a popup
172/// closes; `UIC_ESCAPE` when nothing took it) instead of ending the activity. Elsewhere nothing:
173/// there Esc is a key of its own
174pub fn back_trap(on: bool) {
175 #[cfg(target_os = "android")]
176 web::system_host::back_trap(on);
177 #[cfg(not(target_os = "android"))]
178 let _ = on;
179}
180
181/// Android: the runtime ended (ui.quit): the activity goes and its process with it, a new start
182/// needs a new runtime. Elsewhere nothing: there the main loop ends the program
183pub fn app_finish() {
184 #[cfg(target_os = "android")]
185 web::system_host::app_finish();
186}
187
188/// (ui touch.rs) the host's main pointer is a finger at the start (Android; a phone's browser:
189/// `pointer: coarse`; a Windows tablet in slate posture): no scroll bars from the first frame on; the
190/// next pointer event decides again
191pub fn touch_primary() -> bool {
192 #[cfg(target_arch = "wasm32")]
193 return web::touch_primary();
194 #[cfg(target_os = "android")]
195 return true;
196 #[cfg(windows)]
197 return win_touch_primary();
198 #[cfg(not(any(target_arch = "wasm32", target_os = "android", windows)))]
199 false
200}
201
202/// (ui touch.rs) a text field got the focus through a finger (show) or lost it: the on-screen keyboard
203/// of window w. Windows: InputPane; Wayland: text-input follows the focus by itself (the compositor's
204/// keyboard); elsewhere the host's job (Android, the browser) or nothing there is to ask (X11)
205pub fn touch_keyboard(w: i32, show: bool) {
206 #[cfg(windows)]
207 win_touch_keyboard(w, show);
208 #[cfg(not(windows))]
209 let _ = (w, show);
210}
211
212/// (ui touch.rs) a finger's gesture reached a widget (a tap, a drag), or it did not (a scroll):
213/// Android asks after the finger lifted whether the keyboard has to follow
214pub fn touch_reached(reached: bool) {
215 #[cfg(target_os = "android")]
216 web::system_host::touch_reached(reached);
217 #[cfg(not(target_os = "android"))]
218 let _ = reached;
219}
220
221/// (ui touch.rs) a finger rested long enough: the host's feedback (Android: performLongClick)
222pub fn touch_long_press() {
223 #[cfg(target_os = "android")]
224 web::system_host::touch_long_press();
225}
226
227/// where a window the user moves may be (x, y; w its width; screen the area's size; dpi for the
228/// margin): the title bar stays on the screen, at least 48 DIP of the window at each side
229pub fn reach_clamp(p: [i32; 2], w: i32, screen: [i32; 2], dpi: i32) -> [i32; 2] {
230 let m = 48 * dpi / 96;
231 [p[0].clamp(m.min(w) - w, (screen[0] - m).max(m.min(w) - w)), p[1].clamp(0, (screen[1] - m).max(0))]
232}
233/// Starting the app when the user logs in (Run key, XDG autostart, Background portal, an MSIX
234/// package's StartupTask).
235pub mod autostart;
236/// The package the program runs from (MSIX, Flatpak, AppImage, Snap) and what its package
237/// system offers for updates (App Installer, the Flatpak portal).
238pub mod pkg;
239// the few WinRT calls (StartupTask, Package) through raw COM
240#[cfg(windows)]
241mod win_winrt;
242pub use autostart::{AUTOSTART_WAIT_MS, AutostartError, autostart_entry, autostart_get, autostart_set};
243/// The app's taskbar / dock button: progress, a badge, the jump list's tasks.
244pub mod taskbar;
245/// The app's file types and URL schemes registered without a setup (developer builds).
246pub mod assoc;
247/// The system's list of recently used files (jump lists, recently-used.xbel).
248pub mod recent;
249pub use recent::{recent_add, recent_clear, recent_list, recent_remove};
250/// Sound output: streams, short sounds from memory or files, the system's own sounds.
251pub mod audio;
252/// The monitors, a pixel's colour anywhere on the screen, pictures of the screen.
253pub mod screen;
254pub use screen::{Monitor, monitors};
255/// Global keyboard shortcuts: chords that reach the app while another program has the keyboard.
256pub mod hotkey;
257pub use hotkey::{Chord, HotkeyError, HotkeyEvent, hotkey_register, hotkey_take, hotkey_unregister};
258// what the desktop integration shares on Linux (the session-bus link, the .desktop id)
259#[cfg(target_os = "linux")]
260mod linux_desk;
261// the damage regions of the X11 / Wayland presents
262#[cfg(target_os = "linux")]
263mod linux_damage;
264// the log: levels, a ring for crash reports, stderr, a rotating file
265mod log;
266pub use log::*;
267// the accessibility tree for screen readers (AT-SPI2, UI Automation)
268pub mod a11y;
269// the system settings the UI follows (theme, accent, contrast, motion, text scale, timing)
270mod settings;
271pub use settings::{HcColors, SysSettings, sys_settings, sys_settings_env, font_hint_parse, font_rgba_parse,
272 Titlebar, titlebar_layout_parse, titlebar_action_parse, TB_BTN_CLOSE, TB_BTN_MIN, TB_BTN_MAX,
273 TB_ACT_NONE, TB_ACT_MAXIMIZE, TB_ACT_MINIMIZE, TB_ACT_LOWER, TB_ACT_MENU,
274 FONT_HINT_NONE, FONT_HINT_SLIGHT, FONT_HINT_MEDIUM, FONT_HINT_FULL,
275 FONT_RGBA_NONE, FONT_RGBA_RGB, FONT_RGBA_BGR, FONT_RGBA_VRGB, FONT_RGBA_VBGR};
276// the user's languages and regional format (BCP 47 tags)
277mod locale;
278pub use locale::{locale_tag, system_languages, system_locale};
279mod guarded;
280pub use guarded::*;
281// the user's folders (documents, downloads, pictures ...) and the folder of logs
282mod dirs;
283pub use dirs::*;
284// moving files to the trash instead of deleting them
285mod trash;
286mod control_stream;
287#[cfg(not(any(target_arch = "wasm32", target_os = "android")))]
288pub use control_stream::*;
289#[cfg(any(windows, target_os = "linux"))]
290pub mod control_ipc;
291#[cfg_attr(all(any(target_arch = "wasm32", target_os = "android"), not(web_threads)), path = "web_pool.rs")]
292mod pool;
293/// Async execution: executors in the event loop and for block_on, a pool for blocking work,
294/// timers, cancellation, progress, joins.
295pub mod task;
296/// Files without blocking the caller: chunked reads, atomic writes and copies with progress and
297/// cancellation.
298pub mod aio;
299pub use cpu::*;
300pub use pool::*;
301
302#[cfg(windows)]
303mod win;
304#[cfg(windows)]
305pub use win::*;
306// a managed program on the runtime another application ships; values of HKLM
307#[cfg(windows)]
308mod win_clr;
309#[cfg(windows)]
310pub use win_clr::*;
311
312#[cfg(target_os = "linux")]
313mod linux;
314#[cfg(target_os = "linux")]
315pub use linux::*;
316
317/// Host-driven boundary shared by browser workers and the native Android adapter.
318#[cfg(any(target_arch = "wasm32", target_os = "android"))]
319pub mod web;
320#[cfg(any(target_arch = "wasm32", target_os = "android"))]
321pub use web::*;
322
323mod clipdrop;
324// drag and drop between programs (the shared part; win_dnd.rs, linux_x11_dnd.rs, linux_wl_clip.rs)
325mod dnd;
326pub use dnd::*;
327// clipboard_platform: reusable rich clipboard framing.
328mod cliprich;
329pub use cliprich::*;
330mod consts;
331mod evq;
332mod ime;
333pub use ime::*;
334#[cfg_attr(any(target_arch = "wasm32", target_os = "android"), path = "web_icc.rs")]
335mod icc;
336mod pwin0;
337pub use clipdrop::*;
338pub use consts::*;
339pub use evq::*;
340pub use icc::*;
341pub use pwin0::*;
342// plat-shared: printing (print.rs + win_print.rs / linux_print.rs), plugin libraries and the
343// crash guard (plib.rs + win_lib.rs / linux_elfload.rs, linux_guard.rs)
344#[cfg_attr(any(target_arch = "wasm32", target_os = "android"), path = "web_lib.rs")]
345mod plib;
346mod print;
347pub use plib::*;
348pub use print::*;
349// jxl-module: loadable modules, the host side (the JPEG XL writer jxlenc; modhost.rs, modabi.rs)
350#[cfg_attr(any(target_arch = "wasm32", target_os = "android"), path = "web_modhost.rs")]
351mod modhost;
352pub use modhost::*;
353
354/// one platform event (the EV_* record): type, button, modifiers, window index (0 = the
355/// main window), position (px; E_RESIZE: size), data
356#[derive(Clone, Copy, Default)]
357pub struct Event {
358 pub typ: u8,
359 pub btn: u8,
360 pub mods: u8,
361 pub win: u8,
362 pub x: i32,
363 pub y: i32,
364 pub data: u32,
365}
366
367/// the pixels to present: rows of 32-bit B, G, R, x
368pub struct Frame<'a> {
369 pub px: &'a [u8],
370 pub w: i32,
371 pub h: i32,
372 pub stride: i32,
373}
374
375// ---- files
376pub const FO_READ: u32 = 0; // existing file, read only
377pub const FO_WRITE: u32 = 1; // create or truncate, read + write
378pub const FO_RW: u32 = 2; // open or create (contents kept), read + write
379
380/// a date and time (date(): Windows local time, Linux UTC)
381#[derive(Clone, Copy, Default, Debug)]
382pub struct Date {
383 pub year: u16,
384 pub month: u16,
385 pub day: u16,
386 pub hour: u16,
387 pub min: u16,
388 pub sec: u16,
389 pub ms: u16,
390 pub wday: u16, // 0 = Sunday
391}
392
393/// The name under which a file the user chose stays reachable after a restart, for a list of
394/// recent files or a session (ui.recent_add keeps this one). A document of Flatpak's
395/// documents portal (`$XDG_RUNTIME_DIR/doc/ID/NAME`) is asked for its lasting form
396/// (`Documents.Add`, persistent; linux_docs.rs): `<mount>/<ID>/<NAME>` of the portal's answer.
397/// Where the portal reaches the real file that is a lasting document of it; for a document
398/// of its own mount the portal answers that document's own ID, so inside the sandbox the name
399/// stays as the dialog gave it (the portal's file dialog makes lasting documents, "Open with"
400/// session ones). Every other name comes back unchanged: Android keeps the grant of a
401/// `content://` document and the browser the handle of a `/handles/` file when the user
402/// chooses it, and OS paths need nothing. The name must be readable under the app's
403/// permissions.
404pub fn persistent_name(name: &str) -> String {
405 #[cfg(target_os = "linux")]
406 if crate::policy::fs_allowed(name, crate::policy::FS_READ) {
407 if let Some(p) = crate::linux_docs::persistent(name) {
408 return p;
409 }
410 }
411 String::from(name)
412}
413
414/// The answer of a system file dialog that answers later (file_dialog -> FD_PENDING: only
415/// Android's picker and the browser's; web.rs): None while it is open, then once (1 chosen /
416/// 0 not, index, path).
417#[cfg(not(any(target_os = "android", target_arch = "wasm32")))]
418pub fn file_dialog_poll() -> Option<(i32, u32, String)> {
419 None
420}
421
422/// the argument after `name` on the command line (argument 0, the program, is skipped) [arg_value]
423pub fn arg_value(name: &str) -> Option<String> {
424 let a = args();
425 let i = a.iter().skip(1).position(|x| x == name)? + 1;
426 a.get(i + 1).cloned()
427}
428
429/// the library's options that take a value (`--size 800x600`): a program whose plain
430/// arguments are files skips the value after these
431pub const VALUE_OPTS: &[&str] = &[
432 "--size", "--scale", "--auto-close", "--anim", "--theme", "--accent", "--theme-file", "--contrast", "--text-scale",
433 "--lang", "--shot", "--script", "--threads", "--simd",
434];
435
436// ---- crashes (docs/modules/CRASH.md)
437pub use rt::crash::{CK_ACCESS, CK_BUS, CK_DIVIDE, CK_ILLEGAL, CK_OTHER, CK_PANIC, CK_STACK, CrashHook, CrashInfo};
438
439/// f(&CrashInfo) runs in the crash handler, after the stderr line, before exit code 3; also
440/// for panics (CK_PANIC) [plat_crash_hook]
441pub fn crash_hook(f: Option<CrashHook>) {
442 rt::crash::set_hook(f)
443}
444
445/// a deliberate crash for tests: `mov eax, 16` (5 bytes), then a 4-byte write to address 0x10
446/// -- the faulting instruction is at crash_test + 5
447#[unsafe(naked)]
448#[cfg(target_arch = "x86_64")]
449pub extern "C" fn crash_test() -> ! {
450 core::arch::naked_asm!("mov eax, 16", "mov dword ptr [rax], eax", "ud2")
451}
452
453/// (plat-win) crash_test called from a known place (call rel32): the return address
454/// crash_test_caller + 5 must be among CrashInfo::frames (plattest's call chain check)
455#[unsafe(naked)]
456#[cfg(target_arch = "x86_64")]
457pub extern "C" fn crash_test_caller() -> ! {
458 core::arch::naked_asm!("call {0}", "ud2", sym crash_test)
459}
460
461/// Deliberate trap for browser runtime diagnostics.
462#[cfg(target_arch = "wasm32")]
463pub extern "C" fn crash_test() -> ! { core::arch::wasm32::unreachable() }
464/// Deliberate trap through the compatibility caller API.
465#[cfg(target_arch = "wasm32")]
466pub extern "C" fn crash_test_caller() -> ! { crash_test() }
467
468/// Deliberate termination on Android, where no hardware exception translator is installed.
469#[cfg(all(target_os = "android", not(target_arch = "x86_64")))]
470pub extern "C" fn crash_test() -> ! { rt::os::exit(3) }
471/// Compatibility caller for the Android diagnostic termination.
472#[cfg(all(target_os = "android", not(target_arch = "x86_64")))]
473pub extern "C" fn crash_test_caller() -> ! { crash_test() }