[Microsoft.Android.Build.Tasks] Generate typemap ProGuard rules - #12821
Closed
simonrozsival wants to merge 25 commits into
Closed
simonrozsival wants to merge 25 commits into
simonrozsival wants to merge 25 commits into
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Parse the named Java type-name blobs in release and debug CoreCLR LLVM IR, supporting emitted byte strings and legacy integer arrays. Validate required inputs and blob data before writing canonical sorted keys, and cover emitter output and malformed inputs with focused task tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Inspect surviving assembly TypeMapAttribute metadata and exercise emitted assemblies through the pinned real ILLink in standalone tests. Source-link retained-key tasks for repeatable standalone coverage. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reject absent inputs, invalid assembly metadata and malformed typemap attributes. Reuse canonical name validation after decimal alias normalization. Resolve all fixture references for strict real-ILLink coverage and source-link the LLVM adapter for standalone tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Relocate ExtractTypeMapKeysFromLlvmIr to Microsoft.Android.Build.Tasks and use its source-linked shared diagnostics. Move the emitter-backed NUnit fixture to the modern task test project using its existing aliased reference to the LLVM emitter. Preserve the task API, key format, and parser behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Link existing metadata helpers into the modern task assembly and test its production binaries directly instead of source-linking task copies. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Wire the selected modern adapter after its final producer, union per-RID inputs, generate class-only roots, and keep member retention and non-obfuscation policy separate. Track source lists and mode changes while preserving legacy and explicit override paths. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Honor _AndroidEnableTypemapR8Trimming without a default: false selects legacy retention and avoids automatic DGML, while true/unset retain supported pipeline eligibility. Invalidate stale generated rules across switch transitions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use _AndroidEnableTypemapR8Trimming as the sole product switch. Consume DGML only through retained-key extraction; retain optimized-only automatic selection and explicit codegen graph opt-in without the old NativeAOT switches. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Map object arrays to their canonical element class and omit primitive arrays, which do not represent Java class definitions. Keep malformed descriptors and numeric aliases invalid for LLVM inputs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
ILC emits built-in types such as int32 without assembly-qualified names. Ignore the known intrinsic labels while preserving strict validation of malformed managed identities. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep class-root generation separate from scoped JNI member rules and preserve explicit CoreCLR runtime bootstrap members. Leave NativeAOT's existing policy unchanged. Normalize the modern task assembly path for incremental inputs and cover no-op/deleted-output builds plus real inherited JNI method/field access and Java-only dependency removal. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Stream relevant LLVM symbol records and bound relocation queries to avoid whole-symbol/relocation JSON allocations. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Read each RID's actual NativeObject with explicit NDK LLVM tools, select Java groups structurally, and preserve no-NDK default builds through the private opt-in. Remove automatic graphs and retire DGML diagnostics. Reconcile scoped CoreCLR member rules and normalized incremental inputs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep runtime interface-collection assertions and graph-free pipeline regressions, while removing obsolete graph analysis, fixtures, serialization, and guidance. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Select the optimizing Android R8 defaults for the active CoreCLR typemap pipeline while preserving -dontobfuscate, --no-minification and all keep rules. Leave NativeAOT, legacy modes and complete configuration overrides unchanged. Cover actual config selection and R8 metadata, and allow optimizer inlining of Java-only helpers in the JNI device regression. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Five moderate issues remain in exception handling, target gating/override behavior, and NativeAOT test capability detection.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
What changed in this PR
This PR generates retained-typemap-based ProGuard rules for CoreCLR and opt-in NativeAOT builds, replacing broad ACW/DGML retention.
Changes:
- Adds LLVM IR, assembly, and NativeAOT object typemap extraction.
- Updates MSBuild/R8 integration and incremental build behavior.
- Adds rule-generation tasks, tests, diagnostics, and documentation.
- Review found five unresolved issues requiring changes.
| File | Summary |
|---|---|
tests/MSBuildDeviceIntegration/Tests/ScopedTypeMapR8Tests.cs |
Device R8 coverage |
tests/MSBuildDeviceIntegration/Tests/InterfaceCollectionTests.cs |
Interface collection coverage |
tests/MSBuildDeviceIntegration/Tests/InterfaceCollectionRootingTests.cs |
Rooting coverage |
tests/MSBuildDeviceIntegration/Resources/InterfaceCollectionApp/rooting.dgml.xml |
DGML fixture |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TypeMapTaskBuildEngine.cs |
Test build-engine helpers |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/NativeAotObjectIntegrationTests.cs |
NativeAOT integration tests; clang capability check needs updating |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests.csproj |
Test project configuration |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/NativeAotObjectTestFixture.Tool.cs |
NativeAOT tool fixture |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/NativeAotObjectTestFixture.cs |
NativeAOT object fixture |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/ExtractTypeMapKeysFromLlvmIrArrayTests.cs |
LLVM key extraction tests |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/ExtractTypeMapKeysFromAssembliesTests.cs |
Assembly key extraction tests |
src/Xamarin.Android.Build.Tasks/Xamarin.Android.D8.targets |
Tracks generated ProGuard inputs |
src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets |
R8 property and pipeline integration |
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs |
Build test utilities |
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.cs |
Trimmable typemap build coverage |
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/R8Tests.cs |
R8 task tests |
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GenerateNativeAotProguardConfigurationTests.cs |
NativeAOT rule-generation tests |
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs |
Build regression coverage |
src/Xamarin.Android.Build.Tasks/Tasks/R8.cs |
Applies typemap R8 policies |
src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs |
NativeAOT configuration handling |
src/Xamarin.Android.Build.Tasks/Resources/proguard_typemap.cfg |
Shared ProGuard rules |
src/Xamarin.Android.Build.Tasks/Resources/proguard_typemap_coreclr.cfg |
CoreCLR ProGuard rules |
src/Xamarin.Android.Build.Tasks/Resources/proguard_trimmable_nativeaot.cfg |
NativeAOT ProGuard rules |
src/Xamarin.Android.Build.Tasks/Properties/Resources.resx |
Localized resources |
src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs |
Generated resource accessors |
src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets |
NativeAOT pipeline |
src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.CoreCLR.targets |
CoreCLR pipeline |
src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Proguard.targets |
ProGuard pipeline; eligibility and override guards need correction |
src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets |
LLVM typemap pipeline |
src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets |
Assembly resolution integration |
src/Microsoft.Android.Build.Tasks/Utilities/TypeMapKey.cs |
Typemap key representation |
src/Microsoft.Android.Build.Tasks/Utilities/TypeMapClassName.cs |
JNI class-name normalization |
src/Microsoft.Android.Build.Tasks/Utilities/NativeAotTypeMapReader.cs |
NativeAOT typemap parsing |
src/Microsoft.Android.Build.Tasks/Tests/Microsoft.Android.Build.Tasks.Tests/GenerateTypeMapProguardConfigurationTests.cs |
Rule-generation tests |
src/Microsoft.Android.Build.Tasks/Tests/Microsoft.Android.Build.Tasks.Tests/ExtractTypeMapKeysFromLlvmIrTests.cs |
LLVM extraction tests |
src/Microsoft.Android.Build.Tasks/Tasks/GenerateTypeMapProguardConfiguration.cs |
Generates class keep rules |
src/Microsoft.Android.Build.Tasks/Tasks/GenerateTypeMapMemberProguardConfiguration.cs |
Generates member keep rules |
src/Microsoft.Android.Build.Tasks/Tasks/ExtractTypeMapKeysFromNativeAotObject.cs |
Extracts NativeAOT keys; malformed UTF-8 handling needs correction |
src/Microsoft.Android.Build.Tasks/Tasks/ExtractTypeMapKeysFromLlvmIr.cs |
Extracts LLVM keys; malformed UTF-8 handling needs correction |
src/Microsoft.Android.Build.Tasks/Tasks/ExtractTypeMapKeysFromAssemblies.cs |
Extracts assembly keys |
src/Microsoft.Android.Build.Tasks/Microsoft.Android.Build.Tasks.csproj |
Task project configuration |
Documentation/guides/D8andR8.md |
R8 pipeline documentation |
Documentation/docs-mobile/TOC.yml |
Documentation navigation |
Documentation/docs-mobile/messages/xa4328.md |
Diagnostic documentation |
Documentation/docs-mobile/messages/xa4327.md |
Diagnostic documentation |
Documentation/docs-mobile/messages/xa4321.md |
Diagnostic documentation |
Documentation/docs-mobile/messages/xa4320.md |
Diagnostic documentation |
Documentation/docs-mobile/messages/xa4319.md |
Diagnostic documentation |
Documentation/docs-mobile/messages/index.md |
Diagnostic index |
Documentation/docs-mobile/building-apps/build-properties.md |
Build property documentation |
.github/skills/tests/references/test-catalog.md |
Test prerequisite documentation |
Files not reviewed (1)
- src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs: Generated file
Comment on lines
+122
to
+124
| Condition=" '$(_AndroidEnableTypemapR8Trimming)' != 'false' and '$(PublishTrimmed)' == 'true' and '$(AndroidLinkTool)' == 'r8' and '$(_ComputeFilesToPublishForRuntimeIdentifiers)' != 'true' and ('$(_AndroidRuntime)' == 'CoreCLR' or ('$(_AndroidRuntime)' == 'NativeAOT' and '$(AndroidTypeMapImplementation)' == 'trimmable' and '$(_AndroidEnableTypemapR8Trimming)' == 'true')) " | ||
| Inputs="@(_AndroidTypeMapKeyFile);$(_AndroidTypeMapTasksAssemblyFile);$(_AndroidBuildPropertiesCache)" | ||
| Outputs="$(_ProguardProjectConfiguration)"> |
This was referenced Sep 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why
R8 cannot see managed-to-Java JNI references. Keeping every entry in the
pre-trim ACW map preserves Java classes that managed trimming no longer
needs, while reading Register attributes is not a common representation
for all typemap implementations.
Generate Java class roots from the retained typemap instead, using a small
shared intermediate format and runtime-specific adapters.
Related to #10790, #11767, and #12814.
Implementation
All new tasks live in
Microsoft.Android.Build.Tasks, under theMicrosoft.Android.Tasksnamespace..llJava-name blobsAdapters emit ordinal-sorted, distinct JNI class names, one per line,
UTF-8 without a BOM, with LF endings. Representation-specific aliases and
array keys are normalized before producing the shared class-name file.
Missing or malformed required inputs fail rather than silently producing
an empty retention policy.
<GenerateTypeMapProguardConfiguration/>emits class-only keep rules.Separate configuration handles runtime bootstrap roots and member
preservation. CoreCLR keeps all members of retained JNI-facing classes;
Java-only dependencies remain eligible for member shrinking. NativeAOT
retains the conservative all-members policy. There is no precise
JNI-method inference or runtime obfuscation work here.
The pipeline runs after the relevant trimming/typemap producer and before
R8. Exact per-RID producer paths are propagated and unioned; source-list
and property changes, deleted outputs, incremental builds and Clean are
covered.
NativeAOT no longer generates or scans DGML graphs for this purpose. Its
object adapter currently requires NDK LLVM tools and is explicitly opt-in.
The private
$(_AndroidEnableTypemapR8Trimming)override disables orselects the new pipeline; supported trimmed CoreCLR R8 builds use it
automatically when the override is unset. Complete
$(ProguardConfigFiles)overrides retain their existing behavior.The active CoreCLR path enables R8 optimization while keeping obfuscation
disabled. Other runtime paths retain their configuration selection.
Validation
including real NDK object fixtures, linked-assembly extraction, emitted
LLVM layouts, shared rule generation and MSBuild incremental contracts.
dotnet new androidand MAUIsample-content applications on ARM64, including Samsung A16 runs for
both CoreCLR typemaps and NativeAOT with trimmable typemaps.
applicable. Benchmark/profile artifacts and the reverted precise-member
proof of concept are not part of this PR.
For MAUI sample-content with full managed trimming, Release/ARM64 and
obfuscation disabled, total uncompressed DEX sizes were:
CoreCLR comparisons include enabling R8 optimization. With optimization
disabled on both sides, the respective DEX reductions were 3.85% and
0.086%; the NativeAOT reduction remained 42.70%. The Java-policy toggle
did not materially improve startup with matching MIBC profiles already
applied; this is principally a size improvement.
The MAUI template used the same compatible preview6 dependency pin on both
sides because its original preview7 dependencies produced CS1705 against
the locally built SDK. Trimming warnings were not suppressed.
NativeAOT/full sample-content builds retain a Dashboard-loading limitation
with both rule policies; this PR does not claim to fix it.
Scope and review organization
Visual Studio 2026 provides the supported hosting for these .NET tasks.
Standalone .NET Framework CLI MSBuild is outside the support scope; it is
not a readiness blocker for this change.
NativeAOT remains opt-in until the native-object tooling can be supplied
without requiring an NDK. NativeAOT with the LLVM typemap is unsupported
and is excluded from the results.
This changeset is being split into a stack of smaller review units. This
source PR will remain open until the replacement stack is complete and
verified.