$ android-arm-build-tools 

drop-in aapt2, aidl, zipalign, split-select for Linux ARM64.

install.sh releases source

why does this exist

Google's sdkmanager ships these four binaries for linux-x86_64 only. On a Raspberry Pi, Asahi Linux box, ARM Chromebook, Ampere server, or native-arm64 WSL, the Android Gradle Plugin invokes them and gets exec format error instead of an APK.

This project bypasses Soong, clones ~40 specific AOSP repos, and cross-compiles the four binaries against glibc with gcc-aarch64-linux-gnu. Result: drop in, build APKs natively on arm64.

install

Install the matching build-tools first via sdkmanager — the Java pieces (apksigner, dx, etc.) come from there. We only replace the four native binaries.

sdkmanager "build-tools;37.0.0"

Then run the installer:

curl -fsSL https://raw.githubusercontent.com/Commit451/android-arm-build-tools/main/install.sh | bash

The script picks up the latest release, detects your SDK via $ANDROID_HOME / $ANDROID_SDK_ROOT / ~/Android/Sdk, and writes the binaries into $SDK/build-tools/<version>/. To pin a specific version or use a non-default SDK path:

./install.sh --version 37.0.0 --sdk /opt/android-sdk

It refuses to run on non-aarch64 hosts and on SDKs missing the target build-tools/<version>/ directory.

agp 9.x: also point aapt2 at the arm64 binary

extra step

Android Gradle Plugin 9.x stopped using the SDK's aapt2 and instead pulls its own from Maven (com.android.tools.build:aapt2:<agp>:linux), which is x86_64-only. The drop-in is still needed by other build steps, but on AGP 9+ also tell Gradle to use the arm64 binary directly. Prefer the user-level Gradle properties file so the machine can build every Android project without committing machine-specific paths:

mkdir -p ~/.gradle
cat >> ~/.gradle/gradle.properties <<'EOF'
android.aapt2FromMavenOverride=/home/you/Android/Sdk/build-tools/37.0.0/aapt2
EOF

Use the full path to the aapt2 that this project's installer wrote. For one-project-only overrides, put the same property in that project's gradle.properties instead. Do not put it in local.properties; AGP does not read this override from there.

Restart the Gradle daemon afterward (./gradlew --stop). AGP 8.x and older don't need this — they still shell out to the SDK's aapt2.

available versions

Auto-refreshed when the site rebuilds. Each tag is built from the AOSP source ref shown.

version android source ref status published
37.0.0 Android 17 GA android-17.0.0_r1 mapped 2026-06-18 download
36.1.0 Android 16 QPR1 android-16.0.0_r3 mapped 2026-05-22 download
36.0.0 Android 16 GA android-16.0.0_r1 mapped 2026-05-22 download
35.0.1 Android 15 platform-tools-35.0.1 legacy 2026-05-21 download

what if sdkmanager has something newer than the latest release?

sdkmanager sometimes publishes a build-tools version before AOSP tags the corresponding source publicly. During that gap the resolver reports no-source and no arm64 release is published yet. 37.0.0 used to be in that state; it is now mapped to android-17.0.0_r1 and available above. When a future source tag appears, the daily workflow auto-detects it and publishes a matching arm64 release here — no action needed on this end.

compatibility

Binaries are built on Debian 12 (Bookworm) — glibc 2.36, GCC 12 — so they need glibc 2.36+ and GLIBCXX_3.4.30+ at runtime. Distros that work out of the box:

Raspberry Pi OS Bookworm (glibc 2.36)
Debian 12+
Ubuntu 22.04+ (glibc 2.35, close enough)
Fedora 38+ / Asahi Linux
Anything newer than the above

Older distros: build from source against your distro's libc.

verify

After install, this should work in any AGP project without exec format error:

./gradlew :app:assembleDebug

Or smoke-test the binary directly:

$ANDROID_HOME/build-tools/37.0.0/aapt2 version
# Android Asset Packaging Tool (aapt) 2.X-...

links