From 35bf16b63e2cd7b80f571b159ccc2570dac0f7f3 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 1 Apr 2026 17:03:47 +0000 Subject: [PATCH] docs: add README for Arti Android build tools Covers prerequisites, build commands, output verification, version updates, architecture decisions, Cargo features, and troubleshooting. https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu --- tools/arti-build/README.md | 199 +++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 tools/arti-build/README.md diff --git a/tools/arti-build/README.md b/tools/arti-build/README.md new file mode 100644 index 000000000..1ee313b4e --- /dev/null +++ b/tools/arti-build/README.md @@ -0,0 +1,199 @@ +# Arti Android Build Tools + +Custom-built [Arti](https://gitlab.torproject.org/tpo/core/arti) (Tor in Rust) native libraries +for Amethyst Android. This replaces the Guardian Project's `arti-mobile-ex` AAR with a minimal +JNI wrapper built directly from Arti source. + +## Why custom build? + +| | Guardian Project AAR | Custom build | +|---|---|---| +| **Size** | ~140MB | ~11MB | +| **16KB pages** | No | Yes (NDK 25+) | +| **Stop/restart** | Broken (state file lock) | Works (TorClient persists, only SOCKS proxy stops) | +| **Version** | Behind | Pinned to latest (currently 1.9.0) | + +## Quick start + +Pre-built `.so` files should be committed to `amethyst/src/main/jniLibs/`. You only need to +rebuild if you want to verify binaries, update the Arti version, or modify the JNI wrapper. + +## Prerequisites + +1. **Rust toolchain** + ```bash + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` + +2. **Android targets** + ```bash + rustup target add aarch64-linux-android x86_64-linux-android + ``` + +3. **cargo-ndk** + ```bash + cargo install cargo-ndk + ``` + +4. **Android NDK 25+** (required for 16KB page size support) + ```bash + # Via Android Studio: SDK Manager → SDK Tools → NDK (Side by side) + # Or via command line: + sdkmanager "ndk;27.0.12077973" + + # Set environment variable + export ANDROID_NDK_HOME="$HOME/Android/Sdk/ndk/27.0.12077973" + ``` + +## Building + +```bash +cd tools/arti-build + +# Build for all targets (arm64 + x86_64) +./build-arti.sh + +# Build arm64 only (for release APKs) +./build-arti.sh --release + +# Clean rebuild from scratch +./build-arti.sh --clean +``` + +The script will: +1. Clone official Arti source from `gitlab.torproject.org` +2. Check out the version pinned in `ARTI_VERSION` +3. Copy the JNI wrapper into the source tree +4. Compile with `cargo-ndk` for each target architecture +5. Output `.so` files to `amethyst/src/main/jniLibs/{arm64-v8a,x86_64}/` +6. Verify JNI symbols are exported correctly + +## Output + +``` +amethyst/src/main/jniLibs/ +├── arm64-v8a/ +│ └── libarti_android.so (~5-6 MB) +└── x86_64/ + └── libarti_android.so (~6-7 MB, emulator support) +``` + +## Verifying 16KB page alignment + +Google Play requires 16KB page-aligned native libraries. Verify with: + +```bash +readelf -l amethyst/src/main/jniLibs/arm64-v8a/libarti_android.so | grep LOAD +``` + +The first LOAD segment alignment should be `0x4000` (16384 bytes). + +## Directory structure + +``` +tools/arti-build/ +├── README.md # This file +├── ARTI_VERSION # Pinned Arti git tag (e.g., arti-v1.9.0) +├── Cargo.toml # Rust dependencies and build profile +├── build-arti.sh # Build script +├── src/ +│ └── lib.rs # JNI bridge (Rust → Kotlin) +└── .arti-source/ # [gitignored] Cloned Arti repository +``` + +## Updating Arti version + +1. Check available versions: + ```bash + git ls-remote --tags https://gitlab.torproject.org/tpo/core/arti.git | grep 'arti-v' | tail -10 + ``` + +2. Update the version file: + ```bash + echo "arti-v1.10.0" > ARTI_VERSION + ``` + +3. Update crate versions in `Cargo.toml` to match the new release. + Check the crate versions at: + ``` + https://gitlab.torproject.org/tpo/core/arti/-/raw/arti-v1.10.0/crates/arti-client/Cargo.toml + ``` + +4. Rebuild and test: + ```bash + ./build-arti.sh --clean + ``` + +## Architecture: JNI bridge + +The Rust wrapper (`src/lib.rs`) exposes these JNI functions to Kotlin: + +| JNI function | Kotlin | Purpose | +|---|---|---| +| `initialize(dataDir)` | `ArtiNative.initialize()` | Create TorClient, bootstrap Tor network | +| `startSocksProxy(port)` | `ArtiNative.startSocksProxy()` | Bind SOCKS5 listener on localhost | +| `stopSocksProxy()` | `ArtiNative.stopSocksProxy()` | Abort listener, release port | +| `getVersion()` | `ArtiNative.getVersion()` | Return Arti version string | +| `setLogCallback(cb)` | `ArtiNative.setLogCallback()` | Register log callback | + +### Key design decisions + +- **TorClient is created once** via `initialize()` and persists for the app's lifetime. + Its state file lock is tied to the object's lifetime and released only on GC/process exit. +- **`stopSocksProxy()` only stops the TCP listener** — it does NOT destroy the TorClient. + This allows clean stop/start cycles without state file lock conflicts. +- **SOCKS5 is implemented in Rust** using `tokio::net::TcpListener`, not delegated to Arti's + built-in proxy. This gives us full control over the listener lifecycle. +- **Bidirectional forwarding** uses `tokio::io::copy` with `tokio::select!` for efficiency. + +## Cargo.toml features + +| Feature | Purpose | +|---|---| +| `tokio` | Async runtime | +| `rustls` | TLS without OpenSSL (smaller, no system dependency) | +| `compression` | Tor relay compression support | +| `bridge-client` | Connect via Tor bridges | +| `onion-service-client` | Access .onion addresses | +| `static-sqlite` | Bundled SQLite for state storage | + +### Release profile + +```toml +[profile.release] +opt-level = "z" # Optimize for size +lto = true # Link-time optimization +codegen-units = 1 # Single codegen unit (smaller binary) +strip = true # Strip debug symbols +panic = "abort" # No unwinding (smaller binary) +``` + +## Troubleshooting + +### `cargo-ndk` not found +```bash +cargo install cargo-ndk +``` + +### NDK not found +```bash +export ANDROID_NDK_HOME="$HOME/Android/Sdk/ndk/" +``` + +### Rust targets not installed +```bash +rustup target add aarch64-linux-android x86_64-linux-android +``` + +### Build fails with dependency errors +Try a clean build: +```bash +./build-arti.sh --clean +``` + +### JNI symbols missing after build +The build script verifies symbols automatically. If verification fails, check that +`src/lib.rs` function names match the Kotlin package path: +``` +Java_com_vitorpamplona_amethyst_ui_tor_ArtiNative_ +```