Skip to content

Add base Android tool runner infrastructure#281

Closed
rmarinho wants to merge 1 commit intomainfrom
feature/tool-runner-base
Closed

Add base Android tool runner infrastructure#281
rmarinho wants to merge 1 commit intomainfrom
feature/tool-runner-base

Conversation

@rmarinho
Copy link
Member

Summary

Adds base infrastructure for running Android SDK command-line tools programmatically.

New Classes

  • AndroidToolRunner: Base class for executing Android SDK CLI tools with:

    • Sync/async execution with timeout support
    • Background process management
    • stdout/stderr capture
    • Environment variable configuration
    • netstandard2.0 compatible process handling
  • AndroidEnvironmentHelper: Utilities for:

    • Setting up JAVA_HOME, ANDROID_HOME environment
    • PATH configuration for SDK tools
    • ABI mapping (arm64-v8a ↔ aarch64, etc.)
  • ToolRunnerResult: Generic result model for tool execution

Design Decisions

  • Instance methods for testability and dependency injection
  • Timeout support with graceful cancellation
  • netstandard2.0 compatibility (Process.Kill(true) workaround)
  • Consistent with existing repo patterns

Downstream Usage

This is the foundation for:

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Copy link
Contributor

Copilot AI left a comment

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 adds foundational infrastructure for running Android SDK command-line tools programmatically. It introduces three new classes that provide a consistent way to execute Android tools with features like timeout support, output capture, and environment configuration. This is designed as the base layer for higher-level tool wrappers like AvdManagerRunner, EmulatorRunner, and AdbRunner (mentioned issues #277-#279).

Changes:

  • Added AndroidToolRunner class with synchronous/asynchronous process execution, timeout handling, and background process support
  • Added AndroidEnvironmentHelper utilities for environment variable setup and Android-specific mappings (ABI, API levels, system image tags)
  • Added ToolRunnerResult model classes for standardized tool execution results

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 11 comments.

File Description
src/Xamarin.Android.Tools.AndroidSdk/Runners/AndroidToolRunner.cs Core process execution infrastructure with sync/async methods, timeout support, and platform-specific handling for netstandard2.0
src/Xamarin.Android.Tools.AndroidSdk/Runners/AndroidEnvironmentHelper.cs Helper utilities for environment setup (JAVA_HOME, ANDROID_HOME) and Android-specific mappings
src/Xamarin.Android.Tools.AndroidSdk/Models/ToolRunnerResult.cs Result model classes for process execution, with generic variant for typed data

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return null;

return apiLevel switch {
"36" => "16.0",
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The API level mapping includes "36" mapping to "16.0", but as of the knowledge cutoff in January 2025, Android API level 36 has not been officially released. This may be speculative or based on preview information. Consider verifying this mapping or documenting that it's preliminary.

Suggested change
"36" => "16.0",

Copilot uses AI. Check for mistakes.

if (!string.IsNullOrEmpty (jdkPath)) {
env ["JAVA_HOME"] = jdkPath;
env ["PATH"] = Path.Combine (jdkPath, "bin") + Path.PathSeparator + Environment.GetEnvironmentVariable ("PATH");
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The PATH environment variable construction has a potential null reference issue. If Environment.GetEnvironmentVariable("PATH") returns null, string concatenation will work but could produce unexpected behavior. Consider handling null explicitly or using string interpolation with null coalescing.

Suggested change
env ["PATH"] = Path.Combine (jdkPath, "bin") + Path.PathSeparator + Environment.GetEnvironmentVariable ("PATH");
var currentPath = Environment.GetEnvironmentVariable ("PATH");
env ["PATH"] = string.IsNullOrEmpty (currentPath)
? Path.Combine (jdkPath, "bin")
: Path.Combine (jdkPath, "bin") + Path.PathSeparator + currentPath;

Copilot uses AI. Check for mistakes.
@rmarinho rmarinho added the copilot `copilot-cli` or other AIs were used to author this label Feb 23, 2026
rmarinho added a commit that referenced this pull request Feb 24, 2026
Addresses PR #281 feedback from @jonathanpeppers to use the existing
ProcessUtils.cs instead of the new AndroidToolRunner.cs which was
inventing code that just wraps System.Diagnostics.Process.

Changes:
- Extended ProcessUtils with RunToolAsync() and StartToolBackground()
  methods that leverage the existing StartProcess() implementation
- Added GetExecutableExtension() and GetBatchExtension() utilities
- Updated AvdManagerRunner, AdbRunner, and EmulatorRunner to use
  ProcessUtils methods instead of AndroidToolRunner
- Removed AndroidToolRunner.cs as it is no longer needed
- Kept ToolRunnerResult as it provides a useful structured result type

The new methods build on top of the existing ProcessUtils.StartProcess()
method rather than duplicating its process management logic.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
rmarinho added a commit that referenced this pull request Feb 24, 2026
Addresses PR #281 feedback from @jonathanpeppers:
> 'This is inventing lots of new code that just wraps
> System.Diagnostics.Process. Can we just use the existing code
> for this instead? ProcessUtils.cs'

Changes:
- Extended ProcessUtils with RunToolAsync() and StartToolBackground()
- Added GetExecutableExtension() and GetBatchExtension() utilities
- Removed AndroidToolRunner.cs (-347 lines)
- Removed ToolRunnerResult.cs (-74 lines)

The new methods leverage the existing StartProcess() implementation
which already handles cancellation, output redirection, and process
lifecycle correctly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@rmarinho rmarinho requested a review from Copilot February 24, 2026 14:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 240 to 243
if (environmentVariables != null) {
foreach (var kvp in environmentVariables)
psi.Environment [kvp.Key] = kvp.Value;
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

ProcessStartInfo.Environment is used to set environment variables, but this project targets netstandard2.0 and the more widely supported API there is ProcessStartInfo.EnvironmentVariables. As-is, this risks failing to compile for the netstandard2.0 target. Consider using EnvironmentVariables (or conditional compilation for newer TFMs) to keep the netstandard2.0 build working.

Copilot uses AI. Check for mistakes.
Comment on lines 225 to 226
var stdout = new StringWriter ();
var stderr = new StringWriter ();
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

RunToolAsync allocates StringWriter instances for stdout/stderr but never disposes them. While the impact is small, this is inconsistent with ExecuteToolAsync above (which disposes its writers) and makes resource ownership less clear. Prefer using var/try/finally to ensure writers are disposed after StartProcess completes (including on exceptions).

Suggested change
var stdout = new StringWriter ();
var stderr = new StringWriter ();
using var stdout = new StringWriter ();
using var stderr = new StringWriter ();

Copilot uses AI. Check for mistakes.
- GetToolEnvironment(): Set ANDROID_HOME, JAVA_HOME, and PATH

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@rmarinho rmarinho force-pushed the feature/tool-runner-base branch from 4e7c281 to dc73056 Compare February 24, 2026 15:01
@rmarinho
Copy link
Member Author

Closing this PR as the original AndroidToolRunner approach was replaced with using the existing ProcessUtils.cs per @jonathanpeppers feedback. The AndroidEnvironmentHelper can be included directly in the runner PRs that need it.

@rmarinho rmarinho closed this Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

copilot `copilot-cli` or other AIs were used to author this

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants