[TrimmableTypeMap] Merge library .aar manifests on the legacy merger path#12000
Conversation
…path The trimmable manifest generator (ManifestGenerator) already had the library manifest merge logic (MergeLibraryManifests + FixupNameElements + placeholder substitution), but it was never fed the extracted library (.aar) AndroidManifest.xml files, so on the legacy manifest-merger path the app manifest was missing library-declared permissions/activities/providers. The manifestmerger.jar path was unaffected (it merges downstream in _ManifestMerger). Wire @(ExtractedManifestDocuments) through: _GenerateTrimmableTypeMap (depends on _GetLibraryImports; adds the docs to Inputs) -> GenerateTrimmableTypeMap.MergedManifestDocuments -> ManifestConfig.LibraryManifests -> ManifestGenerator.LibraryManifests. Also surface merge failures via a new XA4302 logger warning (LogLibraryManifestMergeWarning), matching the legacy ManifestDocument path. Fixes ManifestTest.MergeLibraryManifest on the trimmable/NativeAOT path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes missing .aar-provided manifest content (permissions/activities/providers/meta-data, etc.) when using the trimmable typemap path together with AndroidManifestMerger=legacy, by ensuring extracted library manifests are passed into the trimmable manifest generator and merged there (matching the behavior that manifestmerger.jar already provides downstream).
Changes:
- Wire
@(ExtractedManifestDocuments)intoGenerateTrimmableTypeMapand down intoManifestGenerator.LibraryManifests(legacy merger path only). - Add XA4302-based warning plumbing for library-manifest merge failures via
ITrimmableTypeMapLogger.LogLibraryManifestMergeWarning. - Add unit tests validating
${applicationId}substitution, relative name qualification, duplicate element de-dupe, and missing file handling.
Show a summary per file
| File | Description |
|---|---|
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TrimmableTypeMapGeneratorTests.cs | Extend test logger interface implementation for the new merge-warning callback. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/ManifestGeneratorTests.cs | Add coverage for library manifest merging behaviors (placeholders, relative names, de-dupe, missing file). |
| src/Xamarin.Android.Build.Tasks/Tasks/GenerateTrimmableTypeMap.cs | Add task parameter for merged library manifests and pass through into ManifestConfig. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets | Ensure _GenerateTrimmableTypeMap runs with library imports available and passes extracted manifests on legacy path. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/TrimmableTypeMapTypes.cs | Extend ManifestConfig to carry library manifest paths. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/TrimmableTypeMapGenerator.cs | Feed library manifests + warning handler into ManifestGenerator. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/ITrimmableTypeMapLogger.cs | Add logger API for surfacing library manifest merge warnings. |
Copilot's findings
- Files reviewed: 7/7 changed files
- Comments generated: 1
Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
|
/review |
|
✅ Android PR Reviewer completed successfully! |
There was a problem hiding this comment.
🤖 Android PR Review — ✅ LGTM (2 minor suggestions)
Solid, well-scoped fix. On the trimmable typemap path with AndroidManifestMerger=legacy, referenced-library .aar manifest content (permissions/activities/providers/meta-data) was dropped because the generator's already-present merge logic (MergeLibraryManifests + FixupNameElements + placeholder substitution + dedup) was never fed the extracted manifests. The PR wires @(ExtractedManifestDocuments) → MergedManifestDocuments → ManifestConfig.LibraryManifests → ManifestGenerator.LibraryManifests, matching how the LlvmIr/GenerateJavaStubs sibling already handles it.
What I verified
- ✅ Merge ordering in
Generateis correct and documented: merge → dedup → stripnode="remove"→ placeholder substitution, so${applicationId}resolves in merged content and duplicatemeta-datacollapses. MirrorsManifestDocument. - ✅
@(ExtractedManifestDocuments)added toInputs+DependsOnTargets="_GetLibraryImports"— incrementality is correct (it over-includes on the non-legacy path, which is safe: over-inclusion never yields stale output). - ✅
_MergedManifestDocumentsis gated toAndroidManifestMerger == 'legacy', so there is no double-merge withmanifestmerger.jar. - ✅
XA4302is reused (not a new code) and matches the legacyManifestDocument.csusage; the resource string and docs/index already exist. - ✅
MergedManifestDocumentsis correctly non-[Required]/nullable per MSBuild task conventions; no!operators; Mono formatting preserved. - ✅ Coverage: new
ManifestGeneratorunit tests plus theNativeAOT-parameterizedManifestTest.MergeLibraryManifestintegration test exercise the end-to-end wiring. - ✅ CI: all 42
dotnet-androidchecks are green. (mergeable_state: blockedis the pending required review, not CI.)
Suggestions (non-blocking, posted inline)
- 💡 The
Action<int, string>warning-callback design vs. the existingWarnInvalidPlaceholderpattern (+ the silently-dropped code-0warning). - 💡 A missing test for the
XA4302merge-failure path — the branch theAction<int,string>refactor exists to serve.
Nice work — mirroring ManifestDocument semantics and reaching parity with the LlvmIr path are exactly right.
Severity tally: 0 ❌ · 0
Generated by Android PR Reviewer for #12000 · 290.8 AIC · ⌖ 27.2 AIC · ⊞ 6.8K
Comment /review to run again
| ForceExtractNativeLibs = forceDebuggable, | ||
| ManifestPlaceholders = config.ManifestPlaceholders, | ||
| ApplicationJavaClass = config.ApplicationJavaClass, | ||
| Warn = (code, message) => { |
There was a problem hiding this comment.
🤖 💡 Patterns — Warn was widened to Action<int, string>? and now multiplexes two unrelated diagnostics through magic codes (0 = ignore, 4302 = surface as XA4302). ManifestGenerator already models exactly this case with a dedicated Action<string>? WarnInvalidPlaceholder; a parallel Action<string>? WarnLibraryManifestMerge would drop the 0 sentinel and this if (code == ...) routing, and keep the two warnings independently wireable.
Separately: the code == 0 path (the AssemblyLevelElementBuilder "Could not resolve ... type" warning) stays silently swallowed on the trimmable path. It was already dropped before this PR, so this is not a regression — but if that suppression is deliberate, a one-line note on why would save the next reader a spelunk.
(Consistency with the existing WarnInvalidPlaceholder callback)
| } | ||
|
|
||
| [Fact] | ||
| public void LibraryManifests_MissingFileIgnored () |
There was a problem hiding this comment.
🤖 💡 Testing — Good coverage of the successful merge and the missing-file skip. The remaining gap is the merge-failure branch: a malformed library manifest that makes XDocument.Load throw and routes through Warn (LibraryManifestMergeWarningCode, ...) → XA4302. Surfacing that warning is the entire reason for the Action<int, string> refactor in this PR, so a test that points LibraryManifests at an invalid .xml, sets gen.Warn to capture the callback, and asserts the merge-failure message fires would lock in the new routing.
(Rule: Test error paths, not just the happy path)
Summary
On the trimmable typemap path, the app
AndroidManifest.xmlwas missing content declared by referenced library.aarmanifests (permissions, activities, providers, meta-data) whenAndroidManifestMerger=legacy. Themanifestmerger.jarpath was unaffected because it merges library manifests downstream in_ManifestMerger.The trimmable
ManifestGeneratoralready contained the merge logic (MergeLibraryManifests+FixupNameElements+${applicationId}/placeholder substitution + duplicate-element removal), but it was never fed the extracted library manifests, so on the legacy path nothing was merged.Fix
Wire the extracted library manifests through to the generator:
@(ExtractedManifestDocuments)→GenerateTrimmableTypeMap.MergedManifestDocuments→ManifestConfig.LibraryManifests→ManifestGenerator.LibraryManifests._GenerateTrimmableTypeMapnow depends on_GetLibraryImports(which populates@(ExtractedManifestDocuments)) and includes those documents in itsInputsfor incrementality.AndroidManifestMerger == 'legacy').XA4302warning via a newLogLibraryManifestMergeWarninglogger method, matching the legacyManifestDocumentbehavior.Tests
Adds two
ManifestGeneratorTests:LibraryManifests_MergedWithApplicationIdAndRelativeNamesResolved— verifies${applicationId}resolves to the app package, relative.Typecomponent names are qualified with the library's own package, and duplicatemeta-datacollapses to one element (mirrorsManifestTest.MergeLibraryManifest).LibraryManifests_MissingFileIgnored— a non-existent library manifest path is skipped without throwing.This fixes
ManifestTest.MergeLibraryManifeston the trimmable/NativeAOT path.