mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-24 21:45:21 +00:00
* feat: add product flavors and TorProvider abstraction Introduces build flavors to separate Tor functionality from the standard build, reducing APK size for users who don't need Tor. - Creates `standard` and `tor` product flavors. - The `standard` flavor is the default, lightweight build. - The `tor` flavor includes the Arti (Tor) dependency and is identified by the `.tor` application ID suffix. - Adds a `TorProvider` interface and a `TorProviderFactory` to abstract Tor implementation details between flavors. Prepares architecture for optional Tor support to reduce APK size from 142MB to ~4-5MB for standard builds Related to #454 * Refactor: implement StandardTorProvider and RealTorProvider This commit refactors the Tor integration by introducing a `TorProvider` interface and creating separate implementations for 'tor' and 'standard' product flavors. - The original `TorManager` singleton has been moved into `RealTorProvider` for the 'tor' flavor. - A no-op `StandardTorProvider` is introduced for the 'standard' flavor, which reports Tor as unavailable. - A `TorProviderFactory` is used to create the appropriate provider at runtime based on the build variant. * refactor: migrate to TorProvider abstraction Replaced direct calls to the static `TorManager` with an instance obtained from `TorProviderFactory`. This change allows for different Tor implementations based on build flavors, improving modularity and abstracting the Tor provider logic. Updated `BitchatApplication`, `ChatHeader`, `OkHttpProvider`, and `AboutSheet` to use the new factory pattern for accessing Tor functionalities. * build: add flavor-specific ProGuard rules and CI/CD - Split ProGuard rules: base, standard-specific, tor-specific - Move Arti/Guardian Project rules to proguard-tor.pro - Update CI/CD workflow to build both flavors - Add separate artifact uploads for each flavor - Add descriptive release notes template CI now builds both standard (~4-5MB) and tor (~140MB) APKs." resolves #454 * refactor: centralize network reset logic Extracts the repeated network connection reset logic into a new private function `resetNetworkConnections()`. This change also replaces direct `_statusFlow.value = ...` assignments with the safer `_statusFlow.update { ... }` function to prevent race conditions. * ci: run separate build steps for flavors * feat: disable Tor toggle if not available in build * ci: parallelize builds and add conditional tor lint Optimizes CI workflow: - Parallel matrix builds (4 runners instead of sequential) - Conditional tor lint only when app/src/tor/ changes in PRs - Merged test+lint jobs to reduce setup overhead Reduces CI time by ~50% (8-11 min vs 18-26 min) * refactor: Unify Tor implementation and remove build flavors This commit refactors the Tor integration by removing the `standard` and `tor` product flavors in favor of a single, unified build that always includes a custom-built Arti (Tor) library. Key changes include: * **Removed Build Flavors:** Deleted the `standard` and `tor` product flavors from `build.gradle.kts`, simplifying the build process and CI configuration. * **Unified Tor Manager:** Replaced the `TorProvider` interface and flavor-specific implementations (`StandardTorProvider`, `RealTorProvider`) with a new singleton, `ArtiTorManager`. This class now manages the Arti lifecycle for all builds. * **Custom Arti Wrapper:** Introduced a new `ArtiProxy` class to provide a compatible API wrapper around the custom-built native Arti library (`libarti_android.so`). This replaces the dependency on the external `arti-mobile-ex` library. * **Updated Proguard:** Consolidated and updated Proguard rules into the main `proguard-rules.pro` file to keep the necessary `ArtiTorManager` and native library classes. * **CI/CD Simplification:** Updated GitHub Actions workflows (`release.yml`, `android-build.yml`) to build and release a single APK instead of separate ones for each flavor. * build: Configure ABI filters for debug and release builds For debug builds, include `x86_64` to support emulators. For release builds, only include `arm64-v8a` to minimize the final APK size. * feat: Ignore jniLibs directory This change adds the `app/src/main/jniLibs/` directory to the `.gitignore` file to prevent native libraries from being committed to the repository. * feat: Refine .gitignore for Arti build artifacts Improves the `.gitignore` file by: - Ignoring all `build/` directories except for `tools/arti-build/`. - Adding specific ignores for Arti build artifacts, including the cloned source repository and the Rust build cache directory. * feat: Update arti android native library * feat: add build script and JNI wrapper for Arti Adds a comprehensive build system for creating custom Arti (Tor in Rust) shared libraries for Android. This replaces the dependency on external, outdated AARs with a fully transparent and reproducible build process. Key changes: - Introduces `build-arti.sh`, a script to clone the official Arti repository, apply a JNI wrapper, and build `.so` files for Android. - Adds `ARTI_VERSION` to pin the build to a specific Arti release (v1.7.0). - Implements a new Rust JNI wrapper (`src/lib.rs`) that exposes core functions like `initialize`, `startSocksProxy`, and `stop` to the Android app. - Includes a `Cargo.toml` with release profile optimizations for size (`lto`, `strip`, `opt-level = "z"`). - Provides detailed documentation in `README.md` explaining the build process, prerequisites, and architecture. * build script for mac * consolidate both scripts * improve script --------- Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
571 lines
16 KiB
Bash
Executable File
571 lines
16 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Rebuild Arti native libraries from official source
|
|
#
|
|
# This script clones the official Arti repository, applies our custom JNI wrapper,
|
|
# and builds the native libraries for Android. Use this to:
|
|
# - Verify the pre-built .so files match the source
|
|
# - Update to a new Arti version
|
|
# - Debug or modify the wrapper code
|
|
#
|
|
# Requirements:
|
|
# - Bash 4+ (macOS default bash is 3.2; install via Homebrew: brew install bash)
|
|
# - Rust toolchain with Android targets:
|
|
# rustup target add aarch64-linux-android x86_64-linux-android
|
|
# - cargo-ndk: cargo install cargo-ndk
|
|
# - Android NDK 25+ (for 16KB page size support)
|
|
#
|
|
# Usage:
|
|
# ./build-arti.sh # Build both architectures (debug/emulator)
|
|
# ./build-arti.sh --release # Build ARM64 only (production)
|
|
# ./build-arti.sh --clean # Remove cloned Arti repo and rebuild
|
|
|
|
set -euo pipefail
|
|
|
|
# ==============================================================================
|
|
# Configuration
|
|
# ==============================================================================
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Script and project directories
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
ARTI_SOURCE_DIR="$SCRIPT_DIR/.arti-source"
|
|
JNILIBS_DIR="$PROJECT_ROOT/app/src/main/jniLibs"
|
|
|
|
|
|
detect_default_ndk_home() {
|
|
local candidates=(
|
|
"$HOME/Library/Android/sdk/ndk/27.0.12077973"
|
|
"$HOME/Library/Android/sdk/ndk"
|
|
"$HOME/Library/Android/sdk/ndk-bundle"
|
|
"$HOME/Android/Sdk/ndk/27.0.12077973"
|
|
"$HOME/Android/Sdk/ndk"
|
|
"$HOME/Android/Sdk/ndk-bundle"
|
|
)
|
|
|
|
for candidate in "${candidates[@]}"; do
|
|
if [ -d "$candidate" ]; then
|
|
echo "$candidate"
|
|
return
|
|
fi
|
|
done
|
|
|
|
local base
|
|
for base in "$HOME/Library/Android/sdk/ndk" "$HOME/Android/Sdk/ndk"; do
|
|
if [ -d "$base" ]; then
|
|
local latest
|
|
latest="$(find "$base" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sort | tail -1)"
|
|
if [ -n "$latest" ]; then
|
|
echo "$latest"
|
|
return
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Read pinned version
|
|
if [ ! -f "$SCRIPT_DIR/ARTI_VERSION" ]; then
|
|
echo -e "${RED}Error: ARTI_VERSION file not found${NC}"
|
|
exit 1
|
|
fi
|
|
VERSION="$(tr -d '[:space:]' < "$SCRIPT_DIR/ARTI_VERSION")"
|
|
|
|
# Android NDK path
|
|
if [ -z "${ANDROID_NDK_HOME:-}" ]; then
|
|
AUTO_NDK_HOME="$(detect_default_ndk_home)"
|
|
if [ -n "$AUTO_NDK_HOME" ]; then
|
|
ANDROID_NDK_HOME="$AUTO_NDK_HOME"
|
|
fi
|
|
fi
|
|
if [ -z "${ANDROID_NDK_HOME:-}" ]; then
|
|
echo -e "${RED}Error: ANDROID_NDK_HOME is not set and automatic detection failed.${NC}"
|
|
echo "Set ANDROID_NDK_HOME to your NDK installation (e.g., ~/Android/Sdk/ndk/<version>)."
|
|
exit 1
|
|
fi
|
|
export ANDROID_NDK_HOME
|
|
|
|
# Min SDK version (must match bitchat-android minSdk)
|
|
MIN_SDK_VERSION=26
|
|
|
|
# Parse arguments
|
|
RELEASE_ONLY=false
|
|
CLEAN_BUILD=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--release)
|
|
RELEASE_ONLY=true
|
|
shift
|
|
;;
|
|
--clean)
|
|
CLEAN_BUILD=true
|
|
shift
|
|
;;
|
|
--help|-h)
|
|
echo "Usage: $0 [--release] [--clean]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --release Build ARM64 only (smaller, for production)"
|
|
echo " --clean Remove cached Arti source and rebuild from scratch"
|
|
echo ""
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo -e "${RED}Error: Unknown argument: $1${NC}"
|
|
echo "Run: $0 --help"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Architectures to build
|
|
if [ "$RELEASE_ONLY" = true ]; then
|
|
TARGETS=("aarch64-linux-android")
|
|
else
|
|
TARGETS=("aarch64-linux-android" "x86_64-linux-android")
|
|
fi
|
|
|
|
# Map Rust targets to Android ABI names
|
|
declare -A ABI_MAP=(
|
|
["aarch64-linux-android"]="arm64-v8a"
|
|
["x86_64-linux-android"]="x86_64"
|
|
)
|
|
|
|
# Toolchain placeholders (set in detect_ndk_host)
|
|
NDK_HOST=""
|
|
NDK_LLVM_BIN=""
|
|
LLVM_STRIP=""
|
|
LLVM_NM=""
|
|
LLVM_READELF=""
|
|
|
|
# ==============================================================================
|
|
# Functions
|
|
# ==============================================================================
|
|
|
|
print_header() {
|
|
echo -e "${BLUE}=========================================${NC}"
|
|
echo -e "${BLUE}$1${NC}"
|
|
echo -e "${BLUE}=========================================${NC}"
|
|
}
|
|
|
|
print_success() { echo -e "${GREEN}$1${NC}"; }
|
|
print_error() { echo -e "${RED}$1${NC}"; }
|
|
print_info() { echo -e "${YELLOW}$1${NC}"; }
|
|
|
|
detect_ndk_host() {
|
|
local uname_s
|
|
uname_s="$(uname -s)"
|
|
local PREBUILT_DIR="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt"
|
|
local HOST_CANDIDATES=()
|
|
|
|
case "$uname_s" in
|
|
Darwin)
|
|
HOST_CANDIDATES=("darwin-arm64" "darwin-x86_64")
|
|
;;
|
|
Linux)
|
|
HOST_CANDIDATES=("linux-x86_64" "linux-arm64" "linux-aarch64")
|
|
;;
|
|
*)
|
|
print_error "Unsupported host OS: $uname_s"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
for candidate in "${HOST_CANDIDATES[@]}"; do
|
|
if [ -d "$PREBUILT_DIR/$candidate" ]; then
|
|
NDK_HOST="$candidate"
|
|
NDK_LLVM_BIN="$PREBUILT_DIR/$candidate/bin"
|
|
LLVM_STRIP="$NDK_LLVM_BIN/llvm-strip"
|
|
LLVM_NM="$NDK_LLVM_BIN/llvm-nm"
|
|
LLVM_READELF="$NDK_LLVM_BIN/llvm-readelf"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
print_error "No compatible NDK toolchain found under $PREBUILT_DIR"
|
|
print_info "Searched for: ${HOST_CANDIDATES[*]}"
|
|
exit 1
|
|
}
|
|
|
|
check_prerequisites() {
|
|
print_header "Checking Prerequisites"
|
|
|
|
# Bash version
|
|
if [ "${BASH_VERSINFO:-0}" -lt 4 ]; then
|
|
print_error "Bash 4+ is required. macOS ships bash 3.2 by default."
|
|
print_info "macOS: brew install bash"
|
|
print_info "Linux: use your distro package manager (e.g., sudo apt install bash)"
|
|
print_info "Then run with the installed bash (e.g., /opt/homebrew/bin/bash ./build-arti.sh)"
|
|
exit 1
|
|
fi
|
|
print_success "Bash found: $BASH_VERSION"
|
|
|
|
# Git
|
|
if ! command -v git >/dev/null 2>&1; then
|
|
print_error "git is not installed."
|
|
exit 1
|
|
fi
|
|
print_success "git found: $(git --version)"
|
|
|
|
# Rust
|
|
if ! command -v rustc >/dev/null 2>&1; then
|
|
print_error "Rust is not installed. Install from https://rustup.rs/"
|
|
exit 1
|
|
fi
|
|
print_success "Rust found: $(rustc --version)"
|
|
|
|
# rustup
|
|
if ! command -v rustup >/dev/null 2>&1; then
|
|
print_error "rustup is required (for managing targets). Install from https://rustup.rs/"
|
|
exit 1
|
|
fi
|
|
print_success "rustup found: $(rustup --version | head -1)"
|
|
|
|
# cargo-ndk
|
|
if ! command -v cargo-ndk >/dev/null 2>&1; then
|
|
print_error "cargo-ndk is not installed. Run: cargo install cargo-ndk"
|
|
exit 1
|
|
fi
|
|
print_success "cargo-ndk found: $(cargo-ndk --version 2>/dev/null || echo 'installed')"
|
|
|
|
# NDK
|
|
if [ ! -d "$ANDROID_NDK_HOME" ]; then
|
|
print_error "Android NDK not found at: $ANDROID_NDK_HOME"
|
|
print_info "Set ANDROID_NDK_HOME environment variable to your NDK location"
|
|
exit 1
|
|
fi
|
|
print_success "Android NDK found: $ANDROID_NDK_HOME"
|
|
|
|
# NDK version (should be 25+)
|
|
NDK_VERSION="$(basename "$ANDROID_NDK_HOME" | cut -d'.' -f1)"
|
|
if ! [[ "$NDK_VERSION" =~ ^[0-9]+$ ]]; then
|
|
print_error "Could not parse NDK version from ANDROID_NDK_HOME: $ANDROID_NDK_HOME"
|
|
exit 1
|
|
fi
|
|
if [ "$NDK_VERSION" -lt 25 ]; then
|
|
print_error "NDK version $NDK_VERSION is too old. NDK 25+ required for 16KB page size support"
|
|
exit 1
|
|
fi
|
|
print_success "NDK version: $NDK_VERSION (supports 16KB page size)"
|
|
|
|
detect_ndk_host
|
|
if [ ! -d "$NDK_LLVM_BIN" ]; then
|
|
print_error "NDK LLVM toolchain bin directory not found: $NDK_LLVM_BIN"
|
|
exit 1
|
|
fi
|
|
print_success "NDK host tag: $NDK_HOST"
|
|
|
|
if [ ! -x "$LLVM_STRIP" ]; then
|
|
print_info "llvm-strip not found at: $LLVM_STRIP (stripping will be skipped)"
|
|
else
|
|
print_success "llvm-strip found"
|
|
fi
|
|
|
|
if [ ! -x "$LLVM_NM" ] && ! command -v nm >/dev/null 2>&1; then
|
|
print_error "Neither llvm-nm nor nm found. Cannot verify JNI symbols."
|
|
exit 1
|
|
fi
|
|
if [ -x "$LLVM_NM" ]; then
|
|
print_success "llvm-nm found"
|
|
else
|
|
print_info "llvm-nm not found, will fall back to system nm"
|
|
fi
|
|
|
|
if [ ! -x "$LLVM_READELF" ] && ! command -v readelf >/dev/null 2>&1; then
|
|
print_info "Neither llvm-readelf nor readelf found. Alignment verification may be skipped."
|
|
else
|
|
print_success "readelf capability available"
|
|
fi
|
|
# Android targets
|
|
for TARGET in "${TARGETS[@]}"; do
|
|
if ! rustup target list --installed | grep -qx "$TARGET"; then
|
|
print_error "Rust target $TARGET not installed"
|
|
print_info "Run: rustup target add $TARGET"
|
|
exit 1
|
|
fi
|
|
done
|
|
print_success "All Rust Android targets installed"
|
|
|
|
echo ""
|
|
}
|
|
|
|
clone_or_update_arti() {
|
|
print_header "Setting up Arti Source (version: $VERSION)"
|
|
|
|
if [ "$CLEAN_BUILD" = true ] && [ -d "$ARTI_SOURCE_DIR" ]; then
|
|
print_info "Cleaning existing Arti source..."
|
|
rm -rf "$ARTI_SOURCE_DIR"
|
|
fi
|
|
|
|
if [ ! -d "$ARTI_SOURCE_DIR" ]; then
|
|
print_info "Cloning official Arti repository..."
|
|
git clone https://gitlab.torproject.org/tpo/core/arti.git "$ARTI_SOURCE_DIR"
|
|
else
|
|
print_info "Using cached Arti source at $ARTI_SOURCE_DIR"
|
|
fi
|
|
|
|
cd "$ARTI_SOURCE_DIR"
|
|
|
|
print_info "Fetching tags..."
|
|
git fetch --tags --quiet
|
|
|
|
print_info "Checking out version: $VERSION"
|
|
git checkout "$VERSION" --quiet 2>/dev/null || {
|
|
print_error "Version $VERSION not found. Available versions:"
|
|
git tag | grep "^arti-v" | tail -10
|
|
exit 1
|
|
}
|
|
|
|
# Ensure clean working tree to avoid cached modifications influencing builds
|
|
print_info "Resetting repository state (hard) and cleaning untracked files..."
|
|
git reset --hard --quiet
|
|
git clean -ffdqx --quiet
|
|
|
|
print_success "Arti source ready at version $VERSION"
|
|
echo ""
|
|
}
|
|
|
|
setup_wrapper() {
|
|
print_header "Setting up JNI Wrapper"
|
|
|
|
WRAPPER_DIR="$ARTI_SOURCE_DIR/arti-android-wrapper"
|
|
|
|
# Recreate wrapper directory to avoid stale files
|
|
rm -rf "$WRAPPER_DIR"
|
|
mkdir -p "$WRAPPER_DIR/src"
|
|
|
|
cp "$SCRIPT_DIR/src/lib.rs" "$WRAPPER_DIR/src/"
|
|
cp "$SCRIPT_DIR/Cargo.toml" "$WRAPPER_DIR/"
|
|
|
|
print_success "Wrapper files copied to $WRAPPER_DIR"
|
|
echo ""
|
|
}
|
|
|
|
build_for_target() {
|
|
local TARGET="$1"
|
|
local ABI="${ABI_MAP[$TARGET]}"
|
|
local OUTPUT_PATH="$JNILIBS_DIR/$ABI"
|
|
|
|
print_header "Building for $ABI ($TARGET)"
|
|
|
|
mkdir -p "$OUTPUT_PATH"
|
|
|
|
print_info "Building Arti Android wrapper..."
|
|
cargo ndk \
|
|
-t "$TARGET" \
|
|
--platform "$MIN_SDK_VERSION" \
|
|
-o "$OUTPUT_PATH" \
|
|
build --release \
|
|
--locked \
|
|
--manifest-path "$ARTI_SOURCE_DIR/arti-android-wrapper/Cargo.toml"
|
|
|
|
local LIB_NAME="libarti_android.so"
|
|
local NESTED_PATH="$OUTPUT_PATH/$ABI/$LIB_NAME"
|
|
|
|
if [ -f "$NESTED_PATH" ]; then
|
|
mv "$NESTED_PATH" "$OUTPUT_PATH/$LIB_NAME"
|
|
rmdir "$OUTPUT_PATH/$ABI" 2>/dev/null || true
|
|
fi
|
|
|
|
if [ -f "$OUTPUT_PATH/$LIB_NAME" ]; then
|
|
print_success "Built: $OUTPUT_PATH/$LIB_NAME"
|
|
|
|
# Strip debug symbols safely
|
|
print_info "Stripping debug symbols..."
|
|
if [ -x "$LLVM_STRIP" ]; then
|
|
"$LLVM_STRIP" --strip-debug "$OUTPUT_PATH/$LIB_NAME" 2>/dev/null || true
|
|
print_success "Stripped debug symbols"
|
|
else
|
|
print_info "Skipping strip (llvm-strip not available)"
|
|
fi
|
|
|
|
local SIZE
|
|
SIZE="$(du -h "$OUTPUT_PATH/$LIB_NAME" | cut -f1)"
|
|
print_success "Final size: $SIZE"
|
|
|
|
# Verify 16KB page size alignment (best-effort)
|
|
print_info "Verifying 16KB page alignment..."
|
|
local READELF_TOOL=""
|
|
if [ -x "$LLVM_READELF" ]; then
|
|
READELF_TOOL="$LLVM_READELF"
|
|
elif command -v readelf >/dev/null 2>&1; then
|
|
READELF_TOOL="$(command -v readelf)"
|
|
fi
|
|
|
|
if [ -n "$READELF_TOOL" ]; then
|
|
local ALIGNMENT
|
|
ALIGNMENT="$("$READELF_TOOL" -l "$OUTPUT_PATH/$LIB_NAME" 2>/dev/null | grep "LOAD" | head -1 | awk '{print $NF}' || echo "unknown")"
|
|
if [ "$ALIGNMENT" = "0x4000" ] || [ "$ALIGNMENT" = "16384" ]; then
|
|
print_success "16KB page alignment verified: $ALIGNMENT"
|
|
else
|
|
print_info "Page alignment: $ALIGNMENT (NDK handles 16KB at link time)"
|
|
fi
|
|
else
|
|
print_info "Skipping alignment check (readelf not available)"
|
|
fi
|
|
else
|
|
print_error "Build failed: $LIB_NAME not found"
|
|
return 1
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
verify_jni_symbols_for_lib() {
|
|
local LIB_PATH="$1"
|
|
|
|
if [ ! -f "$LIB_PATH" ]; then
|
|
print_error "Library not found: $LIB_PATH"
|
|
return 1
|
|
fi
|
|
|
|
local EXPECTED_SYMBOLS=(
|
|
"Java_org_torproject_arti_ArtiNative_getVersion"
|
|
"Java_org_torproject_arti_ArtiNative_setLogCallback"
|
|
"Java_org_torproject_arti_ArtiNative_initialize"
|
|
"Java_org_torproject_arti_ArtiNative_startSocksProxy"
|
|
"Java_org_torproject_arti_ArtiNative_stop"
|
|
)
|
|
|
|
local ALL_FOUND=true
|
|
for SYMBOL in "${EXPECTED_SYMBOLS[@]}"; do
|
|
local FOUND=false
|
|
|
|
if [ -x "$LLVM_NM" ]; then
|
|
if "$LLVM_NM" -D --defined-only "$LIB_PATH" 2>/dev/null | grep -q "$SYMBOL"; then
|
|
FOUND=true
|
|
fi
|
|
elif command -v nm >/dev/null 2>&1; then
|
|
# Fallback (may be unreliable for ELF on macOS)
|
|
if nm -g "$LIB_PATH" 2>/dev/null | grep -q "$SYMBOL"; then
|
|
FOUND=true
|
|
fi
|
|
fi
|
|
|
|
if [ "$FOUND" = true ]; then
|
|
print_success " Found: $SYMBOL"
|
|
else
|
|
print_error " Missing: $SYMBOL"
|
|
ALL_FOUND=false
|
|
fi
|
|
done
|
|
|
|
if [ "$ALL_FOUND" = true ]; then
|
|
print_success "All JNI symbols verified for: $LIB_PATH"
|
|
else
|
|
print_error "Some JNI symbols are missing for: $LIB_PATH"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
verify_jni_symbols() {
|
|
print_header "Verifying JNI Symbols"
|
|
print_info "Checking exported JNI symbols..."
|
|
|
|
local FAILED=false
|
|
|
|
for TARGET in "${TARGETS[@]}"; do
|
|
local ABI="${ABI_MAP[$TARGET]}"
|
|
local LIB_PATH="$JNILIBS_DIR/$ABI/libarti_android.so"
|
|
print_info "Verifying $ABI: $LIB_PATH"
|
|
if ! verify_jni_symbols_for_lib "$LIB_PATH"; then
|
|
FAILED=true
|
|
fi
|
|
done
|
|
|
|
if [ "$FAILED" = true ]; then
|
|
return 1
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
show_summary() {
|
|
print_header "Build Complete!"
|
|
|
|
echo -e "${GREEN}Built libraries:${NC}"
|
|
for TARGET in "${TARGETS[@]}"; do
|
|
local ABI="${ABI_MAP[$TARGET]}"
|
|
local LIB_PATH="$JNILIBS_DIR/$ABI/libarti_android.so"
|
|
if [ -f "$LIB_PATH" ]; then
|
|
local SIZE
|
|
SIZE="$(du -h "$LIB_PATH" | cut -f1)"
|
|
echo -e " ${GREEN}$ABI:${NC} $SIZE"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
echo -e "${GREEN}Arti version:${NC} $VERSION"
|
|
echo -e "${GREEN}Source:${NC} https://gitlab.torproject.org/tpo/core/arti"
|
|
echo ""
|
|
echo -e "${GREEN}Next steps:${NC}"
|
|
echo " 1. Test the build: ./gradlew assembleDebug"
|
|
echo " 2. Commit the .so files: git add app/src/main/jniLibs/"
|
|
echo ""
|
|
echo -e "${GREEN}To update Arti version:${NC}"
|
|
echo " 1. Edit ARTI_VERSION with new version tag (e.g., arti-v1.8.0)"
|
|
echo " 2. Run: ./build-arti.sh --clean"
|
|
echo ""
|
|
}
|
|
|
|
# ==============================================================================
|
|
# Main
|
|
# ==============================================================================
|
|
|
|
main() {
|
|
print_header "Arti Android Build Script"
|
|
echo -e "${BLUE}Building Arti for Android with 16KB page size support${NC}"
|
|
echo -e "${BLUE}Version: $VERSION${NC}"
|
|
echo -e "${BLUE}Architectures: ${TARGETS[*]}${NC}"
|
|
echo ""
|
|
|
|
check_prerequisites
|
|
clone_or_update_arti
|
|
setup_wrapper
|
|
ensure_wrapper_lockfile
|
|
|
|
for TARGET in "${TARGETS[@]}"; do
|
|
build_for_target "$TARGET"
|
|
done
|
|
|
|
verify_jni_symbols
|
|
show_summary
|
|
}
|
|
|
|
ensure_wrapper_lockfile() {
|
|
print_header "Ensuring wrapper Cargo.lock exists"
|
|
|
|
local WRAPPER_DIR="$ARTI_SOURCE_DIR/arti-android-wrapper"
|
|
local LOCKFILE="$WRAPPER_DIR/Cargo.lock"
|
|
|
|
if [ -f "$LOCKFILE" ]; then
|
|
print_success "Cargo.lock already exists"
|
|
echo ""
|
|
return 0
|
|
fi
|
|
|
|
print_info "Cargo.lock missing; generating it once (network access may be required)..."
|
|
(cd "$WRAPPER_DIR" && cargo generate-lockfile)
|
|
|
|
if [ ! -f "$LOCKFILE" ]; then
|
|
print_error "Failed to generate Cargo.lock at $LOCKFILE"
|
|
return 1
|
|
fi
|
|
|
|
print_success "Generated Cargo.lock"
|
|
echo ""
|
|
}
|
|
|
|
main
|