Skip to content

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

Merged
simonrozsival merged 5 commits into
mainfrom
jonathanpeppers/aar-race-xarlp7024
Jun 2, 2026
Merged

[Xamarin.Android.Build.Tasks] Fix _CreateAar race under parallel build#11527
simonrozsival merged 5 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

Copilot AI 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

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).

@xen2

xen2 commented Jun 2, 2026

Copy link
Copy Markdown

FYI I tried a workaround that does the same thing in the meantime (by adjusting _UpdateAndroidResourcesDependsOn and _IncludeAarInNuGetPackageDependsOn), it seems to works well!

@jonathanpeppers

Copy link
Copy Markdown
Member Author

FYI I tried a workaround that does the same thing in the meantime (by adjusting _UpdateAndroidResourcesDependsOn and _IncludeAarInNuGetPackageDependsOn), it seems to works well!

Ok, great. The test isn't working, but when that's fixed we can get this merged, thanks!

CI showed CreateAarRunsOnceWithGeneratePackageOnBuild failing with count=2.
The binlog shows _CreateAar enters two project evaluations:

* `Build` evaluation (project 71): runs completely, 39ms.
* `_GetTfmSpecificContentForPackage` evaluation (project 91): entered, then
  immediately skipped with "Skipping target _CreateAar because it has no
  inputs. ... only references empty properties and/or empty item lists."

The race in #11514 is on the actual file write, so what the test really
needs to assert is "only one execution wrote the .aar." Counting "Target X
in file" lines is too strict because MSBuild logs that line on entry, even
for entries that are skipped due to empty Inputs. Switch to
"Building target X completely", which is only emitted when MSBuild has
decided the target will actually run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers
jonathanpeppers marked this pull request as ready for review June 2, 2026 14:53
@jonathanpeppers

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jonathanpeppers jonathanpeppers added the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label Jun 2, 2026
@simonrozsival
simonrozsival merged commit f8abfa0 into main Jun 2, 2026
3 checks passed
@simonrozsival
simonrozsival deleted the jonathanpeppers/aar-race-xarlp7024 branch June 2, 2026 21:46
jonathanpeppers added a commit that referenced this pull request Jun 3, 2026
#11527)

Fixes: #11514

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`.

`_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.

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.
simonrozsival pushed a commit that referenced this pull request Jun 8, 2026
#11527) (#11570)

Backport of #11527 to `release/10.0.1xx`.

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(...)
```

`_CreateAar` was running multiple 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.

### Conflicts

Minor merge conflict in `IncrementalBuildTest.cs` because `ManifestMergerIncremental` on `release/10.0.1xx` doesn't take the `[Values] AndroidRuntime runtime` parameter that exists on `main`. Resolved by adding the new test before the existing `ManifestMergerIncremental ()` signature.
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AAR write/read race under parallel build (XARLP7024)

4 participants