Uh oh!
There was an error while loading. Please reload this page.
[TrimmableTypeMap] Manifest rooting and deferred registration propagation - #11097
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends the trimmable typemap generator pipeline to be manifest-aware: it roots manifest-referenced components (including placeholder/substitution handling), promotes compat JNI names so generated JCW names match manifest declarations, and propagates deferred registerNatives behavior through managed base hierarchies for Application/Instrumentation types.
Changes:
- Root manifest-referenced component types as unconditional (with placeholder resolution) and log/warn for unresolved types (XA4250).
- Promote compat JNI names for manifest-rooted components so generated JCW class names align with manifest entries.
- Propagate deferred registration (
CannotRegisterInStaticConstructor) to generated managed base types and default instrumentationtargetPackage.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TrimmableTypeMapGeneratorTests.cs | Adds unit tests for manifest rooting, placeholder resolution, compat name promotion, deferred registration propagation, and unresolved-type warnings. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/ManifestGeneratorTests.cs | Adds a test ensuring instrumentation defaults targetPackage to the manifest package. |
| src/Xamarin.Android.Build.Tasks/Tasks/GenerateTrimmableTypeMap.cs | Implements new typed logger methods: XA4250 warning + info logging for manifest rooting. |
| src/Xamarin.Android.Build.Tasks/Properties/Resources.resx | Adds localized string for XA4250. |
| src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs | Updates generated resource accessor for XA4250. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/TrimmableTypeMapGenerator.cs | Adds manifest-rooting + placeholder prep, compat-JNI promotion, and deferred registration propagation logic. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/JavaPeerInfo.cs | Makes several properties mutable to support post-scan manifest rooting and propagation. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/ITrimmableTypeMapLogger.cs | Extends logger interface with unresolved-type warning + manifest-rooting info message. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/ManifestGenerator.cs | Passes package name into instrumentation generation and simplifies placeholder application. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/ComponentElementBuilder.cs | Defaults instrumentation targetPackage when missing. |
| Documentation/docs-mobile/messages/xa4250.md | Adds documentation page for XA4250 warning. |
| Documentation/docs-mobile/messages/index.md | Adds XA4250 to the messages index. |
Files not reviewed (1)
- src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs: Language not supported
| foreach (var name in componentNames) { | ||
| if (peersByDotName.TryGetValue (name, out var peers)) { | ||
| foreach (var peer in peers.Distinct ()) { | ||
| PromoteManifestCompatibleJavaName (allPeers, peer, name); | ||
| if (deferredRegistrationNames.Contains (name)) { | ||
| peer.CannotRegisterInStaticConstructor = true; | ||
| } | ||
| if (!peer.IsUnconditional) { | ||
| peer.IsUnconditional = true; | ||
| logger?.LogRootingManifestReferencedTypeInfo (name, peer.ManagedTypeName); | ||
| } | ||
| } |
There was a problem hiding this comment.
peers.Distinct() here relies on JavaPeerInfo record value equality/hashing, but JavaPeerInfo now has mutable properties (e.g., JavaName, IsUnconditional, CannotRegisterInStaticConstructor) that are modified inside this loop. Mutating keys used in Distinct()/HashSet can lead to incorrect de-duplication and unpredictable behavior. Consider de-duping by reference (custom comparer) or avoid Distinct() and instead track processed peers in a separate HashSet<JavaPeerInfo> using reference equality.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
d64ece1 to
6ccb7caCompare2b22bc6 to
3b1083eCompare3aa9b44 to
8fd237aCompare23890de to
6ac587cCompare8fd237a to
b82f717Compareb82f717 to
0768a52Compare…tion - Manifest name promotion: promote compat JNI names for manifest-rooted components so the generated JCW class name matches the manifest entry - Deferred registration propagation: propagate CannotRegisterInStaticConstructor to generated managed base types of Application/Instrumentation - Instrumentation targetPackage: pass package name for manifest instrumentation elements - XA4250 warning: warn when manifest references a type that cannot be resolved in any scanned assembly - NestedAssembly for UTF-8 helpers: fix FieldAccessException from NestedPrivate visibility Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
6ac587c to
3b2d707CompareCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
682ebac
into
dev/simonrozsival/trimmable-scanner-jcw-fixesUh oh!
There was an error while loading. Please reload this page.
…#11105) ## Summary Fixes a startup crash (`UnsatisfiedLinkError: No implementation found for void mono.android.Runtime.registerNatives`) when running device tests with the trimmable typemap enabled. ## Background Deferred `registerNatives` support was introduced across several PRs: - **#10957** — Added `CannotRegisterInStaticConstructor` flag and set it in `JavaPeerScanner` for types with `[Application]` or `[Instrumentation]` attributes. The JCW generator skips the `static { registerNatives(...); }` block for these types and emits a lazy `__md_registerNatives()` helper instead. - **#11037** — Extended deferred registration to manifest-rooted types: `RootManifestReferencedTypes` sets `CannotRegisterInStaticConstructor` on types matched by `<application>` or `<instrumentation>` manifest entries. - **#11096** / **#11097** — Further scanner and JCW edge-case fixes, including deferred registration propagation for generated managed base types. **None of these PRs propagated the flag to base classes in the Java type hierarchy.** When `NUnitInstrumentation` (listed in the manifest) correctly uses deferred registration, its base class `TestInstrumentation_1` still emits `static { registerNatives(...); }`. Since Java loads the base class `<clinit>` before the managed runtime registers the JNI native method, this crashes with `UnsatisfiedLinkError`. ## Changes Add `PropagateDeferredRegistrationToBaseClasses()` in `TrimmableTypeMapGenerator`, called after `RootManifestReferencedTypes`. It walks each flagged peer's `BaseJavaName` chain with a simple linear scan and sets `CannotRegisterInStaticConstructor = true` on all base peers that have JCW stubs (i.e., `!DoNotGenerateAcw`). Framework MCW types are skipped. In practice only 1–2 types need propagation (one Application, maybe one Instrumentation), each with a short base-class chain. A linear scan per ancestor is simpler and cheaper than building a `Dictionary<JavaName, List<Peer>>` lookup over all peers up front. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Manifest-aware rooting and deferred registration propagation for the trimmable typemap generator.
Depends on:#11096 (scanner + JCW fixes)
Changes
CannotRegisterInStaticConstructorto generated managed base types of Application/InstrumentationLogUnresolvedTypeWarningandLogRootingManifestReferencedTypeInfoto the logger interface