How We Built a Virtual Device Farm for Android E2E Tests
Article Summary
İbrahim Süren from Trendyol reveals how they ditched job-local emulators and built their own virtual device farm. The result? Predictable Android E2E tests at scale without the resource contention nightmares.
Trendyol's Android team needed reliable E2E tests on every change, but job-local emulators created bottlenecks with duplicated setup, resource competition, and flaky UI timing. They evaluated four deployment models before building Awilix, an internal device farm running ARM64 emulators on Apple Silicon Mac Minis with hardware acceleration and GPU rendering.
Key Takeaways
- Dedicated Mac Minis run ARM64 emulators with Hypervisor.framework and host GPU
- One CI job requests multiple ADB endpoints, fans out tests in parallel
- PostgreSQL coordinates API replicas while runners own local process state
- Allocation IDs fence stale commands after slot reuse or delayed stops
- Phase metrics track scheduling, boot, ADB discovery, and consumer verification separately
Awilix separates device lifecycle from CI jobs through verified ADB endpoints, letting Trendyol scale compute independently while keeping test code framework-neutral.
About This Article
Nested virtualization in containers kept failing. When job-local emulators ran on virtual workers or shared cluster nodes, they couldn't reach the host's /dev/kvm. This forced hardware virtualization through multiple hypervisor layers, which the scheduler's placement decisions didn't support.
Awilix runs on dedicated Apple Silicon Mac Minis with direct KVM and GPU access. This removes the nested virtualization problem entirely. ARM64 emulators run through Hypervisor.framework with host GPU rendering instead of SwiftShader software fallbacks.
Maestro workloads that were slow on Cuttlefish with SwiftShader now run reliably on native ARM64 emulators. Graphics mode stays fixed and CPU/memory resources are stable. The flaky UI timing and transient ADB failures that plagued job-local deployments are gone.