Run a full Android development environment inside an Incus container with hardware-accelerated emulator via KVM.
| Mode | Stack | Use Case | Access |
|---|---|---|---|
| Headless | android |
CI/CD, automated testing, command-line builds | SSH + ADB |
| GUI | android-studio |
App UI development, manual testing, full IDE | SSH + VNC |
- Container must have
security.nesting=true(Containarium sets this by default when Podman is enabled) - Host must support KVM (
grep -c vmx /proc/cpuinfo> 0) - Recommended: 8+ CPU cores, 16GB+ RAM, 50GB+ disk
containarium create android-dev \
--ssh-key ~/.ssh/id_ed25519.pub \
--cpu 8 --memory 16GB --disk 100GB \
--stack android \
--backend-id tunnel-node-b-gpuAfter creation, SSH in and use:
ssh android-dev
# Build a project
cd /path/to/project
./gradlew assembleDebug
# Start emulator (headless)
emulator -avd default -no-window -no-audio -gpu swiftshader_indirect &
# Wait for boot
adb wait-for-device
adb shell getprop sys.boot_completed # Returns "1" when ready
# Run tests
./gradlew connectedAndroidTest
# Stop emulator
adb emu killcontainarium create android-studio-dev \
--ssh-key ~/.ssh/id_ed25519.pub \
--cpu 8 --memory 16GB --disk 100GB \
--stack android-studio \
--backend-id tunnel-node-b-gpuAfter creation:
ssh android-studio-dev
# Start VNC server (first time sets up desktop)
vncserver :1 -geometry 1920x1080 -depth 24
# VNC is now listening on port 5901Access the desktop:
Option A — VNC client (recommended for low latency):
# From your laptop, create SSH tunnel:
ssh -L 5901:localhost:5901 android-studio-dev
# Connect VNC client to localhost:5901
# Password: containariumOption B — Browser via noVNC (no client install):
# Inside the container:
sudo apt install novnc websockify
websockify --web /usr/share/novnc 6080 localhost:5901 &
# From your laptop, tunnel port 6080:
ssh -L 6080:localhost:6080 android-studio-dev
# Open browser: http://localhost:6080/vnc.htmlThen launch Android Studio:
# In the VNC desktop terminal:
studio.sh &- OpenJDK 17 (headless)
- Android SDK command-line tools
- Android SDK platform tools (adb, fastboot)
- Android build tools 35.0.0
- Android platform API 35
- Android Emulator with x86_64 system image
- Pre-created AVD:
default(Pixel 6, Android 15) - QEMU/KVM for emulator acceleration
- Everything in
androidstack, plus: - OpenJDK 17 (full, with GUI support)
- Android Studio (latest stable)
- XFCE4 desktop environment
- TigerVNC server
- Noto fonts
# Headless (no GUI needed)
emulator -avd default -no-window -no-audio -gpu swiftshader_indirect &
# With VNC (visible in VNC desktop)
emulator -avd default -gpu swiftshader_indirect &For better emulator performance on GPU-equipped peers:
# If the container has GPU passthrough:
emulator -avd default -gpu host &
# Software rendering (always works, slower):
emulator -avd default -gpu swiftshader_indirect &# List available system images
sdkmanager --list | grep system-images
# Install a different API level
sdkmanager "system-images;android-34;google_apis;x86_64"
# Create AVD
avdmanager create avd -n android34 \
-k "system-images;android-34;google_apis;x86_64" \
-d pixel_6
# List AVDs
avdmanager list avd# List connected devices/emulators
adb devices
# Install APK
adb install app-debug.apk
# Logcat
adb logcat
# Shell into emulator
adb shell
# Screenshot
adb exec-out screencap -p > screenshot.png
# Record screen
adb shell screenrecord /sdcard/demo.mp4
adb pull /sdcard/demo.mp4Example script for automated builds and tests:
#!/bin/bash
set -euo pipefail
# Start emulator
emulator -avd default -no-window -no-audio -gpu swiftshader_indirect &
EMU_PID=$!
# Wait for boot (up to 5 minutes)
adb wait-for-device
timeout 300 bash -c 'while [ "$(adb shell getprop sys.boot_completed 2>/dev/null)" != "1" ]; do sleep 5; done'
# Disable animations for faster tests
adb shell settings put global window_animation_scale 0
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0
# Run tests
./gradlew connectedAndroidTest
# Cleanup
kill $EMU_PID 2>/dev/nullThe container needs nested virtualization:
# Check from inside container
kvm-ok
# If not supported, the container needs security.nesting=true
# Containarium sets this by default with --podman flag- Use
-gpu swiftshader_indirect(software GPU) - Ensure KVM is working:
emulator -accel-check - Increase container CPU/memory
source ~/.bashrc
# Or set manually:
export ANDROID_HOME=/opt/android-sdk
export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$PATH# Check if VNC is running
vncserver -list
# Start if not running
vncserver :1 -geometry 1920x1080 -depth 24
# Kill and restart
vncserver -kill :1
vncserver :1 -geometry 1920x1080 -depth 24