# Termux proot to avf flutter build

> Source: <https://dev.to/kojiisd/termux-proot-to-avf-flutter-build-3a1m>
> Published: 2026-08-14 07:12:32+00:00

So I moved to Android's built-in Linux VM (AVF) and somehow got a Flutter APK to build

`flutter build apk --debug`

working on AVF.My setup was Termux + proot-distro (Ubuntu) running Claude Code, and it was noticeably heavy. Turns out this isn't a config issue, it's structural: proot runs on top of Android's actual kernel and intercepts every single syscall via ptrace to fake a "real Ubuntu" environment. That interception itself burns CPU, and it's not even 100% compatible — some syscalls behave differently or just don't work.

Anthropic's official native installer ships a glibc binary, which is fundamentally incompatible with Termux's Bionic libc at the ABI level, so it won't even run there without proot. AVF (Android's Virtualization Framework) sidesteps this entirely: it's a built-in pKVM-based Linux VM feature. Unlike proot (pseudo-virtualization via syscall translation), it's a genuine, isolated Linux kernel with no translation overhead.

| proot | AVF | |
|---|---|---|
| What it actually is | Android kernel + syscall translation layer | Real Linux kernel (separate VM) |
| Speed | Translation overhead | Native-ish |
| Official installer | Breaks (glibc mismatch) | Just works |
| Effect on existing setup | — | Fully isolated, coexists fine with Termux/proot |

This is a standard Android feature, so if you don't like it, just flip the toggle off, or reset the VM from the Terminal app's settings. It's fully isolated from your existing Termux/proot setup, so nothing there gets touched.

Once the VM was up, the official installer went through clean:

```
curl -fsSL https://claude.ai/install.sh | bash
export PATH="$HOME/.local/bin:$PATH"
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
claude --version
```

Cloned the Flutter SDK and spun up a plain sample app to test with:

```
flutter create sample_app
cd sample_app
flutter config --enable-web
flutter pub get
flutter run -d web-server --web-port=8080 --web-hostname=0.0.0.0
```

AVF runs in its own isolated network namespace, so opening `0.0.0.0:8080`

inside the VM doesn't automatically become reachable from the Android browser. Had to open **Settings → Port control** in the Terminal app to allow the port (starting the server first, then opening Port control, usually gets it detected).

Once that was sorted, `http://localhost:8080`

loaded the default Flutter counter app fine — Web verification done.

AVF runs on ARM64 (aarch64), but a bunch of tools in the Android SDK/Gradle ecosystem only ship official x86_64 binaries. That mismatch bit me three separate times, and each one had to be tracked down and fixed before the next one even showed up.

(Quick note on reproducing this: the aapt2 issue in 6-1 shows up on basically any Flutter Android build, native code or not. The cmake/NDK issues in 6-2 and 6-3 only kick in once a native build is involved — mine came from the `jni`

pub.dev package for FFI. `flutter create --template=plugin_ffi my_native_plugin`

gives you a minimal repro with the same `CMakeLists.txt`

build path.)

```
AAPT2 aapt2-9.0.1-14304508-linux Daemon #0: Unexpected error output: 
.../aapt2: 1: Syntax error: ")" unexpected
```

Checked with `file`

: host is `aarch64`

, but the aapt2 pulled from Maven is `x86-64`

.

``` bash
$ uname -m
aarch64
$ file .../aapt2
...: ELF 64-bit LSB pie executable, x86-64, ...
```

AGP 9.x fetches aapt2 from Maven directly instead of the SDK, and that Maven artifact just isn't built for ARM64 Linux.

Found a project called `android-arm-build-tools`

(commit451.com) that cross-compiles aapt2/aidl/zipalign/split-select for ARM64 by cloning ~40 AOSP repos. Installed that, then pointed `gradle.properties`

at it:

```
android.aapt2FromMavenOverride=/path/to/arm64/aapt2
```

Same story with the SDK-bundled cmake (3.22.1) when the native build (the `jni`

package) kicked in. Fixed by swapping in Debian's `apt`

cmake, which is ARM64-native:

```
sudo apt install -y cmake ninja-build
```

This override has to go in `local.properties`

, not `gradle.properties`

— cost me a wasted build cycle figuring that out:

```
cmake.dir=/usr
```

Even with cmake fixed, the NDK's bundled clang compiler itself was `linux-x86_64`

and just wouldn't run:

```
.../toolchains/llvm/prebuilt/linux-x86_64/bin/clang: Exec format error
```

Google doesn't officially ship an ARM64-native Linux NDK, so binary-swapping wasn't an option here. Switched tack and emulated the x86_64 binary with qemu-user-static instead:

```
sudo apt install -y qemu-user-static binfmt-support
```

Still got an error after that:

```
x86_64-binfmt-P: Could not open '/lib64/ld-linux-x86-64.so.2': No such file or directory
```

qemu itself was working, but the x86_64 binary it was trying to run needed x86_64 versions of shared libraries (glibc etc.) that simply didn't exist on ARM64. Fixed by pulling in x86_64 libs via Debian's multiarch support:

```
sudo dpkg --add-architecture amd64
sudo apt update
sudo apt install -y libc6:amd64 libstdc++6:amd64 zlib1g:amd64
bash
$ flutter build apk --debug
Running Gradle task 'assembleDebug'...    111.8s
✓ Built build/app/outputs/flutter-apk/app-debug.apk
```

| Symptom | Cause | Fix |
|---|---|---|
| aapt2 won't start | Maven's aapt2 is x86_64-only | Swap in an ARM64-native build |
| cmake won't start | SDK's bundled cmake is x86_64-only | Swap in apt's ARM64-native cmake, point `cmake.dir` in `local.properties`
|
| NDK clang won't run | No official ARM64-native NDK from Google | qemu-user-static + multiarch (amd64 libs) to emulate it |

A lot of the AGP/NDK toolchain still treats ARM64 Linux as a second-class citizen. This whole exercise was basically peeling back one x86_64 assumption at a time until the toolchain would actually run on an ARM64 host.

If you only need Flutter Web verification, moving to AVF is a clear win — noticeably faster, not much setup pain. APK builds are a different story: they need all the workarounds above, so it's more effort than it sounds going in. For now I'm using AVF for Web checks and keeping proot (or this patched-up AVF setup) around for APK builds.

Stuff that came up during this whole process but isn't really part of the "make the toolchain work on ARM64" story — filing it here in case you hit the same thing.

**Terminal crashing on basic commands right after initial setup**

Right after my first setup, `curl -fsSL https://claude.ai/install.sh | bash`

produced nothing. `ping`

worked fine, but `curl`

itself crashed with `Illegal instruction`

. Swapped to `wget`

— `Segmentation fault`

. Reinstalled curl — same crash.

I don't have solid evidence this is a known/common AVF issue rather than a one-off corrupted download on my end, but if you hit something similar (basic commands crashing for no obvious reason, right after a fresh install), a VM reset fixed it immediately for me: Terminal app → Settings → Recovery → "Reset to initial version." Since I hadn't installed anything yet, there was nothing to lose.

**Random disconnects every ~3 minutes, even with the screen on**

Not a screen-off/backgrounding issue — the Terminal app kept flipping to "Reconnect" mid-session regardless. Turned out to be memory pressure: the default VM memory allocation is 1024MB, nowhere near enough for a Gradle build (JVM + native compilation). Bumping it up to ~3GB in Terminal app → Settings → Advanced → Memory size fixed it. Couldn't push it all the way to 4GB — that ceiling depends on how much free RAM the phone itself has left at the time.
