Fix emulator boot and deploy flow for dotnet run#10969
Fix emulator boot and deploy flow for dotnet run#10969
dotnet run#10969Conversation
jonathanpeppers
left a comment
There was a problem hiding this comment.
The problem on the description sounds like:
Which should be in main, if you have at least:
There was a problem hiding this comment.
Pull request overview
Fixes dotnet run --project <app>.csproj deploy failures when the selected Android emulator is stopped by ensuring the emulator-boot target runs via DependsOnTargets, and improving emulator detection/boot polling in the BootAndroidEmulator MSBuild task.
Changes:
- Add
_EnsureDeviceBootedintoDeployToDeviceDependsOnTargetsand_AndroidComputeRunArgumentsDependsOnso it runs reliably during in-procProjectInstance.Build(["DeployToDevice"]). - Improve AVD name detection by preferring
adb shell getprop ro.boot.qemu.avd_name, with fallback toadb emu avd name. - Handle macOS emulator launcher “fork then exit 0” behavior by continuing to poll
adb deviceson exit code 0. - Add a unit test asserting
_EnsureDeviceBootedis included inDeployToDeviceDependsOnTargets.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Application.targets | Ensures _EnsureDeviceBooted participates in run-argument computation and clarifies execution rationale. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets | Adds _EnsureDeviceBooted to deploy dependency chains (fast deploy + non-fast deploy). |
| src/Xamarin.Android.Build.Tasks/Tasks/BootAndroidEmulator.cs | Updates AVD name detection and improves macOS emulator process exit handling. |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildOrderTests.cs | Adds coverage to validate deploy dependency chain includes _EnsureDeviceBooted. |
You can also share your feedback on Copilot code review. Take the survey.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildOrderTests.cs
Outdated
Show resolved
Hide resolved
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildOrderTests.cs
Outdated
Show resolved
Hide resolved
aa3f844 to
d188a4b
Compare
62a458e to
a2787ca
Compare
Address multiple issues preventing 'dotnet run --project' from successfully booting an Android emulator and deploying the app. Fixes: #10965 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The dotnet/sdk fix (dotnet/sdk#53018) now properly passes the Device global property to DeployToDevice via InvalidateGlobalProperties. Remove the device.props write/read cache that was working around this. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The DeployToDeviceDependsOnTargets property expands to multiple log lines because it includes $(_MinimalSignAndroidPackageDependsOn). The test was only checking the first line, which never contained _EnsureDeviceBooted. Switch to MSBuild property functions (Contains/IndexOf) to validate directly in MSBuild, avoiding log parsing entirely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the readable log-parsing approach (fixed by joining all output lines for multi-line property matching) and add a separate MSBuild property function test as a safety net. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The IndexOf check for _EnsureDeviceBooted vs _DeployApk was scanning the entire build output, not just the property value. _DeployApk appears as a target reference earlier in the log, causing a false positive failure. Ordering is already validated reliably by DeployToDeviceDependsOn_MSBuildValidation which checks the property value directly via MSBuild functions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
54bfb68 to
17d3f5f
Compare
jonathanpeppers
left a comment
There was a problem hiding this comment.
I'd rather this have a single end-to-end test that emulates the dotnet run pipeline:
dotnet builddotnet build --no-restore -t:DeployToDevice- Assert
DeployToDeviceran_EnsureDeviceBootedtarget - Assert the app is installed
You'll need to put this in tests/MSBuildDeviceIntegration, so you'll have access to a running emulator.
An emulator will already be booted, but that is OK. I think the bug here is that DeployToApk doesn't run _EnsureDeviceBooted.
Check there isn't an existing test that runs DeployToApk -- you could maybe update the existing test instead of adding new.
| [Test] | ||
| public void DeployToDeviceDependsOn_ContainsEnsureDeviceBooted () | ||
| { | ||
| // _EnsureDeviceBooted must be in DeployToDeviceDependsOnTargets so that it fires | ||
| // when the .NET SDK calls ProjectInstance.Build(["DeployToDevice"]) in-process, | ||
| // where BeforeTargets hooks are not reliably triggered. | ||
| var checkTargets = new Import (() => "CheckDeployOrder.targets") { | ||
| TextContent = () => """ | ||
| <Project> | ||
| <Target Name="_CheckDeployOrder"> | ||
| <Message Text="DeployToDeviceDependsOnTargets=$(DeployToDeviceDependsOnTargets)" Importance="high" /> | ||
| </Target> | ||
| </Project> | ||
| """ |
There was a problem hiding this comment.
This test is kind of pointless? It just checks a target named _EnsureDeviceBooted is in $(DeployToDeviceDependsOnTargets)?
That isn't really testing anything.
| using var builder = CreateApkBuilder (); | ||
| Assert.IsTrue (builder.RunTarget (proj, "_CheckDeployOrder"), | ||
| "Build should have succeeded — _EnsureDeviceBooted must be in DeployToDeviceDependsOnTargets before _DeployApk."); |
There was a problem hiding this comment.
Same with this test, it's not really testing anything. It just checks a target named _EnsureDeviceBooted is in a property.
Summary
Running
dotnet run --project <app>.csprojwith a stopped Android emulator fails to boot the emulator and deploy the app, producingadb: no devices/emulators foundoradb: device '<avd>' not founderrors.This PR fixes the MSBuild target ordering so
_EnsureDeviceBootedfires reliably duringdotnet rundeploy.Fixes #10965
Problem & Fix
_EnsureDeviceBootednot firing duringDeployToDeviceThe .NET SDK's
dotnet runinvokesDeployToDeviceviaProjectInstance.Build(["DeployToDevice"])in-process. In this execution mode,BeforeTargetshooks are not reliably triggered — onlyDependsOnTargetschains are respected.Fix: Add
_EnsureDeviceBootedtoDeployToDeviceDependsOnTargetsinBuildOrder.targets, and to_AndroidComputeRunArgumentsDependsOninApplication.targets, ensuring the emulator boots via the dependency chain during both the main build and the deploy step.Changes
Microsoft.Android.Sdk.Application.targets— Added_EnsureDeviceBootedto_AndroidComputeRunArgumentsDependsOn, simplifiedBeforeTargetsto just_GetPrimaryCpuAbi(commercial builds), updated commentsMicrosoft.Android.Sdk.BuildOrder.targets— Added_EnsureDeviceBootedto bothDeployToDeviceDependsOnTargetsvariants (fast-deploy and non-fast-deploy)BuildOrderTests.cs— AddedDeployToDeviceDependsOn_ContainsEnsureDeviceBootedtestTesting
DeployToDeviceDependsOn_ContainsEnsureDeviceBootedvalidates the target chain