Run Android's aapt2 (x86-64) on aarch64 Linux via QEMU user mode.
Google ships aapt2 only as an x86-64 binary. On ARM64 Linux (Apple Silicon Asahi,
Raspberry Pi 5, etc.) AGP runs it through the system's binfmt_misc dispatcher,
which can be unreliable. This project wraps it with qemu-x86_64 for consistent
behaviour and predictable performance (~0.07 s per call).
sudo dnf install -y qemu-user erofs-utilsDebian/Ubuntu: sudo apt install qemu-user-static erofs-utils
Arch: sudo pacman -S qemu-user-static erofs-utils
Please read the script before executing it. For safety concerns, always do so.
curl -sLO https://raw.githubusercontent.com/IgnacioLD/aapt2-qemu/main/aapt2-qemu-setup.sh
# review the script:
less aapt2-qemu-setup.sh
# run it:
sh aapt2-qemu-setup.sh
./gradlew assembleDebugThe script:
- Mounts the FEX emulator rootfs (erofs image) as the x86-64 sysroot.
- Locates the newest x86-64
aapt2that AGP already downloaded. - Writes a tiny wrapper that invokes
qemu-x86_64 -L <sysroot> <aapt2>. - Sets
android.aapt2FromMavenOverridein~/.gradle/gradle.properties.
Run it once per session — the FUSE mount is ephemeral.
| Variable | Default | Description |
|---|---|---|
AAPT2_EROFS |
/usr/share/fex-emu/RootFS/default.erofs |
Path to the FEX rootfs image |
AAPT2_SYSROOT |
/tmp/aapt2-x86root |
Mount point for the FUSE image |
AAPT2_WRAPPER_DIR |
$HOME/.local/share/aapt2-qemu |
Where the wrapper script lives |
Override any of them to customise paths:
AAPT2_SYSROOT=/custom/mount ./aapt2-qemu-setup.shIf you don't have FEX installed, provide any x86-64 rootfs that contains
lib64/ld-linux-x86-64.so.2 and the required libraries. Set AAPT2_EROFS to
a directory instead of an erofs image (the script skips the FUSE mount when
it's not a file).
AAPT2_EROFS=/custom-x86-rootfs ./aapt2-qemu-setup.shAGP calls aapt2 during resource processing. The wrapper:
- For
aapt2 version: merges stderr→stdout becauseaapt2prints its version banner to stderr but AGP reads the version from stdout. - For all other commands: passes everything through to
qemu-x86_64without redirecting stderr (AGP monitors the daemon's stderr pipe and treats EOF as a crash).
The wrapper filename must end in aapt2 — AGP checks this with
path.endsWith("aapt2") and rejects anything else.
The SDK adb at $ANDROID_HOME/platform-tools/adb is also x86-64 and won't
run natively. Install the native ARM64 package instead:
sudo dnf install android-toolsThen use /usr/bin/adb (or ensure it comes first in $PATH).
Debian/Ubuntu: sudo apt install adb
Arch: sudo pacman -S android-tools