Skip to content

[Xamarin.Android.Build.Tasks] Retain only typemap class mappings - #13022

Closed
simonrozsival wants to merge 1 commit into
mainfrom
simonrozsival-typemap-member-retention
Closed

simonrozsival wants to merge 1 commit into
mainfrom
simonrozsival-typemap-member-retention

Conversation

@simonrozsival

@simonrozsival simonrozsival commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Context: #12848
Related pending consumer: #12692.

Xamarin.Android.Tasks.JniRemapping.JniRemappingAssemblyScanner.ScanTypeMapAttributes() calls RecordAllMappings() for every surviving Java TypeMap key. That helper records every R8-mapped method and field, even when those members have disappeared from final managed metadata. A class-only TypeMap therefore bypasses the scanner's surviving-consumer filter and restores unused member replacements.

Record only class identity with R8Mapping.TryGetRenamedClass() and remove the now-unused all-member helper. Forward/reverse type mappings remain available; legitimate method and field retention continues through surviving JNI metadata. Framework attribute/group/assembly identity checks, alias normalization, malformed-input diagnostics, field descriptor semantics, input assembly immutability, public signatures, and the separate NativeAOT retention path are unchanged.

Correct the existing TypeMap retention expectation rather than deleting it. Extend class-only generation fixtures with renamed methods/fields and real local proxy/target types without Register metadata, covering both two- and three-argument TypeMap forms and framework implementation identities. Mixed fixtures retain the registered method and both field descriptor variants, but not unused members or an unused overload. Assertions inspect actual accessed entries and generated XML, and compare input assembly bytes. Document the class/member distinction.

This is a new standalone fix based exactly on 8de547b9a2962a0383c57a418777c8add7bdaf1c. It does not change any existing PR or stack metadata.

Validation

The worktree has no local Android SDK. The following repository host-test command failed before test execution with You need to run 'make prepare' first.:

./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter 'FullyQualifiedName~JniRemappingAssemblyScannerTests|FullyQualifiedName~GenerateR8JniRemappingTests'

Used an authorized scratch source harness in the session artifact directory instead. It compiles the actual current-worktree scanner, R8 mapping/parser, descriptor helpers, GenerateR8JniRemapping, NativeAOT retention/readers, MergeRemapXml, metadata helpers, resources, and original focused NUnit test files—not stale product DLLs. Only SDK-wide encoding/logging and test-environment infrastructure are adapted. It runs on the installed .NET 11 RC runtime; the actual source compatibility build targets the product's netstandard2.0. linked.runsettings enables the existing real ILLink identity test using cached ILLink 11.0.0-rc.2.26475.136 and its matching installed framework.

Commands below were executed from the session-area typemap-retention-harness directory:

dotnet test RetentionHarness.csproj -f net11.0 --settings linked.runsettings --filter 'FullyQualifiedName~JniRemappingAssemblyScannerTests|FullyQualifiedName~GenerateR8JniRemappingTests|FullyQualifiedName~R8MappingTests|FullyQualifiedName~JniDescriptorTextTests' --logger 'trx;LogFileName=before.trx' --results-directory results -v minimal

Before the production fix: 19 expected retention failures, 143 passed, 0 skipped, 162 total. Production scanner source was verified unchanged against the exact main baseline. Class-only fixtures emitted unwanted replace-method/replace-field; mixed fixtures recorded unused members and an unused overload.

dotnet test RetentionHarness.csproj -f net11.0 --settings linked.runsettings --filter 'FullyQualifiedName~JniRemappingAssemblyScannerTests|FullyQualifiedName~GenerateR8JniRemappingTests|FullyQualifiedName~R8MappingTests|FullyQualifiedName~JniDescriptorTextTests' --logger 'trx;LogFileName=after.trx' --results-directory results -v minimal

After the fix: 162 passed, 0 failed, 0 skipped: 31 scanner, 74 generator/retention/malformed-XML, 41 mapping, and 16 descriptor cases. The real ILLink identity case passed. Test compilation reports two unchanged nullable warnings in baseline R8Mapping/MergeRemapXml sources.

dotnet build RetentionHarness.csproj -f netstandard2.0 --no-restore -v minimal
git diff --check

Results: source compatibility build passed with 0 warnings and 0 errors; diff check passed. Full Android SDK builds, app-level R2R/device tests, and pipelines were not run; no broad bootstrap was performed per the requested scope. Before/after TRX results, logs, runsettings, and harness sources remain in session artifacts.

A surviving Java TypeMap attribute establishes class identity, not
that every R8-mapped member still has a managed consumer.  Recording
all members restores remapping entries for methods and fields absent
from final linked metadata.

Record only the class mapping and leave member retention to surviving
JNI metadata.  Remove the unused all-member helper.  Cover class-only
and mixed fixtures, both attribute forms, forward/reverse XML, field
descriptor variants, and byte-for-byte input assembly immutability.

Context: #12848

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 6, 2026 12:07

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

🔵 Needs a closer look

Runtime remapping behavior lacks validation through the standard repository build, CI, and integration test paths.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

Restricts TypeMap-based R8 retention to class mappings while preserving member mappings only when surviving JNI metadata references them.

Changes:

  • Replaces all-member retention with class-only retention.
  • Adds regression coverage for TypeMap forms and surviving members.
  • Documents class-versus-member retention semantics.
File Description
JniRemappingAssemblyScanner.cs Records only TypeMap class access.
JniRemappingAssemblyScannerTests.cs Expands retention and immutability tests.
JavaJNI_Interop.md Documents retention behavior.

{
/// <summary>
/// Reads linked managed metadata to identify JNI mappings that still have managed consumers.
/// TypeMap attributes retain class identity, not members lacking surviving JNI metadata.
@simonrozsival

Copy link
Copy Markdown
Member Author

Superseded by #12692. The validated class-only TypeMap retention commit c139a77 was adopted directly into the rebased #12692 branch as commit 7c11831. Closing this standalone PR to keep the fix with the R8 runtime-remapping policy series.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants