[androidsdk] Fix SDK extraction incrementality#11756
Conversation
Refresh the extracted source.properties sentinel after unzip so MSBuild sees SDK package extraction outputs as newer than the cached zip inputs. Guard Unix staging item inference for skipped targets, and make generated package.xml outputs incremental only for packages that synthesize them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR improves incremental behavior in the androidsdk build targets so repeated builds correctly skip SDK extraction and related steps when nothing changed, avoiding unnecessary work and fixing cases where preserved mtimes prevented MSBuild’s Inputs/Outputs logic from considering packages up-to-date.
Changes:
- Refreshes extracted
source.propertiestimestamps after unzip to ensure MSBuild incremental outputs behave correctly on subsequent builds. - Adds guards to Unix staging directory inference so item globbing doesn’t misbehave when extraction is skipped/doesn’t produce expected staging content.
- Makes
package.xmlgeneration incremental only for SDK packages that actually synthesizepackage.xml(viaGeneratePackageXml=truemetadata).
Show a summary per file
| File | Description |
|---|---|
| src/androidsdk/androidsdk.targets | Fixes _ExtractAndroidSdkPackages sentinel freshness, hardens Unix staging inference, and scopes incremental package.xml generation to only the packages that generate it. |
Copilot's findings
- Files reviewed: 1/1 changed files
- Comments generated: 0
|
/review |
|
✅ Android PR Reviewer completed successfully! |
There was a problem hiding this comment.
🤖 Android PR Reviewer
Verdict: ✅ Looks good — a well-reasoned, well-documented incremental-build fix. Two optional 💡 nits inline; nothing blocking.
What the PR does
- Touches the extracted
source.propertiesafter each package extraction so MSBuild'sOutputssentinel is newer than the cached-zipInputs.unzippreserves old archive mtimes, which previously left the output older than the input and re-extracted every package on every build. - Adds a fail-fast
<Error>if extraction didn't producesource.properties. - Guards the
.stagingenumeration (Exists(...)) and the staged-file glob (_GlobRoot != '') so output inference of the now-skippable target can't enumerate a missing directory or glob from filesystem root. - Splits
package.xmlitem filtering into_AddGeneratedPackageXmls, so_GenerateAndroidPackageXmlsdeclaresInputs/Outputsonly for packages that actually emit apackage.xml— fixing a target that ran every build.
Verification notes
- ✅ Traced the
<Touch>against both downstream consumers ofsource.propertiesmtime —_GenerateAndroidPackageXmlsand_CopyNdkRedistributables(Inputs="$(AndroidNdkDirectory)\source.properties"). Both re-run once after the initial re-extraction, then settle to skipped. No re-trigger loop. - ✅ The new
<Error>only hardens an assumption the existingOutputsalready made (every package emitssource.properties), so it won't introduce spurious failures for the current package set; it converts a silent "always rebuild" into a loud failure if that ever breaks. - ✅ The
'$(_GlobRoot)' != ''guard correctly prevents the catastrophicInclude="\**\*"root-glob when_StagedTopDiris empty during output inference. - ✅
_GeneratedPackageXmlis always non-empty (the active emulator variant hasGeneratePackageXml=true), so the refactoredInputs/Outputsstay well-formed.
Suggestions (optional)
- 💡 Reuse the already-computed
$(_DestDir)in the new<Touch>/<Error>for consistency with the rest of the body. - 💡
_AddGeneratedPackageXmlscould be aDependsOnTargetsof its single consumer rather than aBeforeTargets, matching the repo convention.
CI
The Azure DevOps build (Linux / Windows / Mac) was still in progress at review time — please confirm it goes green before merge.
Generated by Android PR Reviewer for issue #11756 · 628.2 AIC · ⌖ 46.1 AIC · ⊞ 40K
Comment /review to run again
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Addressed both suggestions in 7f44b6c:
|
Summary
This fixes
src/androidsdk/androidsdk.csprojbeing slow on repeated builds by making the SDK extraction targets genuinely incremental.The important change is that after extracting each Android SDK/NDK archive, we now refresh the extracted
source.propertiesfile that MSBuild uses as the target output. That lets later builds see the extraction output as newer than the cached archive input and skip the expensive unzip/delete/recreate work.What was happening before
_DownloadAndroidSdkPackageswas not the main problem: the archives were already cached under$(AndroidToolchainCacheDirectory)/~/android-archives, and the sharedDownloadFileWithRetry.targetsstamp files meant the download/hash-validation work was normally skipped.The slow part was
_ExtractAndroidSdkPackages. It is batched per package and declares:That looks correct at first: cached zip in, extracted
source.propertiesout. The problem is thatunzippreserves timestamps from the zip entries. Many Android SDK zips contain very old file mtimes, for examplesource.propertiesdated 2008, 2010, 2024, or 2025, while the cached zip file in~/android-archiveshas the time it was downloaded/restored.So after a successful extraction, MSBuild still saw:
That made
_ExtractAndroidSdkPackagesout-of-date on every build. Each repeated build deleted the existing SDK/NDK destination, recreated a staging directory, and unzipped/moved the package contents again. On my machine this showed up as_ExtractAndroidSdkPackagestaking about 205s on an otherwise repeated build.Why this works now
After extraction completes, the target verifies that the expected
source.propertiesexists and then touches it:That does not modify package contents semantically; it only updates the incremental-build sentinel that this target already chose as its output. On the next build, the output timestamp is newer than the cached zip input, so MSBuild can correctly skip the batch instead of re-extracting the package.
Making extraction actually skippable exposed two related incremental-build issues, both fixed here:
.stagingdirectory while MSBuild was doing skipped-target output inference. Once extraction is skipped, that staging directory correctly does not exist, so the target now guards the staging directory enumeration and staged-file glob._GenerateAndroidPackageXmlsdeclaredpackage.xmloutputs for every SDK package, but only packages withGeneratePackageXml=truesynthesize one. For packages that never producepackage.xml, the target was permanently missing outputs and ran every build. It now builds a filtered_GeneratedPackageXmlitem list and makes the incremental Inputs/Outputs apply only to those packages.Validation
Ran repeated builds of the standalone project:
After the one expected re-extraction to refresh sentinels, the steady-state diagnostic build shows: