Skip to content

[Xamarin.Android.Build.Tasks] Fix _CreateAar race under parallel build#11527

Draft
jonathanpeppers wants to merge 4 commits into
mainfrom
jonathanpeppers/aar-race-xarlp7024
Draft

[Xamarin.Android.Build.Tasks] Fix _CreateAar race under parallel build#11527
jonathanpeppers wants to merge 4 commits into
mainfrom
jonathanpeppers/aar-race-xarlp7024

Conversation

@jonathanpeppers
Copy link
Copy Markdown
Member

Fixes: #11514

Why

Under parallel build (-m), library projects with <GeneratePackageOnBuild>true</GeneratePackageOnBuild> can intermittently fail with:

error XARLP7024: System.IO.IOException: The process cannot access the file
'.../<assembly>.aar' because it is being used by another process.
   at Microsoft.Android.Build.Tasks.Files.HashFile(...)
   at Xamarin.Android.Tasks.ResolveLibraryProjectImports.Extract(...)

The reporter's mini.binlog shows _CreateAar running in two distinct project instances of the same library csproj, and a local repro shows it running three times for a single dotnet build:

  • Once from BuildDependsOn.
  • Once from _UpdateAndroidResourcesDependsOn on the regular Build chain.
  • Once more from _UpdateAndroidResourcesDependsOn on a Pack-dispatched project instance entered via _GetFrameworkAssemblyReferences (NuGet pack's per-TFM inner-target dispatch). That instance has different global properties, so MSBuild does not dedupe it and may run it on a fresh worker node, opening a write/write or write/read race against consumers that read the .aar via Files.HashFile.

Approach

_UpdateAndroidResources is the aapt2/resource-designer step; producing the publish artifact (.aar) is unrelated. Remove _CreateAar from _UpdateAndroidResourcesDependsOn. The AAR is still produced because _CreateAar remains in BuildDependsOn for non-application projects, and Pack depends on Build, so dotnet build and dotnet pack both still create it.

This collapses the count to a single invocation per build, eliminating the race window and the redundant AAR rewrites at the root rather than papering over them with reader retries or atomic writes.

Test

Added IncrementalBuildTest.CreateAarRunsOnceWithGeneratePackageOnBuild: builds a library with GeneratePackageOnBuild=true at LoggerVerbosity.Detailed and asserts Target "_CreateAar" in file ... appears exactly once in the build log.

Verified against the issue's repro project: count drops from 3 to 1 with the fix.

Fixes: #11514

Under parallel build (`-m`), library projects with
`<GeneratePackageOnBuild>true</GeneratePackageOnBuild>` could fail with:

    error XARLP7024: System.IO.IOException: The process cannot access the file
    '.../<assembly>.aar' because it is being used by another process.
       at Microsoft.Android.Build.Tasks.Files.HashFile(...)
       at Xamarin.Android.Tasks.ResolveLibraryProjectImports.Extract(...)

`_CreateAar` was being scheduled up to *three* times for a single library
build, on two distinct MSBuild project instances:

  * Once from `BuildDependsOn`.
  * Once from `_UpdateAndroidResourcesDependsOn` on the regular `Build` chain.
  * Once more from `_UpdateAndroidResourcesDependsOn` on a Pack-dispatched
    project instance entered via `_GetFrameworkAssemblyReferences`. Because
    that instance has different global properties (NuGet pack's per-TFM
    inner-target dispatch), MSBuild does not dedupe it and may run it on a
    fresh worker node, opening a write/write or write/read race against
    consumers that read the `.aar` via `Files.HashFile`.

`_UpdateAndroidResources` is the aapt2/resource-designer step; producing
the publish artifact (`.aar`) is unrelated. The AAR is still produced
because `_CreateAar` remains in `BuildDependsOn` for non-application
projects, and Pack depends on `Build`, so a normal build and `dotnet pack`
both still create it.

Removing `_CreateAar` from `_UpdateAndroidResourcesDependsOn` collapses
the count to a single invocation per build, eliminating the race window
and the redundant AAR rewrites.

Added a regression test in `IncrementalBuildTest` that builds a library
with `GeneratePackageOnBuild=true` at `LoggerVerbosity.Detailed` and
asserts that `Target "_CreateAar" in file ...` appears exactly once in
the build log. Verified against the repro project on the issue: the
count drops from 3 to 1 with the fix applied.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 28, 2026 13:46
Copy link
Copy Markdown
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

Removes _CreateAar from _UpdateAndroidResourcesDependsOn to prevent it from being invoked multiple times during a single build (notably via NuGet pack's per-TFM inner-target dispatch), which was causing a write/read race on the .aar file under parallel builds (XARLP7024). _CreateAar is still wired through BuildDependsOn for non-application projects, so dotnet build and dotnet pack continue to produce the AAR.

Changes:

  • Remove _CreateAar from _UpdateAndroidResourcesDependsOn in Microsoft.Android.Sdk.BuildOrder.targets.
  • Add IncrementalBuildTest.CreateAarRunsOnceWithGeneratePackageOnBuild asserting _CreateAar runs exactly once when GeneratePackageOnBuild=true.

Reviewed changes

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

File Description
src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets Drops _CreateAar from the resource-update dependency chain to eliminate redundant invocations and the race window.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs New regression test verifying _CreateAar executes exactly once for a library with GeneratePackageOnBuild=true.

@jonathanpeppers jonathanpeppers marked this pull request as draft May 28, 2026 16:11
jonathanpeppers and others added 3 commits May 28, 2026 11:22
The `CreateAar` task writes each item in `@(JarFiles)` into the
output `.aar` archive at `libs/<hash>.jar`. Today nothing protects
against the same archive path being written twice: e.g.
`_CompileBindingJava` adds the binding classes zip to both
`@(EmbeddedJar)` and `@(AndroidJavaLibrary)`, and the input groups
can otherwise accumulate duplicates across target invocations. Calling
`aar.AddStream` repeatedly with the same path produces multiple zip
entries with identical names, which the `DotNetPack` test now
catches as `found 3` jars where only 2 unique paths exist.

Track archive paths in a `HashSet<string>` and skip duplicates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…n _CreateAar

After removing _CreateAar from _UpdateAndroidResourcesDependsOn (to fix the
parallel-build race in #11514), the DotNetPack test started failing because
the .aar inside the .nupkg contained an extra .jar.

Previously, dotnet pack''s inner _GetFrameworkAssemblyReferences evaluation
implicitly re-ran _CreateAar through the resource chain (see #10270). In
that inner evaluation _CompileBindingJava had not run, so the binding
classes zip was not in @(EmbeddedJar)/@(AndroidJavaLibrary), and the
resulting .aar (which overwrote the outer Build evaluation''s .aar) did
not contain it. The .nupkg picked up that smaller .aar.

Removing _CreateAar from the resource chain eliminated that overwrite, so
the outer Build evaluation''s .aar (with the binding zip included in both
EmbeddedJar and AndroidJavaLibrary) ended up in the .nupkg.

Make _IncludeAarInNuGetPackage explicitly depend on _CreateAar so the
inner per-TFM Pack evaluation still produces the .aar layout intended for
the .nupkg, without relying on the resource-chain side effect that caused
the original race.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AAR write/read race under parallel build (XARLP7024)

2 participants