Skip to content

[flaky-ci] Atomically replace Android SDK packages - #12767

Open
simonrozsival wants to merge 1 commit into
mainfrom
simonrozsival-flaky-ci-android-sdk-cleanup
Open

simonrozsival wants to merge 1 commit into
mainfrom
simonrozsival-flaky-ci-android-sdk-cleanup

Conversation

@simonrozsival

Copy link
Copy Markdown
Member

Summary

  • extract Android SDK/NDK packages into unique sibling staging directories and atomically replace the destination only after source.properties is present
  • preserve the hash-specific extraction stamp, so image-provided packages without the pinned archive/hash sentinel are still replaced rather than trusted implicitly
  • retry transient directory moves and old-tree cleanup with actionable diagnostics, clean failed staging directories, and retry stale backup cleanup on later incremental builds and Clean
  • add task-level coverage for stubborn cleanup, rollback, and validation plus target-level coverage for trailing separators, replacement, failed extraction cleanup, and incrementality

Root cause

Azure build 1592587, job MSBuild Emulator Tests macOS > Tests > MSBuild+Emulator 5, log 1032 reached _ExtractAndroidSdkPackages for the image-provided platforms/android-36.1. The hosted-image directory did not contain this repository's .extracted-<archive>-<hash> sentinel, so re-extracting the pinned archive was intentional. Target batching is per package and the package destinations are distinct; there is no parallel batch writing this destination.

The failure came from recursively deleting the live destination before the replacement archive was staged. RemoveDir partially removed the existing tree, then Directory.Delete reported data/res was still non-empty. The pipeline-level retries immediately retried the already-partially-deleted directory and failed again.

The new flow stages and validates the archive first, renames the old directory to a sibling backup, and atomically moves the staged directory into place. A transient or concurrently changing old tree can no longer prevent the pinned package from being committed. Genuine unzip, validation, or commit failures still fail and restore the previous destination when possible.

References #12704.

Validation

  • dotnet test tests/Microsoft.Android.Build.BaseTasks-Tests/Microsoft.Android.Build.BaseTasks-Tests.csproj -v minimal (132 passed, 4 skipped)
  • dotnet build build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks.csproj -v minimal
  • parsed the changed MSBuild XML and preprocessed src/androidsdk/androidsdk.csproj
  • git diff --check

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 11, 2026 16:21
@simonrozsival simonrozsival added the flaky-ci Intermittent CI failures and work to improve CI reliability label Sep 11, 2026

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.

Copilot review overview

🟡 Changes recommended

Unresolved cleanup and staged-directory validation bugs can cause failed builds or remove recoverable backups.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review tier: Lite
Findings: 1 High severity · 1 Medium severity

New issues introduced by this change (2)
Severity Finding
High severity src/​androidsdk/​androidsdk.targets — Do not delete rollback backups after extraction failures View comment
Medium severity src/​androidsdk/​androidsdk.targets — Validate the staged source before normalization View comment
What changed in this PR

Updates Android SDK/NDK extraction to stage validated packages before atomic replacement, with retries, rollback, and cleanup support.

Changes:

  • Adds directory replacement, retry, rollback, and backup cleanup tasks.
  • Updates extraction targets for staging, validation, stamps, and incrementality.
  • Adds task- and target-level test coverage.
File Description
tests/​Microsoft.Android.Build.BaseTasks-Tests/​Resources/​AndroidSdkTargetsTest.proj Test project configuration
tests/​Microsoft.Android.Build.BaseTasks-Tests/​ReplaceDirectoryTests.cs Replacement and rollback tests
tests/​Microsoft.Android.Build.BaseTasks-Tests/​Microsoft.Android.Build.BaseTasks-Tests.csproj Bootstrap task project reference
tests/​Microsoft.Android.Build.BaseTasks-Tests/​AndroidSdkTargetsTests.cs Extraction and incrementality tests
src/​androidsdk/​androidsdk.targets Staged extraction and cleanup orchestration
build-tools/​Xamarin.Android.Tools.BootstrapTasks/​Xamarin.Android.Tools.BootstrapTasks/​RetryingDirectoryTask.cs Shared retry and delete logic
build-tools/​Xamarin.Android.Tools.BootstrapTasks/​Xamarin.Android.Tools.BootstrapTasks/​ReplaceDirectory.cs Atomic replacement and rollback support
build-tools/​Xamarin.Android.Tools.BootstrapTasks/​Xamarin.Android.Tools.BootstrapTasks/​RemoveDirectoryBackups.cs Stale backup cleanup

</Target>

<Target Name="_CleanAndroidSdkPackageBackups"
AfterTargets="_ExtractAndroidSdkPackages"
Comment on lines +364 to 367
<PropertyGroup>
<_InstallSourceDir Condition=" '$(HostOS)' == 'Windows' Or '$(_StripComponents)' == '0' ">$(_StagingDir)</_InstallSourceDir>
<_InstallSourceDir Condition=" '$(HostOS)' != 'Windows' And '$(_StripComponents)' == '1' ">@(_StagedTopDir)</_InstallSourceDir>
</PropertyGroup>
Comment on lines +51 to +52
<UsingTask AssemblyFile="$(BootstrapTasksAssembly)" TaskName="Xamarin.Android.Tools.BootstrapTasks.ReplaceDirectory" TaskFactory="TaskHostFactory" Runtime="NET" />
<UsingTask AssemblyFile="$(BootstrapTasksAssembly)" TaskName="Xamarin.Android.Tools.BootstrapTasks.RemoveDirectoryBackups" TaskFactory="TaskHostFactory" Runtime="NET" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a way we could implement this without using two new MSBuild tasks? Can the built-in MSBuild ones work for this?

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

Labels

flaky-ci Intermittent CI failures and work to improve CI reliability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants