Skip to content
This repository was archived by the owner on Jul 13, 2026. It is now read-only.

Handle InvalidOperationException in emulator boot and improve Process disposal - #359

Merged
simonrozsival merged 1 commit into
mainfrom
copilot/fix-emulator-boot-error
May 8, 2026
Merged

Handle InvalidOperationException in emulator boot and improve Process disposal#359
simonrozsival merged 1 commit into
mainfrom
copilot/fix-emulator-boot-error

Conversation

CopilotAI commented May 7, 2026

Copy link
Copy Markdown
Contributor

BootEmulatorAsync crashes with InvalidOperationException: No process is associated with this object when accessing Process.HasExited/Process.ExitCode on a broken emulator process. Instead of propagating an unhandled exception, return a structured EmulatorBootResult error.

Changes

  • LaunchEmulator: Check Process.Start() return value; dispose and throw if false
  • BootEmulatorAsync polling loop: Wrap HasExited/ExitCode access in try-catch for InvalidOperationException, returning a LaunchFailed result with a diagnostic message
  • BootEmulatorAsync process lifetime: Use using (emulatorProcess) block for automatic disposal instead of manual Dispose() calls scattered across every exit path
  • TryKillProcess: Remove finally Dispose since the using block handles disposal
  • New test: InvalidEmulatorBinary_ReturnsLaunchFailed -- creates a script that exits immediately with code 1, asserts LaunchFailed result

CopilotAI linked an issue May 7, 2026 that may be closed by this pull request
CopilotAI changed the title [WIP] Fix error when booting an emulatorHandle InvalidOperationException when emulator process has no associated OS processMay 7, 2026
CopilotAI requested a review from jonathanpeppersMay 7, 2026 13:44
Comment threadsrc/Xamarin.Android.Tools.AndroidSdk/Runners/EmulatorRunner.cs Outdated
Comment threadsrc/Xamarin.Android.Tools.AndroidSdk/Runners/EmulatorRunner.cs Outdated
CopilotAI requested a review from jonathanpeppersMay 7, 2026 14:25
@jonathanpeppers
jonathanpeppersforce-pushed the copilot/fix-emulator-boot-error branch from d805a07 to b3ad031CompareMay 7, 2026 14:34
@jonathanpeppers
jonathanpeppers marked this pull request as ready for review May 7, 2026 14:34
CopilotAI review requested due to automatic review settings May 7, 2026 14:34
@jonathanpeppersjonathanpeppers changed the title Handle InvalidOperationException when emulator process has no associated OS processHandle InvalidOperationException in emulator boot and improve Process disposalMay 7, 2026
Comment on lines 283 to 291
void TryKillProcess (Process process)
{
try {
process.Kill ();
} catch (Exception ex) {
// Best-effort: process may have already exited
logger.Invoke (TraceLevel.Verbose, $"Failed to stop emulator process: {ex.Message}");
} finally {
process.Dispose ();
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TryKillProcess no longer needs this, because of the outer using block.

@jonathanpeppers
jonathanpeppers self-requested a review May 7, 2026 14:38
@jonathanpeppers

Copy link
Copy Markdown
Member

/review

@github-actions

github-actionsBot commented May 7, 2026

Copy link
Copy Markdown

Android Tools PR Reviewer completed successfully!

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens EmulatorRunner.BootEmulatorAsync in Xamarin.Android.Tools.AndroidSdk to avoid crashing when the launched emulator Process object is in an invalid state (e.g., InvalidOperationException when reading HasExited/ExitCode), returning a structured EmulatorBootResult failure instead.

Changes:

  • Validate emulator launch by checking Process.Start() return value and converting failure into a LaunchFailed flow.
  • Guard the boot polling loop against InvalidOperationException from Process.HasExited/ExitCode, returning LaunchFailed with diagnostics.
  • Add a test covering an emulator binary that exits immediately and should result in LaunchFailed.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
tests/Xamarin.Android.Tools.AndroidSdk-Tests/EmulatorRunnerTests.csAdds a regression test asserting immediate emulator exit maps to LaunchFailed with a useful message.
src/Xamarin.Android.Tools.AndroidSdk/Runners/EmulatorRunner.csAdds Process.Start() return-value handling, wraps HasExited/ExitCode access to prevent InvalidOperationException crashes, and relies on using for Process disposal.

@jonathanpeppers
jonathanpeppersforce-pushed the copilot/fix-emulator-boot-error branch from b3ad031 to 5f9b0a6CompareMay 7, 2026 14:40
…ted OS process
- Check Process.Start() return value in LaunchEmulator
- Guard HasExited/ExitCode access with try-catch for InvalidOperationException
- Use `using (emulatorProcess)` block for automatic disposal instead of manual
Dispose() calls scattered across every exit path
- Remove Dispose() from TryKillProcess since the using block handles it
- Add InvalidEmulatorBinary_ReturnsLaunchFailed test: script that exits with
code 1 asserts LaunchFailed result with diagnostic message
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppersforce-pushed the copilot/fix-emulator-boot-error branch from 5f9b0a6 to 78ee58fCompareMay 7, 2026 14:41

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 ✅ LGTM — solid defensive fix

Summary: This PR correctly addresses an InvalidOperationException crash in BootEmulatorAsync by guarding HasExited/ExitCode access, improving Process lifetime management with a using block, and checking the Process.Start() return value.

What's good:

  • The using (emulatorProcess) pattern is a clear improvement over scattered Dispose() calls — it guarantees cleanup in all paths including unexpected exceptions.
  • The InvalidOperationException catch returns a structured EmulatorBootResult error instead of propagating an unhandled exception — good for callers.
  • The Process.Start() return value check in LaunchEmulator is proper defensive programming.
  • CancellationToken is correctly propagated to all downstream async calls.
  • The TryKillProcess + using interaction is correct: Kill() is called inside the block, then Dispose() runs on block exit.

Minor observations:

  • 💡 ×1 — positive callout on using pattern
  • 💡 ×1 — test coverage note (see inline)

CI note: Only license/cla completed; no build/test checks are visible. The changes are straightforward, but it would be good to confirm tests pass before merge.

Issues by severity: 0 ❌ · 0 ⚠️ · 2 💡

Generated by Android Tools PR Reviewer for issue #359 · ● 1.7M

@jonathanpeppersjonathanpeppers added the ready-to-review This PR is ready to review/merge. label May 7, 2026
@simonrozsival
simonrozsival merged commit 482a9bb into mainMay 8, 2026
2 checks passed
@simonrozsival
simonrozsival deleted the copilot/fix-emulator-boot-error branch May 8, 2026 09:30
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error when booting an emulator

4 participants

@jonathanpeppers@simonrozsival