diff --git a/src/Microsoft.Android.Sdk.ILLink/StripEmbeddedLibraries.cs b/src/Microsoft.Android.Sdk.ILLink/StripEmbeddedLibraries.cs deleted file mode 100644 index 041bead3f92..00000000000 --- a/src/Microsoft.Android.Sdk.ILLink/StripEmbeddedLibraries.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Mono.Cecil; -using Mono.Linker; -using Mono.Linker.Steps; -using System; -using System.Linq; -using Xamarin.Android.Tasks; - -namespace MonoDroid.Tuner -{ - public class StripEmbeddedLibraries : BaseStep - { - protected override void ProcessAssembly (AssemblyDefinition assembly) - { - if (!Annotations.HasAction (assembly)) - return; - var action = Annotations.GetAction (assembly); - if (action == AssemblyAction.Skip || action == AssemblyAction.Delete) - return; - - if (MonoAndroidHelper.IsFrameworkAssembly (assembly)) - return; - bool assembly_modified = false; - foreach (var mod in assembly.Modules) { - foreach (var r in mod.Resources.ToArray ()) { - if (ShouldStripResource (r)) { - Context.LogMessage ($" Stripped {r.Name} from {assembly.Name.Name}.dll"); - mod.Resources.Remove (r); - assembly_modified = true; - } - } - } - if (assembly_modified && action == AssemblyAction.Copy) { - Annotations.SetAction (assembly, AssemblyAction.Save); - } - } - - bool ShouldStripResource (Resource r) - { - if (!(r is EmbeddedResource)) - return false; - // embedded jars - if (r.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase)) - return true; - // embedded AndroidNativeLibrary archive - if (r.Name == "__AndroidNativeLibraries__.zip") - return true; - // embedded AndroidResourceLibrary archive - if (r.Name == "__AndroidLibraryProjects__.zip") - return true; - // embedded AndroidEnvironment item - if (r.Name.StartsWith ("__AndroidEnvironment__", StringComparison.Ordinal)) - return true; - return false; - } - } -} 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 68fd6b77705..4be55630c91 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 @@ -7,6 +7,7 @@ + <_RemoveRegisterFlag>$(MonoAndroidIntermediateAssemblyDir)shrunk\shrunk.flag @@ -203,7 +204,6 @@ Type="MonoDroid.Tuner.AddKeepAlivesStep" /> - <_TrimmerCustomSteps Include="$(_AndroidLinkerCustomStepAssembly)" AfterStep="CleanStep" Type="MonoDroid.Tuner.StripEmbeddedLibraries" /> <_TrimmerCustomSteps Condition=" '$(AndroidLinkResources)' == 'true' " Include="$(_AndroidLinkerCustomStepAssembly)" @@ -250,6 +250,22 @@ + + + + <_StripEmbeddedLibrariesAssembly Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " /> + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/StripEmbeddedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/StripEmbeddedLibraries.cs new file mode 100644 index 00000000000..7a65c4a8145 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/StripEmbeddedLibraries.cs @@ -0,0 +1,116 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Mono.Cecil; + +namespace Xamarin.Android.Tasks; + +/// +/// An MSBuild task that strips embedded Android resources (.jar, __AndroidNativeLibraries__.zip, +/// __AndroidLibraryProjects__.zip, __AndroidEnvironment__) from trimmed assemblies. +/// +/// This runs in the inner build after ILLink but before ReadyToRun/crossgen2 compilation, +/// so that R2R images are generated from the already-stripped assemblies. +/// +public class StripEmbeddedLibraries : AndroidTask +{ + public override string TaskPrefix => "SEL"; + + [Required] + public ITaskItem [] Assemblies { get; set; } = []; + + public bool Deterministic { get; set; } + + public override bool RunTask () + { + var resolver = new DefaultAssemblyResolver (); + var searchDirectories = new HashSet (StringComparer.OrdinalIgnoreCase); + + foreach (var assembly in Assemblies) { + var dir = Path.GetFullPath (Path.GetDirectoryName (assembly.ItemSpec) ?? ""); + if (searchDirectories.Add (dir)) { + resolver.AddSearchDirectory (dir); + } + } + + try { + foreach (var assembly in Assemblies) { + if (MonoAndroidHelper.IsFrameworkAssembly (assembly)) { + continue; + } + + StripAssembly (assembly.ItemSpec, resolver); + } + } finally { + resolver.Dispose (); + } + + return !Log.HasLoggedErrors; + } + + void StripAssembly (string assemblyPath, IAssemblyResolver resolver) + { + string pdbPath = Path.ChangeExtension (assemblyPath, ".pdb"); + bool havePdb = File.Exists (pdbPath); + + var readerParams = new ReaderParameters { + ReadSymbols = havePdb, + ReadWrite = true, + AssemblyResolver = resolver, + }; + + bool assembly_modified = false; + + using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath, readerParams)) { + foreach (var module in assembly.Modules) { + foreach (var resource in module.Resources.ToArray ()) { + if (ShouldStripResource (resource)) { + Log.LogDebugMessage ($" Stripped {resource.Name} from {assembly.Name.Name}.dll"); + module.Resources.Remove (resource); + assembly_modified = true; + } + } + } + + if (!assembly_modified) { + return; + } + + Log.LogDebugMessage ($" Writing stripped assembly: {assemblyPath}"); + assembly.Write (new WriterParameters { + WriteSymbols = havePdb, + DeterministicMvid = Deterministic, + }); + } + } + + /// + /// Determines whether a resource should be stripped from the assembly. + /// Matches the same criteria as the old ILLink StripEmbeddedLibraries step. + /// + internal static bool ShouldStripResource (Resource resource) + { + if (!(resource is EmbeddedResource)) + return false; + // Embedded jars + if (resource.Name.EndsWith (".jar", StringComparison.InvariantCultureIgnoreCase)) + return true; + // Embedded AndroidNativeLibrary archive + if (resource.Name == "__AndroidNativeLibraries__.zip") + return true; + // Embedded AndroidResourceLibrary archive + if (resource.Name == "__AndroidLibraryProjects__.zip") + return true; + // Embedded AndroidEnvironment items + if (resource.Name.StartsWith ("__AndroidEnvironment__", StringComparison.Ordinal)) + return true; + return false; + } + +}