-
Notifications
You must be signed in to change notification settings - Fork 31
Add EmulatorRunner for emulator CLI operations #284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f5a820b
d976963
fa4ca63
863be74
9b53526
b998452
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,110 @@ | ||||||
| // Licensed to the .NET Foundation under one or more agreements. | ||||||
| // The .NET Foundation licenses this file to you under the MIT license. | ||||||
|
|
||||||
| using System; | ||||||
| using System.Collections.Generic; | ||||||
| using System.Diagnostics; | ||||||
| using System.IO; | ||||||
| using System.Threading; | ||||||
| using System.Threading.Tasks; | ||||||
|
|
||||||
| namespace Xamarin.Android.Tools | ||||||
| { | ||||||
| /// <summary> | ||||||
| /// Runs Android Emulator commands. | ||||||
| /// </summary> | ||||||
| public class EmulatorRunner | ||||||
| { | ||||||
| readonly Func<string?> getSdkPath; | ||||||
| readonly Func<string?>? getJdkPath; | ||||||
|
|
||||||
| public EmulatorRunner (Func<string?> getSdkPath) | ||||||
| : this (getSdkPath, null) | ||||||
| { | ||||||
| } | ||||||
|
|
||||||
| public EmulatorRunner (Func<string?> getSdkPath, Func<string?>? getJdkPath) | ||||||
| { | ||||||
| this.getSdkPath = getSdkPath ?? throw new ArgumentNullException (nameof (getSdkPath)); | ||||||
| this.getJdkPath = getJdkPath; | ||||||
| } | ||||||
|
|
||||||
| public string? EmulatorPath { | ||||||
| get { | ||||||
| var sdkPath = getSdkPath (); | ||||||
| if (string.IsNullOrEmpty (sdkPath)) | ||||||
| return null; | ||||||
|
|
||||||
| var ext = OS.IsWindows ? ".exe" : ""; | ||||||
| var path = Path.Combine (sdkPath, "emulator", "emulator" + ext); | ||||||
|
|
||||||
| return File.Exists (path) ? path : null; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| public bool IsAvailable => EmulatorPath is not null; | ||||||
|
|
||||||
| void ConfigureEnvironment (ProcessStartInfo psi) | ||||||
| { | ||||||
| var sdkPath = getSdkPath (); | ||||||
| if (!string.IsNullOrEmpty (sdkPath)) | ||||||
| psi.EnvironmentVariables ["ANDROID_HOME"] = sdkPath; | ||||||
|
|
||||||
| var jdkPath = getJdkPath?.Invoke (); | ||||||
| if (!string.IsNullOrEmpty (jdkPath)) | ||||||
| psi.EnvironmentVariables ["JAVA_HOME"] = jdkPath; | ||||||
| } | ||||||
|
|
||||||
| public Process StartAvd (string avdName, bool coldBoot = false, string? additionalArgs = null) | ||||||
| { | ||||||
| if (!IsAvailable) | ||||||
| throw new InvalidOperationException ("Android Emulator not found."); | ||||||
|
|
||||||
| var args = $"-avd \"{avdName}\""; | ||||||
| if (coldBoot) | ||||||
| args += " -no-snapshot-load"; | ||||||
| if (!string.IsNullOrEmpty (additionalArgs)) | ||||||
| args += " " + additionalArgs; | ||||||
|
Comment on lines
+63
to
+67
|
||||||
|
|
||||||
| var psi = new ProcessStartInfo { | ||||||
| FileName = EmulatorPath!, | ||||||
| Arguments = args, | ||||||
| UseShellExecute = false, | ||||||
| CreateNoWindow = true | ||||||
| }; | ||||||
| ConfigureEnvironment (psi); | ||||||
|
|
||||||
| var process = new Process { StartInfo = psi }; | ||||||
| process.Start (); | ||||||
|
|
||||||
| return process; | ||||||
| } | ||||||
|
|
||||||
| public async Task<List<string>> ListAvdNamesAsync (CancellationToken cancellationToken = default) | ||||||
|
||||||
| public async Task<List<string>> ListAvdNamesAsync (CancellationToken cancellationToken = default) | |
| public async Task<IReadOnlyList<string>> ListAvdNamesAsync (CancellationToken cancellationToken = default) |
Copilot
AI
Feb 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ListAvdNamesAsync allocates a StringWriter for stdout but never disposes it. Use a using/using var to dispose the writer (and to keep the pattern consistent with other code that disposes disposable resources).
| var stdout = new StringWriter (); | |
| using var stdout = new StringWriter (); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR description/New API lists StartEmulator/StartEmulatorAsync, WaitForBootAsync, and ListRunningEmulatorsAsync, but this class currently only implements StartAvd and ListAvdNamesAsync (and the signature differs). Either update the implementation to match the proposed API surface or adjust the PR description/issue link expectations so consumers aren’t broken/misled.