Skip to content

Conversation

@simonrozsival
Copy link
Member

Summary

This PR adds automatic Android emulator lifecycle management to XHarness, matching the behavior of iOS simulators. When no suitable device is found, XHarness can now automatically start an emulator with the exact API level and architecture requirements, eliminating manual emulator management.

Key improvements:

  • ✅ Automatic emulator start when no matching device found (opt-in with --api-version)
  • --reset-emulator flag for data wiping and cleanup (iOS parity with --reset-simulator)
  • ✅ Diagnostic collection on emulator boot failures (disk space, memory, AVD config)
  • ✅ Consistent cross-platform experience between Android and iOS workflows

Note: API version and architecture validation already existed in XHarness. This PR adds automation of emulator lifecycle, not the validation logic itself.

Usage Examples

1. Automatic emulator start with specific API level

# Before: Manual emulator management required
emulator -avd Pixel_5_API_34 -no-window &
xharness android test --app=test.apk --package-name=com.example.test

# After: Automatic emulator lifecycle
xharness android test --app=test.apk --package-name=com.example.test --api-version=34

2. Clean slate testing with data wipe

# Matches iOS: --reset-simulator behavior
xharness android test --app=test.apk --package-name=com.example.test \
  --api-version=34 --reset-emulator

3. Architecture-specific testing

# Ensures correct architecture match (e.g., x86_64 for Intel Macs)
xharness android test --app=test.apk --package-name=com.example.test \
  --api-version=34 --device-arch=x86_64

4. Helix/CI integration

# No manual emulator setup in CI scripts
<HelixWorkItem Include="TestApp">
  <Command>xharness android test --app test.apk --api-version=34 --reset-emulator</Command>
</HelixWorkItem>

Before vs After Comparison

Manual workflow (before)

# 1. List available AVDs
emulator -list-avds

# 2. Start correct emulator manually
emulator -avd Pixel_5_API_34 -no-window &

# 3. Wait for boot
adb wait-for-device

# 4. Run tests
xharness android test --app=test.apk --package-name=com.example.test

# 5. Manually stop emulator
adb emu kill

Automated workflow (after)

# Single command does everything
xharness android test --app=test.apk --package-name=com.example.test \
  --api-version=34 --reset-emulator

iOS Parity Achieved

Feature iOS Android (Before) Android (After)
Manual lifecycle required No Yes ⚠️ No ✅
Automatic start with version Yes No ⚠️ Yes ✅
--reset-* flag for data wipe Yes No ⚠️ Yes ✅
Stop after test completion With flag Manual ⚠️ With flag ✅
Default preserves state Yes Yes (if running) Yes
Boot diagnostics on failure Limited No ⚠️ Yes ✅

Problems solved by this PR:

  • ❌ Manual emulator start/stop required in CI scripts
  • ❌ No automatic cleanup between test runs
  • ❌ Inconsistent experience between iOS and Android workflows
  • ❌ No diagnostic collection when emulators fail to boot

Technical Implementation

New Components

EmulatorManager (src/Microsoft.DotNet.XHarness.Android/EmulatorManager.cs)

  • AVD discovery and filtering by API level/architecture
  • Emulator process lifecycle (start/stop/kill)
  • Boot completion detection with timeout
  • State management for running emulators

EmulatorDiagnostics (src/Microsoft.DotNet.XHarness.Android/EmulatorDiagnostics.cs)

  • Disk space analysis when boot fails
  • Memory availability check
  • Running process inspection
  • AVD configuration dump

AdbRunner.GetDeviceOrStartEmulator (src/Microsoft.DotNet.XHarness.Android/AdbRunner.cs#L936-L1011)

  • Extended device selection with fallback to emulator start
  • Existing API/architecture validation (unchanged from before)
  • Automatic cleanup of other running emulators
  • Error handling with diagnostic collection

Integration Points

Commands now call GetDeviceOrStartEmulator instead of GetSingleDevice:

// Before: Manual device selection only
var device = _adbRunner.GetSingleDevice(
    requiredApiVersion: apiVersion,
    requiredArchitectures: architectures);

// After: Automatic emulator start when needed
var device = _adbRunner.GetDeviceOrStartEmulator(
    emulatorManager: _emulatorManager,
    startEmulatorIfNeeded: apiVersion.HasValue,
    wipeEmulatorData: resetEmulator,
    requiredApiVersion: apiVersion,
    requiredArchitectures: architectures);

Design Decisions

  1. Opt-in behavior: Emulator start only triggered when --api-version specified

    • Prevents unexpected behavior changes
    • Makes requirements explicit
  2. Stop other emulators first: Avoids resource contention

    • Only one emulator runs at a time
    • Matches iOS simulator behavior
  3. Diagnostic collection on failure: Helps troubleshoot boot issues

    • Collects disk space, memory, processes
    • Dumps AVD configuration for analysis
  4. Device ID takes precedence: If --device-id specified, never start emulator

    • User explicitly wants that specific device
    • Maintains backward compatibility

Testing

  • ✅ Unit tests in Microsoft.DotNet.XHarness.Android.Tests
  • ✅ Integration tests on Helix: tests/integration-tests/Android/Emulator.Lifecycle.Tests.proj
  • ✅ Existing tests continue to pass (backward compatible)

Related Issues

Closes #1459 - Add support for running workitems on specified Android emulator API levels
References #393 - Automatically create and boot Android emulators
References #1488 - Timeout on android leaves test processes running

- Extend device selection to optionally start emulator when none matches
- Add GetDeviceOrStartEmulator method to AdbRunner with emulator lifecycle
- Update AndroidInstallCommand and AndroidTestCommand to use emulator start flow
- Add --reset-emulator CLI flag (matches iOS --reset-simulator semantics)
- Implement emulator cleanup after test completion when --reset-emulator used
- Add integration tests for emulator lifecycle on Helix infrastructure
@simonrozsival simonrozsival force-pushed the dev/srozsival/android-start-device-with-specific-api-level branch from 69269a2 to f74d49e Compare December 11, 2025 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[android] Add support for running workitems on specified Android emulator API levels

2 participants