diff --git a/external/Java.Interop b/external/Java.Interop index cf80deb7d2a..1366d998c56 160000 --- a/external/Java.Interop +++ b/external/Java.Interop @@ -1 +1 @@ -Subproject commit cf80deb7d2ad3c79abfd0140e4adee4376b41af5 +Subproject commit 1366d998c5662c2ada9a069c7df4428b13f58175 diff --git a/src/Microsoft.Android.Sdk.ILLink/AssemblyResolverCoda.cs b/src/Microsoft.Android.Sdk.ILLink/AssemblyResolverCoda.cs new file mode 100644 index 00000000000..46b65d82a0c --- /dev/null +++ b/src/Microsoft.Android.Sdk.ILLink/AssemblyResolverCoda.cs @@ -0,0 +1,12 @@ +using Mono.Cecil; +using System.IO; + +namespace Java.Interop.Tools.Cecil; + +public static class AssemblyResolverCoda +{ + public static AssemblyDefinition GetAssembly (this IAssemblyResolver resolver, string fileName) + { + return resolver.Resolve (AssemblyNameReference.Parse (Path.GetFileNameWithoutExtension (fileName))); + } +} 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 aa8694c7a3c..7f2b7cea5fa 100644 --- a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj +++ b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj @@ -1,14 +1,18 @@  + $(DotNetTargetFramework) - ILLINK + true + ILLINK;HAVE_CECIL false $(MicrosoftAndroidSdkOutDir) + + @@ -45,6 +49,13 @@ + + + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/CalculateJavaStubHashStep.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/CalculateJavaStubHashStep.cs new file mode 100644 index 00000000000..17518d302fe --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/CalculateJavaStubHashStep.cs @@ -0,0 +1,83 @@ +using System; +using System.Buffers; +using System.Diagnostics; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Java.Interop.Tools.JavaCallableWrappers; +using Microsoft.Android.Build.Tasks; +using Mono.Cecil; +using Mono.Linker; +using Mono.Linker.Steps; + +#if ILLINK +using Microsoft.Android.Sdk.ILLink; +#endif // ILLINK + + +namespace MonoDroid.Tuner +{ + public class CalculateJavaStubHashStep : BaseStep + { +#if ILLINK + protected override void Process () + { + logger = (level, message) => Context.LogMessage ($"{level} {message}"); + cache = Context; + scanner = new JavaTypeScanner (logger, Context); + } +#else // !ILLINK + public CalculateJavaStubHashStep (Action logger, IMetadataResolver cache) + { + this.logger = logger; + this.cache = cache; + scanner = new JavaTypeScanner (logger, this.cache); + } +#endif // !ILLINK + + static readonly Encoding Encoding = Encoding.UTF8; + + Action logger; + IMetadataResolver cache; + JavaTypeScanner scanner; + string outputDirectory; + + public void Calculate (AssemblyDefinition assembly, string outputDirectory) + { + this.outputDirectory = outputDirectory; + ProcessAssembly (assembly); + } + + protected override void ProcessAssembly (AssemblyDefinition assembly) + { + HashAlgorithm hasher = new Microsoft.Android.Build.Tasks.Crc64 (); + foreach (var type in scanner.GetJavaTypes (assembly)) { + Hash (hasher, type.FullName); + + foreach (var method in type.Methods) { + Hash (hasher, method.Name); + } + } + + hasher.TransformFinalBlock (Array.Empty (), 0, 0); + + var assemblyFile = Path.GetFileName (assembly.MainModule.FileName); + var hashFile = Path.Combine (outputDirectory, $"{assemblyFile}.hash"); + if (Files.CopyIfStringChanged (Convert.ToBase64String (hasher.Hash), hashFile)) { + logger (TraceLevel.Verbose, $"Saved: {hashFile}"); + } + } + + static void Hash (HashAlgorithm hasher, string value) + { + int length = Encoding.GetByteCount (value); + var bytes = ArrayPool.Shared.Rent (length); + try { + Encoding.GetBytes (value, 0, value.Length, bytes, 0); + hasher.TransformBlock (bytes, 0, length, null, 0); + } finally { + ArrayPool.Shared.Return (bytes); + } + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs index 78804fcf315..9037e3a6c5a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkAssembliesNoShrink.cs @@ -4,6 +4,7 @@ using Microsoft.Build.Utilities; using Mono.Cecil; using System; +using System.Diagnostics; using System.IO; using Microsoft.Android.Build.Tasks; @@ -54,7 +55,8 @@ public override bool RunTask () DeterministicMvid = Deterministic, }; - using (var resolver = new DirectoryAssemblyResolver (this.CreateTaskLogger (), loadDebugSymbols: true, loadReaderParameters: readerParameters)) { + var logger = this.CreateTaskLogger (); + using (var resolver = new DirectoryAssemblyResolver (logger, loadDebugSymbols: true, loadReaderParameters: readerParameters)) { // Add SearchDirectories with ResolvedAssemblies foreach (var assembly in ResolvedAssemblies) { var path = Path.GetFullPath (Path.GetDirectoryName (assembly.ItemSpec)); @@ -67,6 +69,7 @@ public override bool RunTask () var fixAbstractMethodsStep = new FixAbstractMethodsStep (resolver, cache, Log); var addKeepAliveStep = new AddKeepAlivesStep (resolver, cache, Log, UsingAndroidNETSdk); var fixLegacyResourceDesignerStep = new FixLegacyResourceDesignerStep (resolver, Log); + var javaStubHashStep = new MonoDroid.Tuner.CalculateJavaStubHashStep (logger, cache); for (int i = 0; i < SourceFiles.Length; i++) { var source = SourceFiles [i]; var destination = DestinationFiles [i]; @@ -89,16 +92,16 @@ public override bool RunTask () fixAbstractMethodsStep.CheckAppDomainUsage (assemblyDefinition, (string msg) => Log.LogCodedWarning ("XA2000", msg)); } - // Only run the step on "MonoAndroid" assemblies + // Only run the following step(s) on "MonoAndroid" assemblies if (MonoAndroidHelper.IsMonoAndroidAssembly (source) && !MonoAndroidHelper.IsSharedRuntimeAssembly (source.ItemSpec)) { - if (assemblyDefinition == null) - assemblyDefinition = resolver.GetAssembly (source.ItemSpec); + assemblyDefinition ??= resolver.GetAssembly (source.ItemSpec); bool save = fixAbstractMethodsStep.FixAbstractMethods (assemblyDefinition); if (UseDesignerAssembly) save |= fixLegacyResourceDesignerStep.ProcessAssemblyDesigner (assemblyDefinition); if (AddKeepAlives) save |= addKeepAliveStep.AddKeepAlives (assemblyDefinition); + javaStubHashStep.Calculate (assemblyDefinition, Path.GetDirectoryName (destination.ItemSpec)); if (save) { Log.LogDebugMessage ($"Saving modified assembly: {destination.ItemSpec}"); writerParameters.WriteSymbols = assemblyDefinition.MainModule.HasSymbols; diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 14418bb0e23..c7c7dc80738 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1496,6 +1496,8 @@ because xbuild doesn't support framework reference assemblies. UsingAndroidNETSdk="$(UsingAndroidNETSdk)" /> + <_AllJavaStubHashFile Include="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath).hash')" /> + <_JavaStubHashFile Include="@(_AllJavaStubHashFile)" Condition="Exists('%(_AllJavaStubHashFile.Identity)')" /> @@ -1525,7 +1527,7 @@ because xbuild doesn't support framework reference assemblies.