From b3b929abf1198a3df89bc87eb9e88ed37d704c9c Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 22 May 2026 10:13:51 +0200 Subject: [PATCH 1/7] [TrimmableTypeMap] Generate NativeAOT ProGuard rules from DGML Use NativeAOT scan DGML to identify retained managed types, intersect them with acw-map.txt, and emit concrete R8 keep rules for trimmable typemap NativeAOT builds. This avoids keeping the broad generated Java wrapper set when R8 is enabled. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Microsoft.Android.Sdk.NativeAOT.targets | 4 +- ...crosoft.Android.Sdk.TypeMap.LlvmIr.targets | 4 +- ...id.Sdk.TypeMap.Trimmable.NativeAOT.targets | 20 +++++ .../Tasks/GenerateProguardConfiguration.cs | 83 ++++++++++++++++++- src/Xamarin.Android.Build.Tasks/Tasks/R8.cs | 30 ++++++- .../Xamarin.Android.D8.targets | 1 + 6 files changed, 136 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets index e145c311485..c364405434e 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets @@ -26,7 +26,9 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. <_IsPublishing Condition=" '$(_IsPublishing)' == '' ">true - <_GenerateProguardAfterTargets>_AndroidComputeIlcCompileInputs + <_GenerateProguardAfterTargets Condition=" '$(_AndroidTypeMapImplementation)' != 'trimmable' ">_AndroidComputeIlcCompileInputs + <_SkipLinkedAssemblyProguardConfiguration Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' ">true + <_UseTrimmableNativeAotProguardConfiguration Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' ">true static diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index d2ca7cb573d..2ac7e2a978c 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -412,7 +412,7 @@ + Condition=" '$(PublishTrimmed)' == 'true' and '$(_ProguardProjectConfiguration)' != '' and '$(_SkipLinkedAssemblyProguardConfiguration)' != 'true' "> <_LinkedAssemblyForProguard Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " /> @@ -420,7 +420,7 @@ + + <_TrimmableRuntimeProviderJavaName Condition=" '$(_TrimmableRuntimeProviderJavaName)' == '' ">net.dot.jni.nativeaot.NativeAotRuntimeProvider + true - + <_TrimmableRuntimeProviderJavaName Condition=" '$(_TrimmableRuntimeProviderJavaName)' == '' ">net.dot.jni.nativeaot.NativeAotRuntimeProvider @@ -41,7 +41,7 @@ Condition=" '$(PublishTrimmed)' == 'true' and '$(_ProguardProjectConfiguration)' != '' " Inputs="$(NativeIntermediateOutputPath)$(TargetName).scan.dgml.xml;$(IntermediateOutputPath)acw-map.txt" Outputs="$(_ProguardProjectConfiguration)"> - diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs new file mode 100644 index 00000000000..c022d753249 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs @@ -0,0 +1,103 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Microsoft.Build.Framework; +using Microsoft.Android.Build.Tasks; + +namespace Xamarin.Android.Tasks +{ + public class GenerateNativeAotProguardConfiguration : AndroidTask + { + public override string TaskPrefix => "GNAPC"; + + [Required] + public string NativeAotDgmlFile { get; set; } = ""; + + [Required] + public string AcwMapFile { get; set; } = ""; + + [Required] + public string OutputFile { get; set; } = ""; + + public override bool RunTask () + { + var dir = Path.GetDirectoryName (OutputFile); + if (!dir.IsNullOrEmpty () && !Directory.Exists (dir)) { + Directory.CreateDirectory (dir); + } + + if (!File.Exists (NativeAotDgmlFile)) { + Log.LogError ("NativeAOT DGML file '{0}' was not found.", NativeAotDgmlFile); + return false; + } + if (!File.Exists (AcwMapFile)) { + Log.LogError ("ACW map file '{0}' was not found.", AcwMapFile); + return false; + } + + var retainedTypeKeys = LoadRetainedTypeKeysFromDgml (); + var javaTypes = LoadJavaTypesFromAcwMap (retainedTypeKeys); + + using var writer = File.CreateText (OutputFile); + writer.WriteLine ("# ACWs retained by NativeAOT ILC"); + foreach (var javaTypeName in javaTypes) { + writer.WriteLine ($"-keep class {javaTypeName} {{ *; }}"); + } + + Log.LogMessage (MessageImportance.Low, $"Generated {javaTypes.Count} NativeAOT trimmable typemap ProGuard rules from '{NativeAotDgmlFile}'."); + return !Log.HasLoggedErrors; + } + + SortedSet LoadJavaTypesFromAcwMap (HashSet retainedTypeKeys) + { + var javaTypes = new SortedSet (StringComparer.Ordinal); + foreach (var line in File.ReadLines (AcwMapFile)) { + var separator = line.IndexOf (';'); + if (separator <= 0 || separator == line.Length - 1) { + continue; + } + var managedTypeName = line.Substring (0, separator); + var javaTypeName = line.Substring (separator + 1); + if (retainedTypeKeys.Contains (managedTypeName)) { + javaTypes.Add (javaTypeName); + } + } + return javaTypes; + } + + HashSet LoadRetainedTypeKeysFromDgml () + { + var typeKeys = new HashSet (StringComparer.Ordinal); + using var reader = XmlReader.Create (NativeAotDgmlFile, new XmlReaderSettings { + DtdProcessing = DtdProcessing.Prohibit, + }); + + while (reader.Read ()) { + if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "Node") { + continue; + } + + var label = reader.GetAttribute ("Label"); + if (label.IsNullOrEmpty () || !label.StartsWith ("Type metadata: [", StringComparison.Ordinal)) { + continue; + } + + var assemblyStart = "Type metadata: [".Length; + var assemblyEnd = label.IndexOf (']', assemblyStart); + if (assemblyEnd < 0 || assemblyEnd == label.Length - 1) { + continue; + } + + var assemblyName = label.Substring (assemblyStart, assemblyEnd - assemblyStart); + var managedTypeName = label.Substring (assemblyEnd + 1); + typeKeys.Add (managedTypeName); + typeKeys.Add ($"{managedTypeName}, {assemblyName}"); + } + + return typeKeys; + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateProguardConfiguration.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateProguardConfiguration.cs index 7d5bf72b278..385ba9bd08f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateProguardConfiguration.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateProguardConfiguration.cs @@ -1,11 +1,9 @@ #nullable enable using System; -using System.Collections.Generic; using System.IO; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; -using System.Xml; using Microsoft.Build.Framework; using Microsoft.Android.Build.Tasks; @@ -20,10 +18,6 @@ public class GenerateProguardConfiguration : AndroidTask [Required] public string OutputFile { get; set; } = ""; - public string NativeAotDgmlFile { get; set; } = ""; - - public string AcwMapFile { get; set; } = ""; - public override bool RunTask () { var dir = Path.GetDirectoryName (OutputFile); @@ -32,11 +26,6 @@ public override bool RunTask () } using var writer = File.CreateText (OutputFile); - if (!NativeAotDgmlFile.IsNullOrEmpty ()) { - ProcessNativeAotDgml (writer); - return !Log.HasLoggedErrors; - } - foreach (var assembly in LinkedAssemblies) { ProcessAssembly (assembly.ItemSpec, writer); } @@ -77,77 +66,6 @@ void ProcessAssembly (string assemblyPath, TextWriter writer) } } - void ProcessNativeAotDgml (TextWriter writer) - { - if (!File.Exists (NativeAotDgmlFile)) { - Log.LogError ("NativeAOT DGML file '{0}' was not found.", NativeAotDgmlFile); - return; - } - if (AcwMapFile.IsNullOrEmpty () || !File.Exists (AcwMapFile)) { - Log.LogError ("ACW map file '{0}' was not found.", AcwMapFile); - return; - } - - var retainedTypeKeys = LoadRetainedTypeKeysFromDgml (); - var javaTypes = LoadJavaTypesFromAcwMap (retainedTypeKeys); - - writer.WriteLine ("# ACWs retained by NativeAOT ILC"); - foreach (var javaTypeName in javaTypes) { - writer.WriteLine ($"-keep class {javaTypeName} {{ *; }}"); - } - - Log.LogMessage (MessageImportance.Low, $"Generated {javaTypes.Count} NativeAOT trimmable typemap ProGuard rules from '{NativeAotDgmlFile}'."); - } - - SortedSet LoadJavaTypesFromAcwMap (HashSet retainedTypeKeys) - { - var javaTypes = new SortedSet (StringComparer.Ordinal); - foreach (var line in File.ReadLines (AcwMapFile)) { - var separator = line.IndexOf (';'); - if (separator <= 0 || separator == line.Length - 1) { - continue; - } - var managedTypeName = line.Substring (0, separator); - var javaTypeName = line.Substring (separator + 1); - if (retainedTypeKeys.Contains (managedTypeName)) { - javaTypes.Add (javaTypeName); - } - } - return javaTypes; - } - - HashSet LoadRetainedTypeKeysFromDgml () - { - var typeKeys = new HashSet (StringComparer.Ordinal); - using var reader = XmlReader.Create (NativeAotDgmlFile, new XmlReaderSettings { - DtdProcessing = DtdProcessing.Prohibit, - }); - - while (reader.Read ()) { - if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "Node") { - continue; - } - - var label = reader.GetAttribute ("Label"); - if (label.IsNullOrEmpty () || !label.StartsWith ("Type metadata: [", StringComparison.Ordinal)) { - continue; - } - - var assemblyStart = "Type metadata: [".Length; - var assemblyEnd = label.IndexOf (']', assemblyStart); - if (assemblyEnd < 0 || assemblyEnd == label.Length - 1) { - continue; - } - - var assemblyName = label.Substring (assemblyStart, assemblyEnd - assemblyStart); - var managedTypeName = label.Substring (assemblyEnd + 1); - typeKeys.Add (managedTypeName); - typeKeys.Add ($"{managedTypeName}, {assemblyName}"); - } - - return typeKeys; - } - static bool ReferencesMonoAndroid (MetadataReader reader) { foreach (var refHandle in reader.AssemblyReferences) { From 5d4aae8ae1e13194a84aaf8aee186911db1385ca Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 22 May 2026 10:30:05 +0200 Subject: [PATCH 3/7] [TrimmableTypeMap] Move ProGuard wiring to typemap targets Keep NativeAOT.targets free of ProGuard coordination properties. Let LlvmIr targets hardcode linked-assembly ProGuard timing for ILLink and NativeAOT, and keep the trimmable NativeAOT R8 mode flag with the trimmable NativeAOT typemap targets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Microsoft.Android.Sdk.NativeAOT.targets | 5 --- ...crosoft.Android.Sdk.TypeMap.LlvmIr.targets | 31 +++++++++++-------- ...id.Sdk.TypeMap.Trimmable.NativeAOT.targets | 1 + 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets index c364405434e..e23d1813198 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets @@ -24,11 +24,6 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. true <_IsPublishing Condition=" '$(_IsPublishing)' == '' ">true - - <_GenerateProguardAfterTargets Condition=" '$(_AndroidTypeMapImplementation)' != 'trimmable' ">_AndroidComputeIlcCompileInputs - <_SkipLinkedAssemblyProguardConfiguration Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' ">true - <_UseTrimmableNativeAotProguardConfiguration Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' ">true static diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 2ac7e2a978c..caf36b7f5f8 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -400,27 +400,32 @@ + + + <_LinkedAssemblyForProguard Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " /> + + + + - - <_GenerateProguardAfterTargets Condition=" '$(_GenerateProguardAfterTargets)' == '' ">ILLink - - - + Instead, _AndroidComputeIlcCompileInputs populates ResolvedFileToPublish. Trimmable NativeAOT + generates its ProGuard configuration from ILC DGML in Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets. --> + <_LinkedAssemblyForProguard Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " /> <_TrimmableRuntimeProviderJavaName Condition=" '$(_TrimmableRuntimeProviderJavaName)' == '' ">net.dot.jni.nativeaot.NativeAotRuntimeProvider true + <_UseTrimmableNativeAotProguardConfiguration>true <_IsPublishing Condition=" '$(_IsPublishing)' == '' ">true + + <_GenerateProguardAfterTargets>_AndroidComputeIlcCompileInputs static diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index caf36b7f5f8..d2ca7cb573d 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -400,32 +400,27 @@ - - - <_LinkedAssemblyForProguard Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " /> - - - - - + Instead, _AndroidComputeIlcCompileInputs populates ResolvedFileToPublish, so NativeAOT.targets + sets _GenerateProguardAfterTargets to run these targets after that. --> + + <_GenerateProguardAfterTargets Condition=" '$(_GenerateProguardAfterTargets)' == '' ">ILLink + + + <_LinkedAssemblyForProguard Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " /> mono.MonoRuntimeProvider + + + - - - diff --git a/src/Xamarin.Android.Build.Tasks/Resources/proguard_trimmable_nativeaot.cfg b/src/Xamarin.Android.Build.Tasks/Resources/proguard_trimmable_nativeaot.cfg new file mode 100644 index 00000000000..6d54d809ae2 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Resources/proguard_trimmable_nativeaot.cfg @@ -0,0 +1,15 @@ +# Xamarin.Android NativeAOT trimmable typemap configuration. + +-dontobfuscate + +-keep class net.dot.jni.** { *; (...); } +-keep class net.dot.android.crypto.** { *; (...); } + +-keepclassmembers class * extends android.view.View { + *** set*(...); +} + +-keepclassmembers class * extends android.view.View { + (android.content.Context,android.util.AttributeSet); + (android.content.Context,android.util.AttributeSet,int); +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs index c022d753249..83620408b9e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs @@ -51,9 +51,9 @@ public override bool RunTask () return !Log.HasLoggedErrors; } - SortedSet LoadJavaTypesFromAcwMap (HashSet retainedTypeKeys) + List LoadJavaTypesFromAcwMap (HashSet retainedTypeKeys) { - var javaTypes = new SortedSet (StringComparer.Ordinal); + var javaTypes = new List (); foreach (var line in File.ReadLines (AcwMapFile)) { var separator = line.IndexOf (';'); if (separator <= 0 || separator == line.Length - 1) { @@ -61,7 +61,7 @@ SortedSet LoadJavaTypesFromAcwMap (HashSet retainedTypeKeys) } var managedTypeName = line.Substring (0, separator); var javaTypeName = line.Substring (separator + 1); - if (retainedTypeKeys.Contains (managedTypeName)) { + if (retainedTypeKeys.Contains (managedTypeName) && !javaTypes.Contains (javaTypeName)) { javaTypes.Add (javaTypeName); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateProguardConfiguration.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateProguardConfiguration.cs index 385ba9bd08f..6c3b683d6c5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateProguardConfiguration.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateProguardConfiguration.cs @@ -13,6 +13,7 @@ public class GenerateProguardConfiguration : AndroidTask { public override string TaskPrefix => "GPC"; + [Required] public ITaskItem[] LinkedAssemblies { get; set; } = []; [Required] diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/R8.cs b/src/Xamarin.Android.Build.Tasks/Tasks/R8.cs index 4412cfca893..ac91b59d705 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/R8.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/R8.cs @@ -114,7 +114,7 @@ protected override string CreateResponseFile () if (!ProguardCommonXamarinConfiguration.IsNullOrWhiteSpace ()) { using (var xamcfg = File.CreateText (ProguardCommonXamarinConfiguration)) { if (UseTrimmableNativeAotProguardConfiguration) { - WriteTrimmableNativeAotCommonConfiguration (xamcfg); + GetType ().Assembly.GetManifestResourceStream ("proguard_trimmable_nativeaot.cfg").CopyTo (xamcfg.BaseStream); } else { GetType ().Assembly.GetManifestResourceStream ("proguard_xamarin.cfg").CopyTo (xamcfg.BaseStream); } @@ -166,25 +166,6 @@ protected override string CreateResponseFile () return responseFile; } - static void WriteTrimmableNativeAotCommonConfiguration (TextWriter writer) - { - writer.WriteLine ("# Xamarin.Android NativeAOT trimmable typemap configuration."); - writer.WriteLine (); - writer.WriteLine ("-dontobfuscate"); - writer.WriteLine (); - writer.WriteLine ("-keep class net.dot.jni.** { *; (...); }"); - writer.WriteLine ("-keep class net.dot.android.crypto.** { *; (...); }"); - writer.WriteLine (); - writer.WriteLine ("-keepclassmembers class * extends android.view.View {"); - writer.WriteLine (" *** set*(...);"); - writer.WriteLine ("}"); - writer.WriteLine (); - writer.WriteLine ("-keepclassmembers class * extends android.view.View {"); - writer.WriteLine (" (android.content.Context,android.util.AttributeSet);"); - writer.WriteLine (" (android.content.Context,android.util.AttributeSet,int);"); - writer.WriteLine ("}"); - } - // Note: We do not want to call the base.LogEventsFromTextOutput as it will incorrectly identify // Warnings and Info messages as errors. protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance) From e3d85aabc115dc3bef238ec32757844bf58084ac Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 22 May 2026 11:07:41 +0200 Subject: [PATCH 5/7] [TrimmableTypeMap] Enable R8 by default for NativeAOT Default NativeAOT trimmable typemap builds to AndroidLinkTool=r8 so the generated DGML-based keep rules are active without requiring users to opt in manually. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets index 3101aeefd1b..059ec8dbe38 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets @@ -6,6 +6,10 @@ <_TrimmableRuntimeProviderJavaName Condition=" '$(_TrimmableRuntimeProviderJavaName)' == '' ">net.dot.jni.nativeaot.NativeAotRuntimeProvider + r8 + d8 + True + True true <_UseTrimmableNativeAotProguardConfiguration>true From 3d4e1cd0789455c187ece8f42f98d7fe2f1bdc9c Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 22 May 2026 11:14:35 +0200 Subject: [PATCH 6/7] [TrimmableTypeMap] Address ProGuard review comments Tolerate the no-input typemap generation case by creating an empty assembly list, avoid nested framework reference scans, and disable XML resolver use when reading ILC DGML. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Scanner/JavaPeerScanner.cs | 6 +++--- .../Microsoft.Android.Sdk.TypeMap.Trimmable.targets | 7 +++++++ .../Tasks/GenerateNativeAotProguardConfiguration.cs | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/JavaPeerScanner.cs b/src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/JavaPeerScanner.cs index 884f95521db..9865283360a 100644 --- a/src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/JavaPeerScanner.cs +++ b/src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/JavaPeerScanner.cs @@ -121,9 +121,9 @@ void MarkFrameworkArrayEntryPeers (IEnumerable peers) if (frameworkAssemblyNames.Contains (index.AssemblyName)) { continue; } - foreach (var frameworkAssemblyName in frameworkAssemblyNames) { - if (index.ReferencedTypeNamesByAssembly.TryGetValue (frameworkAssemblyName, out var typeNames)) { - referencedFrameworkTypes.UnionWith (typeNames); + foreach (var referencedTypeNames in index.ReferencedTypeNamesByAssembly) { + if (frameworkAssemblyNames.Contains (referencedTypeNames.Key)) { + referencedFrameworkTypes.UnionWith (referencedTypeNames.Value); } } } diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets index b040052577f..175c0496618 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets @@ -125,6 +125,13 @@ + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs index 83620408b9e..a803edf5fed 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeAotProguardConfiguration.cs @@ -73,6 +73,7 @@ HashSet LoadRetainedTypeKeysFromDgml () var typeKeys = new HashSet (StringComparer.Ordinal); using var reader = XmlReader.Create (NativeAotDgmlFile, new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit, + XmlResolver = null, }); while (reader.Read ()) { From a5277f47c6ea56e15ab7a370a7b868978d1b7382 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 20:08:13 +0000 Subject: [PATCH 7/7] Fix NativeAOT typemap entrypoint filtering Agent-Logs-Url: https://github.com/dotnet/android/sessions/91b096b3-9ab7-4980-8234-097a0c3caca5 Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com> --- ...droid.Sdk.TypeMap.Trimmable.NativeAOT.targets | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets index 059ec8dbe38..c7e11fec47e 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets @@ -22,21 +22,21 @@ DependsOnTargets="_ReadGeneratedTrimmableTypeMapAssemblies"> <_TrimmableTypeMapIlcAssemblies Include="@(_GeneratedTypeMapAssembliesFromList)" /> - <_TrimmableTypeMapFrameworkIlcAssemblies Include="@(ResolvedFrameworkAssemblies->'$(_TypeMapOutputDirectory)_%(Filename).TypeMap.dll')" /> - <_TrimmableTypeMapFrameworkIlcAssemblies Include="@(PrivateSdkAssemblies->'$(_TypeMapOutputDirectory)_%(Filename).TypeMap.dll')" /> - <_TrimmableTypeMapFrameworkIlcAssemblies Include="@(ReferencePath->'$(_TypeMapOutputDirectory)_%(Filename).TypeMap.dll')" + <_TrimmableTypeMapFrameworkIlcAssemblyNames Include="@(ResolvedFrameworkAssemblies->'_%(Filename).TypeMap')" /> + <_TrimmableTypeMapFrameworkIlcAssemblyNames Include="@(PrivateSdkAssemblies->'_%(Filename).TypeMap')" /> + <_TrimmableTypeMapFrameworkIlcAssemblyNames Include="@(ReferencePath->'_%(Filename).TypeMap')" Condition=" '%(ReferencePath.FrameworkAssembly)' == 'true' " /> - <_TrimmableTypeMapUnmanagedEntryPointAssemblies Include="@(_TrimmableTypeMapIlcAssemblies)" /> - <_TrimmableTypeMapUnmanagedEntryPointAssemblies Remove="$(_TypeMapOutputDirectory)$(_TypeMapAssemblyName).dll" /> - <_TrimmableTypeMapUnmanagedEntryPointAssemblies Remove="$(_TypeMapOutputDirectory)_Java.Interop.TypeMap.dll;$(_TypeMapOutputDirectory)_Mono.Android.TypeMap.dll" /> - <_TrimmableTypeMapUnmanagedEntryPointAssemblies Remove="@(_TrimmableTypeMapFrameworkIlcAssemblies)" /> + <_TrimmableTypeMapUnmanagedEntryPointAssemblyNames Include="@(_TrimmableTypeMapIlcAssemblies->'%(Filename)')" /> + <_TrimmableTypeMapUnmanagedEntryPointAssemblyNames Remove="$(_TypeMapAssemblyName)" /> + <_TrimmableTypeMapUnmanagedEntryPointAssemblyNames Remove="_Java.Interop.TypeMap;_Mono.Android.TypeMap" /> + <_TrimmableTypeMapUnmanagedEntryPointAssemblyNames Remove="@(_TrimmableTypeMapFrameworkIlcAssemblyNames)" /> - +