A third backend: User-Mode Linux (experimental)
Until now a phone without hardware virtualization had one option: QEMU, which emulates every guest CPU instruction in software. This release adds UML, which runs the guest Linux kernel as an ordinary Android process, so guest code runs directly on the CPU. It needs no root, no adb grant and no special permission, and it works on any arm64 phone with Android 8 or later (#107, #111).
UML is opt-in. Auto never picks it, and AVF stays the best choice on phones that have it. It is aimed at everyone else.
Measured speed
Nothing Phone (1), Android 15, no AVF. Same release build, same VM disk, 4 CPUs, 2 GB RAM. Median of three runs.
| Test | QEMU | UML | Change |
|---|---|---|---|
| Boot to Ready | 33 to 41 s | 13 to 18 s | about 2.5x faster |
npm install express (warm cache)
| 49.5 s | 24.8 s | 2.0x faster |
npm install express (cold cache, one run)
| 70.7 s | 34.5 s | 2.0x faster |
| Node.js CPU loop (300M iterations) | 18.8 s | 4.7 s | 4.0x faster |
docker run with a shell loop inside
| 19.7 s | 7.4 s | 2.7x faster |
apk add nodejs npm (one run, includes download)
| 21.2 s | 12.4 s | 1.7x faster |
npm --version
| 7.3 s | 4.6 s | 1.6x faster |
docker run --rm alpine true (container start only)
| 7.6 s | 8.2 s | no gain |
Pixel 10 Pro XL, Android 17, same test on all three backends:
| Test | QEMU | UML | AVF |
|---|---|---|---|
| Boot to Ready | 44 s | 36 s | 10 s |
npm install express (warm cache)
| 25.7 s | 20.6 s | 1.9 s |
| Node.js CPU loop | 10.5 s | 3.4 s | 0.9 s |
docker run with a shell loop inside
| 12.8 s | 8.9 s | 1.2 s |
docker run --rm alpine true
| 9.1 s | 8.4 s | 0.85 s |
What the numbers say: work that computes gains the most, package installs gain about 2x, and starting a container is not faster. On a fast phone the gap to QEMU narrows, and AVF is roughly ten times faster than either. If your phone has AVF, keep using it. These are measurements from two phones, not a promise for yours.
How to try it
- Stop the VM.
- Open Settings, tap Show advanced, and under Backend pick UML (experimental).
- Start the VM. The first start runs a short compatibility test (a few seconds, needs a network connection), then boots.
- Check that it took: the home screen now has a Backend row that should read UML (user-mode), and
uname -rin the terminal prints a different kernel than before. - Run what you normally run. Your containers, packages and files are the same disk on every backend, so you can switch back and forth without losing anything.
To go back, stop the VM and pick Auto.
If the compatibility test fails, or UML crashes or does not finish booting within two minutes, Podroid switches UML off on that phone and starts the VM on the backend Auto would have used, with a notification. Settings then shows the reason and a Try UML again button.
What is different on UML
- No USB passthrough. That still needs the QEMU backend.
- Every process in the VM is a real Android process. On Android 12 and later the system limits how many child processes apps may have, so a container-heavy workload can lose processes. On Android 14 and later, turn on Developer options > Disable child process restrictions. On Android 12 and 13, see the troubleshooting section of the guide.
- It is not a security boundary. The guest kernel runs with the app's own privileges. The Downloads share is restricted to the Downloads folder, but do not run untrusted code in UML expecting VM-grade isolation.
- Stopping takes longer, about 15 to 30 seconds for a clean shutdown.
- The guest network interface is
vec0instead ofeth0. Addresses, port forwards and SSH on 9922 behave as on QEMU. - The APK grows by about 13 MB.
Reports wanted
UML was tested on two phones. If you try it, a report helps a lot, whether it worked or not: phone model, Android version, what you ran, and the file from Settings > Diagnostics > Export diagnostic log. Phones with 16 KB memory pages and phones with old kernels (Android 8 to 11) have not been tested at all.
The UML kernel is built from the arm64 User-Mode Linux port by @zalexdev (https://github.com/zalexdev/linux-um-arm64). Its source, as built, is attached to this release as uml-source-32e5e10b8.tar.zst.
Know which backend you are on
The home screen shows the active backend, stopped or running, with the same wording as the Status screen. If a backend falls back to another one, the row says so (#68).
Live charts on the Status screen
Status now has Phone and VM tabs with live charts of about the last minute, updated twice a second: phone CPU, memory, storage and network, and VM CPU, emulator memory and disk growth. The exact figures sit under each tab. Based on the redesign proposed by @ChinmayaGit (#61).
The guide, inside the VM
The user guide ships in the guest. Run podroid-docs and open the address it prints to read it offline (#67). The contributor guide now documents the whole build, its outputs and how to customise the guest (#64).
Also new
podroid-phone-ipprints the phone's addresses from inside the VM, primary first (#87).- The setup wizard has the Load balance switch on its first step, so it is clear how to pick storage, RAM and CPUs yourself (#109).
- The guest moves to Linux 7.3 and the emulator to QEMU 11.1.2.
- The guest kernel includes the iptables
ipvsmatch that Docker swarm's routing mesh needs (#88).
Fixes
- USB passthrough no longer takes keyboards, mice, trackpads and touchscreens away from Android. On a dock or in DeX, granting the prompt used to leave you without input (#110).
- Auto stays on QEMU when a phone's Android build ships AVF with guest networking switched off, instead of booting a VM with no network. Settings says why (#43).
- The AVF guest no longer panics at boot on phones whose hypervisor advertises a CPU feature it does not let the guest use, seen on a Pixel 8 Pro with Android 17 (#108).
- USB devices now get the right speed on phones whose kernel cannot report it (kernels older than 4.14), which is what broke USB Wi-Fi adapters there (#85). This has not been confirmed on an affected phone yet, so reports are welcome.
- If the bundled VM images cannot be unpacked, for example when storage is full, the app now shows an error instead of starting a VM from a broken set of files (#94).
- The reason shown when AVF falls back to QEMU follows the app language (#96).
- Reliability improvements to port forwarding on AVF (#99) and across the VM backends.
Known limitations
- UML is experimental: no USB passthrough, exposed to Android's child-process limit, and untested on 16 KB page phones and on Android 8 to 11.
- If the phone is offline the first time you start UML, the compatibility test fails and UML stays off until you tap Try UML again.
- On some Wi-Fi networks the guest cannot resolve names even though
ping 8.8.8.8works (#93). Mobile data is the workaround. - USB Wi-Fi adapters that need firmware find none in the guest (#86).
apk add linux-firmware-rtlwifi, or the package for your chipset, works today. - Multi-core AVF VMs can still reboot on Pixel 8 and Pixel 9 class devices, where the AVF backend falls back to a single core (#29).
Tested on
- Pixel 10 Pro XL, Android 17: AVF, QEMU and UML.
- Nothing Phone (1), Android 15: QEMU and UML.
- On both, this build was installed over v1.2.9 with a VM that had packages and container images. Settings, port forwards and data carried over.
Thanks
- @zalexdev for the arm64 port of User-Mode Linux that the new backend is built on.
- @OPX-Aminul and @Taocrypt for asking for UML and pointing at prior work (#107, #111).
- @Kybernetria for the asset extraction check (#94), the localized fallback reason (#96) and the AVF forwarding work (#99).
- @ChinmayaGit for the Status screen redesign (#61).
- @goofrider, @pcause, @WriteCodeEveryday and @erraja97 for the reports behind the fixes above.