Skip to content
Latchkey

emulator: Run a Headless Android Emulator in CI

The emulator binary launches an AVD; passing -no-window -no-audio -no-boot-anim runs it headless with less overhead on a CI runner.

A CI runner has no display and no sound card, so the emulator must run headless. Getting hardware acceleration and cold-boot flags right is the difference between a 60-second boot and a job that never gets past the boot animation.

What it does

emulator -avd <name> starts the named AVD in the qemu-based Android emulator. Headless flags drop the UI window, audio, and boot animation. Acceleration flags select KVM (Linux) or HAXM/HVF; snapshot flags control whether it cold-boots or restores saved state.

Common usage

Terminal
$ANDROID_HOME/emulator/emulator -avd test_avd \
  -no-window -no-audio -no-boot-anim \
  -no-snapshot -gpu swiftshader_indirect \
  -accel on -camera-back none &
adb wait-for-device

Options

FlagWhat it does
-avd <name>AVD to launch
-no-windowRun without the emulator GUI window
-no-audioDisable audio (no sound device on runners)
-no-boot-animSkip the boot animation to speed boot
-no-snapshot / -no-snapshot-loadCold boot instead of restoring a snapshot
-gpu swiftshader_indirectSoftware GL rendering when no GPU is present
-accel onRequire hardware acceleration (KVM/HAXM/HVF)

In CI

On Linux runners you need KVM; on GitHub-hosted ubuntu-latest, KVM is available and the reactivecircus/android-emulator-runner action wires all of this up. Use -gpu swiftshader_indirect for reliable software rendering, and -no-snapshot to avoid restoring a corrupt snapshot from a prior run.

Common errors in CI

"/dev/kvm device permission denied" or "KVM is required to run this AVD" means the runner lacks KVM access; add the runner user to the kvm group or use a runner with nested virtualization. "emulator: ERROR: x86_64 emulation currently requires hardware acceleration!" means -accel/KVM is off. "Cannot find AVD system path" means the AVD or its system image is missing. A hang at the boot animation usually means a GPU flag mismatch; switch to -gpu swiftshader_indirect.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →