From 5dc1279429701c4f217afb6ac0b28a4bb6872acf Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 9 Aug 2026 21:10:00 +0200 Subject: [PATCH] Add the Android app shell; cap cross-build parallelism MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cap both halves of the container build: CARGO_BUILD_JOBS limits how many rustc processes cargo starts, while --cpus limits what the container gets regardless of what nested build scripts spawn — cc, cmake, and ring's asm build all parallelise on their own account and do not consult cargo. Without both, a full cross-compile takes every thread on the host and makes the machine unusable for the length of a background build. Assisted-by: LLM --- Cargo.lock | 204 +++++++++++++++++++++++++++++-- Cargo.toml | 1 + apps/darkroom-android/Cargo.toml | 28 +++++ apps/darkroom-android/src/lib.rs | 36 ++++++ docker/android/build.sh | 13 ++ 5 files changed, 274 insertions(+), 8 deletions(-) create mode 100644 apps/darkroom-android/Cargo.toml create mode 100644 apps/darkroom-android/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 241ca90..367bd76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -111,6 +111,27 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "android-activity" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +dependencies = [ + "android-properties", + "bitflags 2.13.1", + "cc", + "cesu8", + "jni 0.21.1", + "jni-sys 0.3.1", + "libc", + "log", + "ndk 0.8.0", + "ndk-context", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror 1.0.69", +] + [[package]] name = "android-activity" version = "0.6.1" @@ -120,22 +141,48 @@ dependencies = [ "android-properties", "bitflags 2.13.1", "cc", - "jni", + "jni 0.22.4", "libc", "log", - "ndk", + "ndk 0.9.0", "ndk-context", "ndk-sys 0.6.0+11769913", "num_enum", "thiserror 2.0.20", ] +[[package]] +name = "android-build" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fc9904ad2ad097c3c1cfe2eacaaf0fc24710936fa9ed941cb310b7c6ed2ab7" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "android-properties" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" +[[package]] +name = "android_log-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" + +[[package]] +name = "android_logger" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3" +dependencies = [ + "android_log-sys", + "env_filter 0.1.4", + "log", +] + [[package]] name = "android_system_properties" version = "0.1.6" @@ -773,6 +820,12 @@ dependencies = [ "shlex 2.0.1", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cexpr" version = "0.6.0" @@ -1100,6 +1153,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" +[[package]] +name = "darkroom-android" +version = "0.1.0" +dependencies = [ + "android_logger", + "anyhow", + "dr-ui", + "log", +] + [[package]] name = "darkroom-desktop" version = "0.1.0" @@ -1488,6 +1551,16 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + [[package]] name = "env_filter" version = "2.0.0" @@ -1506,7 +1579,7 @@ checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" dependencies = [ "anstream", "anstyle", - "env_filter", + "env_filter 2.0.0", "jiff", "log", ] @@ -2395,6 +2468,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "i-slint-backend-android-activity" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9805bcdcbeea6626a0054347ee55d2424e0d5574b563472719d3fc7a11852242" +dependencies = [ + "android-activity 0.5.2", + "android-activity 0.6.1", + "android-build", + "i-slint-common", + "i-slint-core", + "i-slint-renderer-skia", + "jni 0.22.4", + "ndk 0.9.0", + "raw-window-handle", +] + [[package]] name = "i-slint-backend-linuxkms" version = "1.17.1" @@ -2423,6 +2513,7 @@ checksum = "2247a4590a02a466b2f4916cc789dfe66247f6af826f00eb84a2685259a45c1c" dependencies = [ "cfg-if", "cfg_aliases 0.2.2", + "i-slint-backend-android-activity", "i-slint-backend-linuxkms", "i-slint-backend-winit", "i-slint-common", @@ -3065,6 +3156,22 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + [[package]] name = "jni" version = "0.22.4" @@ -3787,6 +3894,20 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c" +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.13.1", + "jni-sys 0.3.1", + "log", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror 1.0.69", +] + [[package]] name = "ndk" version = "0.9.0" @@ -5303,7 +5424,7 @@ checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" dependencies = [ "core-foundation 0.10.1", "core-foundation-sys", - "jni", + "jni 0.22.4", "log", "once_cell", "rustls", @@ -5685,6 +5806,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce12038f57f8f3a423564b0c9301a2ab3fda4246e4cbadd6b97acf9124bdc315" dependencies = [ "const-field-offset", + "i-slint-backend-android-activity", "i-slint-backend-selector", "i-slint-common", "i-slint-core", @@ -5863,7 +5985,7 @@ dependencies = [ "fastrand", "js-sys", "memmap2", - "ndk", + "ndk 0.9.0", "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", @@ -6988,7 +7110,7 @@ version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62c35be770821a214dbc362fc26908c853e776c0004294d0b10b8a6bad582f94" dependencies = [ - "jni", + "jni 0.22.4", "log", "ndk-context", "objc2 0.6.4", @@ -7306,6 +7428,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -7342,6 +7473,21 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -7382,6 +7528,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -7394,6 +7546,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -7406,6 +7564,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -7424,6 +7588,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -7436,6 +7606,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -7448,6 +7624,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -7460,6 +7642,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -7479,7 +7667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" dependencies = [ "ahash", - "android-activity", + "android-activity 0.6.1", "atomic-waker", "bitflags 2.13.1", "block2 0.5.1", @@ -7494,7 +7682,7 @@ dependencies = [ "js-sys", "libc", "memmap2", - "ndk", + "ndk 0.9.0", "objc2 0.5.2", "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", diff --git a/Cargo.toml b/Cargo.toml index a83fc71..8f9ca96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [ "platform/dr-plat", "ui/dr-ui", "apps/darkroom-desktop", + "apps/darkroom-android", "tools/traceability", ] diff --git a/apps/darkroom-android/Cargo.toml b/apps/darkroom-android/Cargo.toml new file mode 100644 index 0000000..21a94be --- /dev/null +++ b/apps/darkroom-android/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "darkroom-android" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true + +# A cdylib, not a bin: Android loads the app as a shared library and calls +# `android_main` through android-activity's glue. Nothing execs a binary, so +# there is no `main` to provide. +[lib] +name = "darkroom" +crate-type = ["cdylib"] + +[dependencies] +# No backend feature to select: dr-ui picks its Slint backend from the target, +# so building for aarch64-linux-android gets android-activity automatically. +dr-ui.workspace = true +anyhow.workspace = true +log.workspace = true +android_logger = "0.15" + +[features] +# Mirrors darkroom-desktop: the CPU readback path stays on until spike S1 +# lands zero-copy. On Adreno this is the same wrong path as on desktop, only +# with less memory bandwidth to absorb it (ARCH §6.1). +default = ["readback"] +readback = ["dr-ui/readback"] diff --git a/apps/darkroom-android/src/lib.rs b/apps/darkroom-android/src/lib.rs new file mode 100644 index 0000000..a57c86c --- /dev/null +++ b/apps/darkroom-android/src/lib.rs @@ -0,0 +1,36 @@ +//! DarkRoom Android entry point. +//! +//! The counterpart to `darkroom-desktop`'s `main`, with two differences that +//! come from the platform rather than from choice: +//! +//! * There are no command-line paths. Android's SAF hands out document URIs, +//! not filesystem paths (ARCH §6.9), so the viewer opens with an empty +//! browsing list and the library grid is the only way in. +//! * Logging goes to logcat. `env_logger` writes to stderr, which Android +//! discards. + +/// TRACES: M-13 | M-14 +/// Android application entry point, called by android-activity's glue. +#[no_mangle] +fn android_main(app: slint::android::AndroidApp) { + android_logger::init_once( + android_logger::Config::default() + .with_max_level(log::LevelFilter::Info) + .with_tag("DarkRoom"), + ); + + log::info!("DarkRoom v{}", env!("CARGO_PKG_VERSION")); + + if let Err(e) = slint::android::init(app) { + log::error!("Slint Android backend failed to initialise: {e}"); + return; + } + + // Empty rather than the desktop's argv: see the module note above. + // + // Returning from `android_main` ends the process, so a failure here is + // logged rather than propagated — there is no shell to show `Err` to. + if let Err(e) = dr_ui::run(Vec::new()) { + log::error!("DarkRoom exited with error: {e:#}"); + } +} diff --git a/docker/android/build.sh b/docker/android/build.sh index 93c5e8d..bd4b8fa 100755 --- a/docker/android/build.sh +++ b/docker/android/build.sh @@ -46,6 +46,19 @@ ARGS=( -w /work ) +# Build parallelism. A full cross-compile will otherwise take every thread on +# the host and make the machine unusable for the length of the build, which is +# a poor trade when it is running in the background. +# +# Both halves are needed: CARGO_BUILD_JOBS caps how many rustc processes cargo +# starts, while --cpus caps what the container gets no matter what any nested +# build script decides to spawn (cc, cmake, and ring's asm build all parallelise +# on their own account and do not consult cargo). +JOBS="${DARKROOM_BUILD_JOBS:-8}" +if [[ "${JOBS}" != "0" ]]; then + ARGS+=(--cpus "${JOBS}" -e "CARGO_BUILD_JOBS=${JOBS}") +fi + # Rootless podman already maps the host user; docker needs it stated. if [[ "${ENGINE}" == "docker" ]]; then ARGS+=(--user "$(id -u):$(id -g)")