Skip to content

android-emulator-layer

Version 2026.174.0700
Repo superproject

Compose selkies + android-sdk + appium into a booting Android 16 emulator. Composite glue layer that turns the underlying selkies-desktop + android-sdk + appium-server stack into a running Android 16 (API 36, google_apis_playstore x86_64, pixel_9a) emulator. The Play Store image ships Play Store + Google Play services (GMS) + Google Chrome preinstalled. Ships two helper scripts (start-emulator, wait-for-display), two supervisord services (emulator + adb-server), the AVD volume, and the /dev/kvm device-passthrough declaration that round-trips through the OCI label into the quadlet. CPU/RAM are auto-sized from the host at runtime (start-emulator). Optional GOOGLE_ACCOUNT_EMAIL + GOOGLE_AAS_TOKEN secrets feed the charly check adb install-app --source google-play path. The helper scripts, the AVD home directory, and the booted device are all directly observable, so the behaviour is verifiable end to end.

  • emulator
  • adb-server

This candy’s plan: — the runnable spec charly check executes against a live deployment. check: steps are idempotent probes; run: steps change state.

Intent Step
run command=set -e USERNAME=“$(getent passwd 1000 | cut -d: -f1)” # Add user to BOTH the container’s kvm group (satisfies the emulator’s # naive /etc/group preflight check that prints “The KVM line in # /etc/group is: [kvm:x:36:user]”) AND the nobody group (gid 65534). # /dev/kvm inside a rootless container is owned by nobody:nobody # because the host’s kvm group (gid 990) maps through subgid to the # overflow gid 65534. supervisord’s setuid+initgroups drops the # supplementary groups crun-keep-groups provided at container start, # so user must be listed in /etc/group for both groups to retain # access across the setuid boundary. if getent group kvm >/dev/null 2>&1; then usermod -aG kvm “${USERNAME}” fi if getent group nobody >/dev/null 2>&1; then usermod -aG nobody “${USERNAME}” fi
run copy=start-emulator
run copy=wait-for-display
run mkdir=${HOME}/.android
run mkdir=${HOME}/.android/avd
check the start-emulator launcher is installed and executable
check the wait-for-display gate is installed and executable
check the AVD home directory exists for the runtime user
check the emulator supervisord service is running
check the adb server port is reachable on the host
check adb reports the device fully booted
check the booted AVD reports Android version 16
check adb=devices
check adb=getprop
check adb=shell
check adb=shell
check adb=wait-ui-settled
check adb=shell
check adb=shell
check adb=shell
check adb=shell
check adb=shell
check adb=screencap
check adb=shell
check adb=shell
check adb=shell
check adb=shell
check adb=shell
check adb=install
check adb=shell
check adb=screencap
check adb=uninstall
check appium=session-create
check appium=raw
check appium=install-app
check adb=shell
check adb=shell
check appium=app-is-installed
check appium=app-activate
check appium=app-start-activity
check appium=send-keys
check appium=get-text
check appium=app-start-activity
check appium=gesture-tap
check appium=get-attribute
check appium=app-start-activity
check appium=gesture-tap
check appium=get-attribute
check appium=app-start-activity
check appium=gesture-scroll
check appium=find
check appium=app-start-activity
check appium=gesture-tap
check appium=gesture-tap
check appium=source
check appium=app-start-activity
check appium=get-text
check appium=app-start-activity
check appium=gesture-swipe
check appium=get-text
check appium=app-start-activity
check appium=gesture-drag
check appium=source
check appium=app-start-activity
check appium=device-contexts
check appium=device-context
check appium=source
check appium=device-context
check appium=app-start-activity
check appium=gesture-tap
check appium=device-notifications
check appium=source
check appium=key-press
check appium=device-info
check appium=app-current-package
check appium=device-orientation
check appium=execute
check appium=raw
check appium=screenshot
check appium=session-delete