Repository navigation
[TrimmableTypeMap] R8 shrinks bound library Java types out of classes.dex on trimmable NativeAOT (missing proguard keeps) #11835
Description
Summary
On the trimmable typemap + NativeAOT path, R8 (release shrinking) removes bound library Java types from classes.dex because the proguard config that keeps them is excluded and the trimmable path's replacement keep-config is empty. This causes BindingWithAndroidJavaSource to fail (a library's Java class is missing from the app's dex), and more generally means user/library Java types packaged via a binding project can be shrunk out of a trimmable NativeAOT app.
This is currently latent on main because NativeAOT still defaults to the managed typemap. It surfaces once NativeAOT defaults to trimmable (see the stacked PR that makes trimmable the NativeAOT default).
Repro
Build tests, Xamarin.Android.Build.Tests:
BindingWithAndroidJavaSource(NativeAOT)
Failure:
`.../App/obj/Release/android/bin/classes.dex` should include `Lcom/xamarin/android/test/msbuildtest/JavaSourceJarTest;`!
Expected: True
But was: False
Minimal shape: a binding/class library that contributes a Java class (via @(AndroidJavaSource) / a bound jar) referenced by an app, built Release for NativeAOT with the trimmable typemap.
Root cause (verified via binlog)
- Release build ⇒ the dex is produced by R8 (shrinking on).
- R8 does receive the library jars (
obj/Release/lp/1/jl/libs/*.jar) asJavaLibrariesToEmbed— the inputs are correct. - But no keep rule preserves the library Java types, so R8 shrinks
JavaSourceJarTest,JavaSourceTestExtension, andJavaSourceTestInterfaceout of the dex. - The only proguard config that keeps them is
proguard_project_references.cfg($(_ProguardProjectConfiguration)), which contains:…and it is excluded from R8 on trimmable NativeAOT in-keep class com.xamarin.android.test.msbuildtest.JavaSourceTestInterface { *; } -keep class com.xamarin.android.test.msbuildtest.JavaSourceJarTest { *; } -keep class com.xamarin.android.test.msbuildtest.JavaSourceTestExtension { *; }Xamarin.Android.Common.targets:<_ProguardConfiguration Include="$(_ProguardProjectConfiguration)" Condition=" '$(AndroidLinkTool)' != '' and ('$(_AndroidRuntime)' != 'NativeAOT' or '$(_AndroidTypeMapImplementation)' != 'trimmable') " />
- The trimmable path is meant to generate keeps into
proguard_project_primary.cfginstead, but on this build that file is empty — only:The ACW-from-ILC generation does not cover raw java-source-jar classes or bound library Java types, so nothing keeps them.# ACW keep rules are generated from NativeAOT ILC metadata.
Net: R8 gets the jars but no keep ⇒ library Java types are dropped from the dex.
Why it wasn't caught earlier
The original monolithic PR (#11617) had the same _ProguardProjectConfiguration exclusion and already defaulted NativeAOT to trimmable, and it did not skip BindingWithAndroidJavaSource. So the proguard-keep generation for trimmable NativeAOT appears to have regressed between #11617 and the current typemap-manager base branch (the extracted/refined stack), which now emits an empty proguard_project_primary.cfg for this scenario.
Suggested fixes (need a decision)
- (A) Stop excluding
proguard_project_references.cfgon trimmable NativeAOT. That file already contains the correct, complete keep rules produced by the standard ACW-map path. Simple one-line change. Risk: the exclusion was deliberate — confirm it doesn't over-keep and undermine trimming/size goals. - (B) Make the trimmable-NativeAOT proguard generator (
GenerateNativeAotProguardConfiguration/_GenerateTrimmableTypeMapProguardConfigurationinMicrosoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets) emit keeps for library/bound Java types into the primary config. More work; preserves the intended design.
Recommend diffing the NativeAOT proguard generation between #11617 and the current base to see exactly what regressed, which should decide A vs B.
Environment
- Local
make prepare && make allbuild of the typemap-default-nativeaot branch. - Verified by decompiling/binlog: R8 command included the
lp/1/jl/libs/*.jarinputs and--pg-conf proguard_xamarin.cfg / proguard_project_primary.cfg / aapt_rules.txtbut notproguard_project_references.cfg;proguard_project_primary.cfgwas empty apart from the comment.
Activity
simonrozsival commentedon Jul 1, 2026
Duplicate of #11774 (same root cause: R8 shrinking removes Java classes on trimmable NativeAOT because the generated proguard keep-config is incomplete). Folded the binding-specific repro (
BindingWithAndroidJavaSource) and theproguard_project_references.cfgexclusion detail into #11774. Closing in favor of that issue.