Skip to main content
Mobile developers using MacStadium VDI often need Android emulator access alongside their macOS desktop for testing, debugging, or running Android apps in parallel with their Citrix-managed session. Android emulators cannot run inside a macOS virtual machine. The Apple Virtualization Framework does not support nested virtualization, so the emulator has no access to the hardware hypervisor it requires. Running an emulator inside a VM is not a supported path. MacStadium VDI solves this by running the Android emulator natively on the Apple Silicon host node, on the same physical machine as your macOS VM. An ADB relay is automatically configured between the host-side emulator and your VM, so your desktop session can reach the Android device over ADB without manual network setup or a third-party emulator service.

Prerequisites

Before setting up Android Virtual Devices, ensure:
  • MacStadium VDI is deployed and operational (see the Deployment Guide)
  • Ansible runner has sshpass installed
  • The target macOS VM is running on a host node where the Android SDK will be installed

Install the Android SDK

Run this on the Ansible runner to install the Android SDK on your host nodes. This installs:
  • Homebrew (if not already present)
  • Eclipse Temurin JDK 21
  • Android command-line tools, platform-tools, and emulator packages
  • socat (used to set up the ADB relay between the host and your VM)
  • A run-avd script at /opt/orka/bin/run-avd
It also configures JAVA_HOME, ANDROID_HOME, and PATH in the host’s .zshrc.
ansible-playbook install_android_sdk.yml -i inventory
To force reinstallation on hosts where the SDK is already present:
ansible-playbook install_android_sdk.yml -i inventory -e "install_android_sdk_force=true"

Install SDK Platforms and System Images

Once the Android SDK is installed, install the platform and system images you want to use for your AVDs.
ansible-playbook sdkmanager_install.yml -i inventory
This installs platform android-35 with default and google_apis system images by default. To specify a different platform or image types:
ansible-playbook sdkmanager_install.yml -i inventory -e "platform=android-34" -e "image_types=default,google_apis,google_apis_playstore"
Available variables:
  • platform — Android platform to install (default: android-35)
  • image_types — comma-separated list of system image types (default: default,google_apis)

Create an Android Virtual Device

AVDs are tied to a specific VM. The AVD name is derived automatically from the VM name using the pattern {vm_name}-avd-{index}, where the index increments for each additional AVD on that VM (e.g. my-vm-avd-0, my-vm-avd-1). Run with --tags plan first to preview which host the AVD will be created on:
ansible-playbook deploy_avd.yml -i inventory -e "vm_name=my-vm" --tags plan
Then create the AVD:
ansible-playbook deploy_avd.yml -i inventory -e "vm_name=my-vm"
The playbook locates the host running the specified VM, determines the next available AVD index, creates the AVD, and sets up network connectivity between the host-side emulator and the VM. Available variables:
  • vm_name (required) — name of the running VM the AVD should be associated with
  • platform — Android platform to use (default: android-35)
  • image_type — system image type (default: default)
  • run_avd — whether to start the AVD immediately after creation (default: true)
  • cpu — vCPUs to allocate to the AVD
  • memory — memory in MB to allocate to the AVD
Example with custom settings:
ansible-playbook deploy_avd.yml -i inventory -e "vm_name=my-vm" -e "platform=android-34" -e "image_type=google_apis" -e "cpu=4" -e "memory=2048"

Manage Android Virtual Devices

Start, stop, or delete an AVD

Use avd.yml to bring an AVD to a desired state. The playbook is idempotent - it will not attempt to start an already running AVD, stop an already stopped one, or delete one that does not exist.
ansible-playbook avd.yml -i inventory -e "vm_name=my-vm" -e "desired_state=running"
Valid values for desired_state: running, stopped, absent When only one AVD exists for a VM, it is selected automatically. If multiple AVDs exist, specify which one using avd_index:
ansible-playbook avd.yml -i inventory -e "vm_name=my-vm" -e "desired_state=absent" -e "avd_index=1"
To preview the planned action without making changes:
ansible-playbook avd.yml -i inventory -e "vm_name=my-vm" -e "desired_state=running" --tags plan

List AVDs

To list all AVDs across all hosts:
ansible-playbook list_avds.yml -i inventory
To filter by VM:
ansible-playbook list_avds.yml -i inventory -e "vm_name=my-vm"
Each AVD is displayed with its host and status. Running AVDs include additional details: PID, gateway IP, and ADB relay port.

Delete an AVD

To delete a specific AVD by index:
ansible-playbook delete_avd.yml -i inventory -e "vm_name=my-vm" -e "avd_index=0"
If the AVD is currently running, the playbook stops it before deleting. Required variables:
  • vm_name — name of the VM the AVD is associated with
  • avd_index — index of the AVD to delete (e.g. 0 for my-vm-avd-0)

Uninstall SDK Platforms and System Images

To uninstall a specific platform and all of its system images from host nodes:
ansible-playbook sdkmanager_uninstall.yml -i inventory
This uninstalls android-35 by default. To target a different platform:
ansible-playbook sdkmanager_uninstall.yml -i inventory -e "platform=android-34"