dotnet / dotnet/android

EmulatorRunner: return serial / console port / adb port / log path from launch

Open
#12,083 0 comments 1 reaction 2 assignees Claimed by @rmarinho View on GitHub
android-tools enhancement needs-triage
Dominant language
C#
Stars
2.1k
Forks
579
Avg merge
1d 20h
Merged PRs (30d)
257

Description

## Context

Xamarin.Android.Tools.EmulatorRunner.LaunchEmulator(name, coldBoot) returns a bare System.Diagnostics.Process. Callers (e.g. `dotnet/maui-labs` `maui android emulator start` — see https://github.com/dotnet/maui-labs/issues/138) want to surface to users / scripts:

- The emulator **serial** (`emulator-NNNN`).
- The **console port** and **adb port**.
- The **log file path** the emulator writes to.

Today none of this is available from `EmulatorRunner` without out-of-band work:

- Serial / ports → caller has to diff `adb devices` before/after launch (race-prone, requires waiting for adb to see it, breaks fire-and-forget mode).
- Log path → caller has to hardcode the AOSP convention (`\/.avd/emulator.log` or `\C:\Users\rumar/.android/avd/.avd/emulator.log`) — fine until the emulator is launched with `-logfile` or a custom `ANDROID_AVD_HOME`.

This duplicates logic in every consumer and is fragile. The data is all available to `EmulatorRunner` itself — the emulator prints serial/port info to stdout at boot, and `EmulatorRunner` controls the launch arg list.

## Proposal

### 1. Richer launch result

Introduce a new return type and overload (keep existing `LaunchEmulator` signature for compatibility):

```csharp
public sealed class EmulatorLaunchResult
{
public Process Process { get; init; }
public int Pid => Process.Id;
public int? ConsolePort { get; init; } // populated once stdout is parsed (or pre-assigned)
public int? AdbPort { get; init; }
public string? Serial => ConsolePort is int p ? \$"emulator-{p}" : null;
public string LogPath { get; init; } // resolved at launch time
public Task PortsResolvedAsync { get; init; } // completes when stdout parse finds the port lines
}

public EmulatorLaunchResult LaunchEmulatorWithDetails(
string avdName,
bool coldBoot = false,
int? consolePort = null, // optional pre-assignment via -ports
int? adbPort = null,
string? logFile = null);
```

### 2. Pre-assigned ports (optional but recommended)

When `consolePort` is passed, `EmulatorRunner` adds `-ports ,` to the qemu command line. This lets callers know the serial **before the process even starts** — no stdout race, no adb diff. AOSP supports console ports 5554–5682 in steps of 2.

If not passed, `EmulatorRunner` reserves a free pair itself (probe + bind) or falls back to stdout parsing.

### 3. Stdout capture for late binding

When ports are not pre-assigned, `EmulatorRunner` should redirect stdout (it likely already does for diagnostics) and parse the well-known lines the emulator emits at boot:

`
emulator: Listening on port
emulator: ADB Server has started successfully on port
emulator: Logs in
`

These complete the `PortsResolvedAsync` task. Format has been stable across `emulator` releases for years; if it shifts, only this one place changes.

### 4. `BootEmulatorAsync` returns the same shape

`BootEmulatorAsync` (the wait-for-boot path) should return `EmulatorLaunchResult` enriched with `Serial` always populated (since by definition adb has seen it), instead of the current opaque result.

## Compatibility

- Existing `LaunchEmulator` / `BootEmulatorAsync` signatures **stay** — additive only.
- New entry points are `LaunchEmulatorWithDetails` and a `BootEmulatorWithDetailsAsync` overload (or extend the existing result type with new optional members).
- `EmulatorLaunchResult` is a new public type.

## Why this matters

- Eliminates the race in every downstream tool that pairs `maui device list` against `maui android emulator start`.
- Makes `maui android emulator start --json` a complete, scriptable response (matches the new Google `android emulator start` CLI shape: log path + pid + serial + status).
- Enables non-`--wait` launches to still return a serial — currently impossible without polling.
- Removes the need for downstream tools to scavenge `\/running/pid_*.ini` to figure out which qemu PID maps to which emulator (see `dotnet/maui-labs#135`).

## Related

- `dotnet/maui-labs#138` — consumer-side enhancement that benefits directly.
- `dotnet/maui-labs#135` — pid-file based liveness (avoidable for emulators we launched ourselves once this lands).

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.