From a09887760ea113a9fd124647439824b0974496f4 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 27 Mar 2026 11:24:07 -0700 Subject: [PATCH 1/3] Move RemoveResourceDesignerStep from ILLink custom step to PostTrimmingPipeline Migrate RemoveResourceDesignerStep out of the ILLink custom step pipeline and into PostTrimmingPipeline so it runs as an IAssemblyModifierPipelineStep after trimming. This follows the same pattern as FixLegacyResourceDesignerStep. - Add IAssemblyModifierPipelineStep to RemoveResourceDesignerStep - Add constructor accepting assemblies list and logging delegate - Remove GetAssembliesStep (no longer needed; assemblies passed directly) - Remove both _TrimmerCustomSteps entries from targets - Add AndroidLinkResources property to PostTrimmingPipeline task --- .../GetAssembliesStep.cs | 28 ------------- .../Microsoft.Android.Sdk.ILLink.csproj | 1 - .../RemoveResourceDesignerStep.cs | 40 +++++++++++-------- ...crosoft.Android.Sdk.TypeMap.LlvmIr.targets | 13 +----- .../Tasks/PostTrimmingPipeline.cs | 9 +++++ 5 files changed, 33 insertions(+), 58 deletions(-) delete mode 100644 src/Microsoft.Android.Sdk.ILLink/GetAssembliesStep.cs diff --git a/src/Microsoft.Android.Sdk.ILLink/GetAssembliesStep.cs b/src/Microsoft.Android.Sdk.ILLink/GetAssembliesStep.cs deleted file mode 100644 index 7721dc05151..00000000000 --- a/src/Microsoft.Android.Sdk.ILLink/GetAssembliesStep.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Mono.Cecil; -using Mono.Linker; -using Mono.Linker.Steps; -using System; -using System.Linq; -using Xamarin.Android.Tasks; -using System.Collections.Generic; -using Mono.Cecil.Cil; - -namespace MonoDroid.Tuner -{ - public class GetAssembliesStep : BaseStep - { - AndroidLinkConfiguration config = null; - - protected override void Process () - { - config = AndroidLinkConfiguration.GetInstance (Context); - } - - protected override void ProcessAssembly (AssemblyDefinition assembly) - { - if (config == null) - return; - config.Assemblies.Add (assembly); - } - } -} diff --git a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj index 92c92c0ee94..26d2067d1fc 100644 --- a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj +++ b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj @@ -19,7 +19,6 @@ - diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/RemoveResourceDesignerStep.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/RemoveResourceDesignerStep.cs index c5a34887a0f..04d5c2357e7 100644 --- a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/RemoveResourceDesignerStep.cs +++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/RemoveResourceDesignerStep.cs @@ -9,13 +9,10 @@ using System.Collections.Generic; using Mono.Cecil.Cil; using System.Text.RegularExpressions; -#if ILLINK -using Microsoft.Android.Sdk.ILLink; -#endif namespace MonoDroid.Tuner { - public class RemoveResourceDesignerStep : LinkDesignerBase + public class RemoveResourceDesignerStep : LinkDesignerBase, IAssemblyModifierPipelineStep { TypeDefinition mainDesigner = null; AssemblyDefinition mainAssembly = null; @@ -23,15 +20,32 @@ public class RemoveResourceDesignerStep : LinkDesignerBase Dictionary designerConstants; Regex opCodeRegex = new Regex (@"([\w]+): ([\w]+) ([\w.]+) ([\w:./]+)"); + IList allAssemblies; + Action log; + + public RemoveResourceDesignerStep (IList allAssemblies, Action logger) + { + this.allAssemblies = allAssemblies; + this.log = logger; + } + + public override void LogMessage (string message) + { + log (message); + } + + public void ProcessAssembly (AssemblyDefinition assembly, StepContext context) + { + LoadDesigner (); + context.IsAssemblyModified |= ProcessAssemblyDesigner (assembly); + } + protected override void LoadDesigner () { if (mainAssembly != null) return; // resolve the MainAssembly Resource designer TypeDefinition - AndroidLinkConfiguration config = AndroidLinkConfiguration.GetInstance (Context); - if (config == null) - return; - foreach(var asm in config.Assemblies) { + foreach(var asm in allAssemblies) { if (FindResourceDesigner (asm, mainApplication: true, designer: out mainDesigner, designerAttribute: out mainDesignerAttribute)) { mainAssembly = asm; break; @@ -45,14 +59,6 @@ protected override void LoadDesigner () designerConstants = BuildResourceDesignerFieldLookup (mainDesigner); } - protected override void EndProcess () - { - if (mainDesigner != null) { - LogMessage ($" Setting Action on {mainAssembly.Name} to Save."); - Annotations.SetAction (mainAssembly, AssemblyAction.Save); - } - } - protected override void FixBody (MethodBody body, TypeDefinition designer) { Dictionary instructions = new Dictionary(); @@ -100,7 +106,7 @@ internal override bool ProcessAssemblyDesigner (AssemblyDefinition assembly) if (assembly != mainAssembly) { LogMessage ($" {assembly.Name.Name} is not the main assembly. "); if (!FindResourceDesigner (assembly, mainApplication: false, designer: out localDesigner, designerAttribute: out designerAttribute)) { - Context.LogMessage ($" {assembly.Name.Name} does not have a designer file."); + LogMessage ($" {assembly.Name.Name} does not have a designer file."); return false; } } else { 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 84e68d8bf6f..9b8870a8295 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 @@ -198,18 +198,6 @@ <_TrimmerCustomSteps Include="$(_AndroidLinkerCustomStepAssembly)" Type="MonoDroid.Tuner.FixAbstractMethodsStep" /> - <_TrimmerCustomSteps - Condition=" '$(AndroidLinkResources)' == 'true' " - Include="$(_AndroidLinkerCustomStepAssembly)" - AfterStep="CleanStep" - Type="MonoDroid.Tuner.RemoveResourceDesignerStep" - /> - <_TrimmerCustomSteps - Condition=" '$(AndroidLinkResources)' == 'true' " - Include="$(_AndroidLinkerCustomStepAssembly)" - AfterStep="CleanStep" - Type="MonoDroid.Tuner.GetAssembliesStep" - /> <_TrimmerCustomSteps Condition=" '$(AndroidUseDesignerAssembly)' == 'true' " Include="$(_AndroidLinkerCustomStepAssembly)" @@ -259,6 +247,7 @@ diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs index 7a33ea3c7be..4d02fc8c4b4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs @@ -29,6 +29,8 @@ public class PostTrimmingPipeline : AndroidTask public bool AddKeepAlives { get; set; } + public bool AndroidLinkResources { get; set; } + public bool Deterministic { get; set; } public override bool RunTask () @@ -47,6 +49,13 @@ public override bool RunTask () var steps = new List (); steps.Add (new StripEmbeddedLibrariesStep (Log)); + if (AndroidLinkResources) { + var allAssemblies = new List (Assemblies.Length); + foreach (var item in Assemblies) { + allAssemblies.Add (resolver.GetAssembly (item.ItemSpec)); + } + steps.Add (new RemoveResourceDesignerStep (allAssemblies, (msg) => Log.LogDebugMessage (msg))); + } if (AddKeepAlives) { // Memoize the corlib resolution so the attempt (and any error logging) happens at most once, // regardless of how many assemblies/methods need KeepAlive injection. From 14ca98ddcd337ef2b540571a174139a3a1056a7b Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 27 Mar 2026 12:13:35 -0700 Subject: [PATCH 2/3] Pre-load assemblies once in PostTrimmingPipeline to avoid redundant resolver calls Load all assemblies into a shared list upfront so that RemoveResourceDesignerStep and the per-assembly processing loop operate on the same AssemblyDefinition instances instead of calling resolver.GetAssembly() twice for each assembly. --- .../Tasks/PostTrimmingPipeline.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs index 4d02fc8c4b4..f5b16047e37 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs @@ -47,12 +47,19 @@ public override bool RunTask () } } + // Pre-load all assemblies once so that every step (and the processing loop) + // operates on the same AssemblyDefinition instances. + var loadedAssemblies = new List<(ITaskItem item, AssemblyDefinition assembly)> (Assemblies.Length); + foreach (var item in Assemblies) { + loadedAssemblies.Add ((item, resolver.GetAssembly (item.ItemSpec))); + } + var steps = new List (); steps.Add (new StripEmbeddedLibrariesStep (Log)); if (AndroidLinkResources) { - var allAssemblies = new List (Assemblies.Length); - foreach (var item in Assemblies) { - allAssemblies.Add (resolver.GetAssembly (item.ItemSpec)); + var allAssemblies = new List (loadedAssemblies.Count); + foreach (var (_, assembly) in loadedAssemblies) { + allAssemblies.Add (assembly); } steps.Add (new RemoveResourceDesignerStep (allAssemblies, (msg) => Log.LogDebugMessage (msg))); } @@ -76,8 +83,7 @@ public override bool RunTask () (msg) => Log.LogDebugMessage (msg))); } - foreach (var item in Assemblies) { - var assembly = resolver.GetAssembly (item.ItemSpec); + foreach (var (item, assembly) in loadedAssemblies) { var context = new StepContext (item, item); foreach (var step in steps) { step.ProcessAssembly (assembly, context); From 7aa0ff156bbe1f46d23945da19199fb56d1ab46c Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 30 Mar 2026 10:48:34 -0700 Subject: [PATCH 3/3] Remove duplicate AndroidLinkResources block from merge --- .../Tasks/PostTrimmingPipeline.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs index 9ba0d1b5bd1..f02aadec4ba 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs @@ -84,13 +84,6 @@ public override bool RunTask () }, (msg) => Log.LogDebugMessage (msg))); } - if (AndroidLinkResources) { - var allAssemblies = new List (Assemblies.Length); - foreach (var item in Assemblies) { - allAssemblies.Add (resolver.GetAssembly (item.ItemSpec)); - } - steps.Add (new RemoveResourceDesignerStep (allAssemblies, (msg) => Log.LogDebugMessage (msg))); - } foreach (var (item, assembly) in loadedAssemblies) { var context = new StepContext (item, item);