Test Results, Firebase Test Lab, and What's Next for Pockr
Part 6 of 6 — the final chapter of building Pockr, a single APK that runs Docker on non-rooted Android.
← Part 5: Debugging a VM Restart Loop
Download
pockr-v1.apk — v1.0.0 · ARM64 · 163 MB
Release notes · GitHub
Requires Android 9+ (API 28), ARM64 device. Enable "Install from unknown sources" before installing.
How We Test: Firebase Test Lab
Physical device testing on a Mac with an Android emulator is unreliable for this project — QEMU needs hardware virtualisation, and nested virtualisation in emulators doesn't work.
Instead, every build gets tested on Firebase Test Lab with a Robo test:
| Setting | Value |
|---|---|
| Device | Pixel 2 (arm64) |
| Android version | 11 (API 30) |
| Test type | Robo (automated UI crawler) |
| Timeout | 600 seconds |
| Architecture | ARM64 (same as real phones) |
The Robo crawler explores the UI systematically — tapping every button it finds, navigating every screen, filling forms. It's brutal but effective at finding race conditions and edge cases that manual testing misses.
Test History
| Version | Result | What Changed |
|---|---|---|
| v11–v20 | ❌ Various crashes | ELF/linker issues, asset extraction bugs |
| v22 | ✅ Pass | VmManager as Application singleton — QEMU survives Activity relaunch |
| v23 | ✅ Pass | DNS fix (use-vc + 8.8.8.8 fallback) — Docker Hub reachable |
| v24 | ✅ Pass | Flutter ScaffoldMessenger context fix |
| v25 | ✅ Pass | First container pull + run — busybox and nginx from Docker Hub (~78s) |
| v28 | ✅ Pass | Release APK + Pockr branding |
| v30 | ✅ Pass | Corrected APK filename in test script |
| v33 | ✅ Pass | Race condition fix in VmManager.getStatus() — no more restart loop |
| v34 | ❌ Fail | Double-start found — Robo tapped Start during starting→running transition, launching a second QEMU instance |
| v35 | ✅ Pass | Double-start guard in VmState.startVm() — confirmed no double-start, containers running |
What a Passing Test Looks Like
From the v35 logcat (second boot — Docker image cache already warm):
03:38:02 VmManager: Starting VM...
03:38:02 VmManager: Reusing existing user.qcow2 (Docker image cache preserved)
03:38:02 VmManager: VM process launched
... Alpine second boot: ~50 seconds ...
... API server comes up ...
03:38:53 VmApiClient: Container started: alpine_1772710722409 ✅
03:39:28 VmApiClient: Container started: test_1772710762640 ✅
From cold install (first boot, Docker + Python setup):
03:35:33 VmManager: Starting VM...
03:35:33 VmManager: Extracted vm/base.qcow2 (fresh install)
03:35:33 VmManager: VM process launched
... Alpine first boot: ~2–5 minutes ...
... Docker installs, API server bootstraps ...
From cold install to running container: ~5 minutes.
Second boot (Docker image cache warm): ~50 seconds.
What Works Today
- ✅ Install APK → tap Start → QEMU boots Alpine Linux
- ✅ Docker pulls images from Docker Hub over SLIRP networking
- ✅
busybox,alpine,nginxconfirmed running on real hardware (ARM64, Android 11) - ✅ Persistent overlay disk — pulled images survive VM restarts
- ✅ No root. No Termux. No PC required after install.
- ✅ Foreground service keeps VM alive when app is backgrounded
- ✅ Auto-start option to launch VM on app open
Current Limitations
| Limitation | Notes |
|---|---|
| First boot ~5 min | Docker + Python bootstrap on Alpine; subsequent boots ~50s |
| ARM64 only | QEMU binary targets aarch64 only (no ARM32/x86) |
Storage driver: vfs
|
Less efficient than overlay2, but works without kernel modules |
--network host only |
No isolated container networks without bridge module |
| APK size ~163 MB | Includes full Alpine disk image + QEMU binary + 50 libraries |
What's Next
- [ ] Stop container / view logs in app UI
- [ ] ARM32 device support
- [ ] Reduce first-boot time
- [ ] Custom container image support from UI
The Full Series
- Part 1: The Idea and Architecture
- Part 2: Executing Binaries on Android — The SELinux Problem
- Part 3: Bundling 50 Native Libraries Without Breaking the Android Linker
- Part 4: Making Docker Run Without iptables, bridge, or overlay2
- Part 5: Debugging a VM Restart Loop — A Race Condition in Kotlin
- Part 6: Test Results and What's Next ← you are here
Pockr Series — Docker in Your Pocket
Pockr = Pocket + Docker. A single Android APK that runs real Docker containers in your pocket — no root, no Termux, no PC required.
| # | Post | Topic |
|---|---|---|
| 📖 | Intro | What is Pockr? Start here |
| 1 | Part 1 | The Idea and Architecture |
| 2 | Part 2 | Executing Binaries — The SELinux Problem |
| 3 | Part 3 | Bundling 50 Native Libraries |
| 4 | Part 4 | Docker Without Kernel Modules |
| 5 | Part 5 | Debugging the VM Restart Loop |
| 6 | Part 6 | Test Results and What's Next |
GitHub: github.com/AI2TH/Pockr
QA & Release Engineer: Kalvin Nathan
skalvinnathan@gmail.com · LinkedIn
Top comments (0)