Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

Arti Android Build Tools

This directory contains the build scripts and source files for compiling the custom Arti (Tor in Rust) library for Android.

Overview

bitchat-android uses a custom-built Arti library instead of Guardian Project's outdated arti-mobile-ex AAR. This provides:

  • Smaller APK size: ~11MB total vs ~140MB with Guardian Project AAR (28x reduction)
  • Latest Arti version: Currently v1.7.0 with pure Rust TLS (rustls)
  • 16KB page size support: Required for Google Play (Nov 2025)
  • Full transparency: Build from official Arti source + our JNI wrapper

Quick Start

The pre-built .so files are committed to the repo, so you don't need to build unless you want to:

  1. Verify the binaries match the source
  2. Update to a new Arti version
  3. Modify the JNI wrapper

Directory Structure

tools/arti-build/
├── README.md           # This file
├── build-arti.sh       # Main build script (clones Arti, builds .so files)
├── ARTI_VERSION        # Pinned Arti version tag (e.g., arti-v1.7.0)
├── Cargo.toml          # Rust package configuration
├── src/
│   └── lib.rs          # JNI wrapper (Rust -> Kotlin/Java bridge)
└── .arti-source/       # [GITIGNORED] Cloned official Arti repo

app/src/main/jniLibs/   # [COMMITTED] Pre-built native libraries
├── arm64-v8a/
│   └── libarti_android.so  (~5.3MB)
└── x86_64/
    └── libarti_android.so  (~6.2MB)

Rebuilding from Source

Prerequisites

  1. Rust toolchain with Android targets:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    rustup target add aarch64-linux-android x86_64-linux-android
  2. cargo-ndk for Android cross-compilation:

    cargo install cargo-ndk
  3. Android NDK 25+ (for 16KB page size support):

    # Via Android Studio SDK Manager, or:
    $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager "ndk;27.0.12077973"
    
    # Set environment variable
    export ANDROID_NDK_HOME="$HOME/Library/Android/sdk/ndk/27.0.12077973"

Build Commands

cd tools/arti-build

# Build both architectures (arm64 + x86_64 for emulator)
./build-arti.sh

# Build ARM64 only (smaller, for production releases)
./build-arti.sh --release

# Clean rebuild (re-clone Arti source)
./build-arti.sh --clean

The script will:

  1. Clone official Arti from https://gitlab.torproject.org/tpo/core/arti
  2. Checkout the version specified in ARTI_VERSION
  3. Copy our JNI wrapper into the cloned repo
  4. Build with cargo ndk
  5. Copy .so files to app/src/main/jniLibs/

Verification

After building, verify the libraries:

# Check file sizes
ls -lh ../../app/src/main/jniLibs/*/libarti_android.so

# Verify JNI symbols are exported
nm -gU ../../app/src/main/jniLibs/arm64-v8a/libarti_android.so | grep Java_org_torproject

# Verify 16KB page alignment
readelf -l ../../app/src/main/jniLibs/arm64-v8a/libarti_android.so | grep LOAD
# Look for: Align 0x4000 (16KB)

Updating Arti Version

  1. Check available versions:

    git ls-remote --tags https://gitlab.torproject.org/tpo/core/arti.git | grep arti-v
  2. Update the version file:

    echo "arti-v1.8.0" > ARTI_VERSION
  3. Rebuild from scratch:

    ./build-arti.sh --clean
  4. Test the build:

    cd ../..
    ./gradlew clean assembleDebug
    ./gradlew installDebug
    # Enable Tor in app and verify it works
  5. Commit the new libraries:

    git add app/src/main/jniLibs/ tools/arti-build/ARTI_VERSION
    git commit -m "chore: update Arti to v1.8.0"

JNI Wrapper Architecture

The src/lib.rs file implements a JNI bridge between Kotlin and Rust:

Kotlin (ArtiNative.kt)
    ↓ JNI
Rust (lib.rs)
    ↓
Arti Client (TorClient)
    ↓
SOCKS5 Proxy (localhost:9060)

Exported JNI Functions:

  • getVersion() - Returns Arti version string
  • setLogCallback(callback) - Registers log listener for bootstrap progress
  • initialize(dataDir) - Creates Tokio runtime and TorClient
  • startSocksProxy(port) - Starts SOCKS5 proxy on specified port
  • stop() - Stops SOCKS proxy (TorClient is reused)

Key Design Decisions:

  • Global TorClient persists across stop/start cycles (fixes Nov 2024 toggle bug)
  • Tokio runtime created once and never destroyed
  • Log messages bridged to Java via GlobalRef callback

Feature Configuration

Edit Cargo.toml to customize Arti features:

[dependencies]
arti-client = {
    path = "../crates/arti-client",
    default-features = false,
    features = [
        "tokio",                  # Required: async runtime
        "rustls",                 # Required: pure Rust TLS (no OpenSSL)
        "compression",            # Optional: directory compression
        "bridge-client",          # Optional: Tor bridge support
        "onion-service-client",   # Optional: .onion site support
        "static-sqlite"           # Required: bundled SQLite
    ]
}

Size Comparison

Configuration arm64-v8a x86_64 Total APK Size
Guardian Project AAR - - ~140 MB ~150 MB
Custom (both arch) 5.3 MB 6.2 MB 11.5 MB ~15 MB
Custom (ARM-only) 5.3 MB - 5.3 MB ~10 MB

28x size reduction vs Guardian Project implementation.

Troubleshooting

"cargo-ndk not found"

cargo install cargo-ndk

"Android NDK not found"

export ANDROID_NDK_HOME="$HOME/Library/Android/sdk/ndk/27.0.12077973"

"Rust target not installed"

rustup target add aarch64-linux-android x86_64-linux-android

"Version not found"

Check available versions:

git ls-remote --tags https://gitlab.torproject.org/tpo/core/arti.git | grep arti-v | tail -10

Library too large

  1. Ensure building with --release flag
  2. Verify strip = true in Cargo.toml [profile.release]
  3. Consider removing optional features

References