{"slug": "termux-proot-to-avf-flutter-build", "title": "Termux proot to avf flutter build", "summary": "A developer successfully built a Flutter APK inside Android's Virtualization Framework (AVF), a built-in pKVM-based Linux VM, after moving from Termux's proot environment. The developer found proot's syscall interception via ptrace caused performance overhead and incompatibility with glibc-based installers, while AVF provided a native Linux kernel with no translation overhead. They overcame ARM64 toolchain mismatches by using cross-compiled aapt2 and ARM64-native cmake, enabling the build to complete.", "body_md": "So I moved to Android's built-in Linux VM (AVF) and somehow got a Flutter APK to build\n\n`flutter build apk --debug`\n\nworking 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.\n\nAnthropic'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.\n\n| proot | AVF | |\n|---|---|---|\n| What it actually is | Android kernel + syscall translation layer | Real Linux kernel (separate VM) |\n| Speed | Translation overhead | Native-ish |\n| Official installer | Breaks (glibc mismatch) | Just works |\n| Effect on existing setup | — | Fully isolated, coexists fine with Termux/proot |\n\nThis 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.\n\nOnce the VM was up, the official installer went through clean:\n\n```\ncurl -fsSL https://claude.ai/install.sh | bash\nexport PATH=\"$HOME/.local/bin:$PATH\"\necho 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.bashrc\nsource ~/.bashrc\nclaude --version\n```\n\nCloned the Flutter SDK and spun up a plain sample app to test with:\n\n```\nflutter create sample_app\ncd sample_app\nflutter config --enable-web\nflutter pub get\nflutter run -d web-server --web-port=8080 --web-hostname=0.0.0.0\n```\n\nAVF runs in its own isolated network namespace, so opening `0.0.0.0:8080`\n\ninside 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).\n\nOnce that was sorted, `http://localhost:8080`\n\nloaded the default Flutter counter app fine — Web verification done.\n\nAVF 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.\n\n(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`\n\npub.dev package for FFI. `flutter create --template=plugin_ffi my_native_plugin`\n\ngives you a minimal repro with the same `CMakeLists.txt`\n\nbuild path.)\n\n```\nAAPT2 aapt2-9.0.1-14304508-linux Daemon #0: Unexpected error output: \n.../aapt2: 1: Syntax error: \")\" unexpected\n```\n\nChecked with `file`\n\n: host is `aarch64`\n\n, but the aapt2 pulled from Maven is `x86-64`\n\n.\n\n``` bash\n$ uname -m\naarch64\n$ file .../aapt2\n...: ELF 64-bit LSB pie executable, x86-64, ...\n```\n\nAGP 9.x fetches aapt2 from Maven directly instead of the SDK, and that Maven artifact just isn't built for ARM64 Linux.\n\nFound a project called `android-arm-build-tools`\n\n(commit451.com) that cross-compiles aapt2/aidl/zipalign/split-select for ARM64 by cloning ~40 AOSP repos. Installed that, then pointed `gradle.properties`\n\nat it:\n\n```\nandroid.aapt2FromMavenOverride=/path/to/arm64/aapt2\n```\n\nSame story with the SDK-bundled cmake (3.22.1) when the native build (the `jni`\n\npackage) kicked in. Fixed by swapping in Debian's `apt`\n\ncmake, which is ARM64-native:\n\n```\nsudo apt install -y cmake ninja-build\n```\n\nThis override has to go in `local.properties`\n\n, not `gradle.properties`\n\n— cost me a wasted build cycle figuring that out:\n\n```\ncmake.dir=/usr\n```\n\nEven with cmake fixed, the NDK's bundled clang compiler itself was `linux-x86_64`\n\nand just wouldn't run:\n\n```\n.../toolchains/llvm/prebuilt/linux-x86_64/bin/clang: Exec format error\n```\n\nGoogle 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:\n\n```\nsudo apt install -y qemu-user-static binfmt-support\n```\n\nStill got an error after that:\n\n```\nx86_64-binfmt-P: Could not open '/lib64/ld-linux-x86-64.so.2': No such file or directory\n```\n\nqemu 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:\n\n```\nsudo dpkg --add-architecture amd64\nsudo apt update\nsudo apt install -y libc6:amd64 libstdc++6:amd64 zlib1g:amd64\nbash\n$ flutter build apk --debug\nRunning Gradle task 'assembleDebug'...    111.8s\n✓ Built build/app/outputs/flutter-apk/app-debug.apk\n```\n\n| Symptom | Cause | Fix |\n|---|---|---|\n| aapt2 won't start | Maven's aapt2 is x86_64-only | Swap in an ARM64-native build |\n| 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`\n|\n| NDK clang won't run | No official ARM64-native NDK from Google | qemu-user-static + multiarch (amd64 libs) to emulate it |\n\nA 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.\n\nIf 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.\n\nStuff 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.\n\n**Terminal crashing on basic commands right after initial setup**\n\nRight after my first setup, `curl -fsSL https://claude.ai/install.sh | bash`\n\nproduced nothing. `ping`\n\nworked fine, but `curl`\n\nitself crashed with `Illegal instruction`\n\n. Swapped to `wget`\n\n— `Segmentation fault`\n\n. Reinstalled curl — same crash.\n\nI 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.\n\n**Random disconnects every ~3 minutes, even with the screen on**\n\nNot 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.", "url": "https://wpnews.pro/news/termux-proot-to-avf-flutter-build", "canonical_source": "https://dev.to/kojiisd/termux-proot-to-avf-flutter-build-3a1m", "published_at": "2026-08-14 07:12:32+00:00", "updated_at": "2026-08-14 07:46:18.518384+00:00", "lang": "en", "topics": ["developer-tools", "mlops"], "entities": ["Termux", "AVF", "Flutter", "Claude Code", "Anthropic", "Android", "aapt2", "cmake"], "alternates": {"html": "https://wpnews.pro/news/termux-proot-to-avf-flutter-build", "markdown": "https://wpnews.pro/news/termux-proot-to-avf-flutter-build.md", "text": "https://wpnews.pro/news/termux-proot-to-avf-flutter-build.txt", "jsonld": "https://wpnews.pro/news/termux-proot-to-avf-flutter-build.jsonld"}}