From f3dfe900362a56d253d3ed8a1d060c372be37a18 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 3 Oct 2024 21:53:13 +0200 Subject: [PATCH 01/60] Embed some data files in `libxamarin-app.so` --- .../Tasks/GeneratePackageManagerJava.cs | 359 +++++++++++++++++- .../Utilities/DSOWrapperGenerator.cs | 2 +- .../Utilities/MonoAndroidHelper.cs | 21 +- .../Xamarin.Android.Common.targets | 33 +- 4 files changed, 387 insertions(+), 28 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index a82c4c0408f..91e5e21ab27 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -30,10 +30,242 @@ public override bool RunTask () pkgmgr.WriteLine ("public class MonoPackageManager_Resources {"); pkgmgr.WriteLine ("\tpublic static String[] Assemblies = new String[]{"); - pkgmgr.WriteLine ("\t\t/* We need to ensure that \"{0}\" comes first in this list. */", mainFileName); - pkgmgr.WriteLine ("\t\t\"" + mainFileName + "\","); - foreach (var assembly in ResolvedUserAssemblies) { - if (string.Compare (Path.GetFileName (assembly.ItemSpec), mainFileName, StringComparison.OrdinalIgnoreCase) == 0) + public ITaskItem[] NativeLibraries { get; set; } + + public ITaskItem[] MonoComponents { get; set; } + + public ITaskItem[] SatelliteAssemblies { get; set; } + + public bool UseAssemblyStore { get; set; } + + [Required] + public string OutputDirectory { get; set; } + + [Required] + public string EnvironmentOutputDirectory { get; set; } + + [Required] + public string MainAssembly { get; set; } + + [Required] + public string TargetFrameworkVersion { get; set; } + + [Required] + public string Manifest { get; set; } + + [Required] + public string [] SupportedAbis { get; set; } + + [Required] + public string AndroidPackageName { get; set; } + + [Required] + public bool EnablePreloadAssembliesDefault { get; set; } + + [Required] + public string AndroidBinUtilsDirectory { get; set; } + + public bool EnableMarshalMethods { get; set; } + public string RuntimeConfigBinFilePath { get; set; } + public string BoundExceptionType { get; set; } + + public string PackageNamingPolicy { get; set; } + public string Debug { get; set; } + public ITaskItem[] Environments { get; set; } + public string AndroidAotMode { get; set; } + public bool AndroidAotEnableLazyLoad { get; set; } + public bool EnableLLVM { get; set; } + public string HttpClientHandlerType { get; set; } + public string TlsProvider { get; set; } + public string AndroidSequencePointsMode { get; set; } + public bool EnableSGenConcurrent { get; set; } + public string? CustomBundleConfigFile { get; set; } + + bool _Debug { + get { + return string.Equals (Debug, "true", StringComparison.OrdinalIgnoreCase); + } + } + + public override bool RunTask () + { + var doc = AndroidAppManifest.Load (Manifest, MonoAndroidHelper.SupportedVersions); + int minApiVersion = doc.MinSdkVersion == null ? 4 : (int) doc.MinSdkVersion; + // We need to include any special assemblies in the Assemblies list + var mainFileName = Path.GetFileName (MainAssembly); + + using (var pkgmgr = MemoryStreamPool.Shared.CreateStreamWriter ()) { + pkgmgr.WriteLine ("package mono;"); + + // Write all the user assemblies + pkgmgr.WriteLine ("public class MonoPackageManager_Resources {"); + pkgmgr.WriteLine ("\tpublic static String[] Assemblies = new String[]{"); + + pkgmgr.WriteLine ("\t\t/* We need to ensure that \"{0}\" comes first in this list. */", mainFileName); + pkgmgr.WriteLine ("\t\t\"" + mainFileName + "\","); + foreach (var assembly in ResolvedUserAssemblies) { + if (string.Compare (Path.GetFileName (assembly.ItemSpec), mainFileName, StringComparison.OrdinalIgnoreCase) == 0) + continue; + pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly.ItemSpec) + "\","); + } + foreach (var assembly in MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies (ResolvedAssemblies)) { + if (string.Compare (Path.GetFileName (assembly.ItemSpec), mainFileName, StringComparison.OrdinalIgnoreCase) == 0) + continue; + pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly.ItemSpec) + "\","); + } + + // Write the assembly dependencies + pkgmgr.WriteLine ("\t};"); + pkgmgr.WriteLine ("\tpublic static String[] Dependencies = new String[]{"); + + //foreach (var assembly in assemblies.Except (args.Assemblies)) { + // if (args.SharedRuntime && !Toolbox.IsInSharedRuntime (assembly)) + // pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly) + "\","); + //} + + pkgmgr.WriteLine ("\t};"); + + pkgmgr.WriteLine ("}"); + pkgmgr.Flush (); + + // Only copy to the real location if the contents actually changed + var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "MonoPackageManager_Resources.java")); + + Files.CopyIfStreamChanged (pkgmgr.BaseStream, dest); + } + + AddEnvironment (); + + return !Log.HasLoggedErrors; + } + + static internal AndroidTargetArch GetAndroidTargetArchForAbi (string abi) => MonoAndroidHelper.AbiToTargetArch (abi); + + static readonly string[] defaultLogLevel = {"MONO_LOG_LEVEL", "info"}; + static readonly string[] defaultMonoDebug = {"MONO_DEBUG", "gen-compact-seq-points"}; + static readonly string[] defaultHttpMessageHandler = {"XA_HTTP_CLIENT_HANDLER_TYPE", "System.Net.Http.HttpClientHandler, System.Net.Http"}; + static readonly string[] defaultTlsProvider = {"XA_TLS_PROVIDER", "btls"}; + + void AddEnvironment () + { + bool usesMonoAOT = false; + var environmentVariables = new Dictionary (StringComparer.Ordinal); + var systemProperties = new Dictionary (StringComparer.Ordinal); + + if (!Enum.TryParse (PackageNamingPolicy, out PackageNamingPolicy pnp)) { + pnp = PackageNamingPolicyEnum.LowercaseCrc64; + } + + AotMode aotMode = AotMode.None; + if (!string.IsNullOrEmpty (AndroidAotMode) && Aot.GetAndroidAotMode (AndroidAotMode, out aotMode) && aotMode != AotMode.None) { + usesMonoAOT = true; + } + + SequencePointsMode sequencePointsMode; + if (!Aot.TryGetSequencePointsMode (AndroidSequencePointsMode, out sequencePointsMode)) + sequencePointsMode = SequencePointsMode.None; + + // Even though environment files were potentially parsed in GenerateJavaStubs, we need to do it here again because we might have additional environment + // files (generated by us) which weren't present by the time GeneratJavaStubs ran. + var environmentParser = new EnvironmentFilesParser { + BrokenExceptionTransitions = false, + UsesAssemblyPreload = EnablePreloadAssembliesDefault, + }; + environmentParser.Parse (Environments, sequencePointsMode, Log); + + foreach (string line in environmentParser.EnvironmentVariableLines) { + AddEnvironmentVariableLine (line); + } + + if (_Debug && !environmentParser.HaveLogLevel) { + AddEnvironmentVariable (defaultLogLevel[0], defaultLogLevel[1]); + } + + if (sequencePointsMode != SequencePointsMode.None && !environmentParser.HaveMonoDebug) { + AddEnvironmentVariable (defaultMonoDebug[0], defaultMonoDebug[1]); + } + + if (!environmentParser.HaveHttpMessageHandler) { + if (HttpClientHandlerType == null) + AddEnvironmentVariable (defaultHttpMessageHandler[0], defaultHttpMessageHandler[1]); + else + AddEnvironmentVariable ("XA_HTTP_CLIENT_HANDLER_TYPE", HttpClientHandlerType.Trim ()); + } + + if (!environmentParser.HaveMonoGCParams) { + if (EnableSGenConcurrent) + AddEnvironmentVariable ("MONO_GC_PARAMS", "major=marksweep-conc"); + else + AddEnvironmentVariable ("MONO_GC_PARAMS", "major=marksweep"); + } + + global::Android.Runtime.BoundExceptionType boundExceptionType; + if (String.IsNullOrEmpty (BoundExceptionType) || String.Compare (BoundExceptionType, "System", StringComparison.OrdinalIgnoreCase) == 0) { + boundExceptionType = global::Android.Runtime.BoundExceptionType.System; + } else if (String.Compare (BoundExceptionType, "Java", StringComparison.OrdinalIgnoreCase) == 0) { + boundExceptionType = global::Android.Runtime.BoundExceptionType.Java; + } else { + throw new InvalidOperationException ($"Unsupported BoundExceptionType value '{BoundExceptionType}'"); + } + + int assemblyNameWidth = 0; + Encoding assemblyNameEncoding = Encoding.UTF8; + + Action updateNameWidth = (ITaskItem assembly) => { + if (UseAssemblyStore) { + return; + } + + string assemblyName = Path.GetFileName (assembly.ItemSpec); + int nameBytes = assemblyNameEncoding.GetBytes (assemblyName).Length; + if (nameBytes > assemblyNameWidth) { + assemblyNameWidth = nameBytes; + } + }; + + int assemblyCount = 0; + bool enableMarshalMethods = EnableMarshalMethods; + HashSet archAssemblyNames = null; + HashSet uniqueAssemblyNames = new HashSet (StringComparer.OrdinalIgnoreCase); + Action updateAssemblyCount = (ITaskItem assembly) => { + string? culture = MonoAndroidHelper.GetAssemblyCulture (assembly); + string fileName = Path.GetFileName (assembly.ItemSpec); + string assemblyName; + + if (String.IsNullOrEmpty (culture)) { + assemblyName = fileName; + } else { + assemblyName = $"{culture}/{fileName}"; + } + + if (!uniqueAssemblyNames.Contains (assemblyName)) { + uniqueAssemblyNames.Add (assemblyName); + } + + string abi = MonoAndroidHelper.GetAssemblyAbi (assembly); + archAssemblyNames ??= new HashSet (StringComparer.OrdinalIgnoreCase); + + if (!archAssemblyNames.Contains (assemblyName)) { + assemblyCount++; + archAssemblyNames.Add (assemblyName); + } + }; + + if (SatelliteAssemblies != null) { + foreach (ITaskItem assembly in SatelliteAssemblies) { + updateNameWidth (assembly); + updateAssemblyCount (assembly); + } + } + + int android_runtime_jnienv_class_token = -1; + int jnienv_initialize_method_token = -1; + int jnienv_registerjninatives_method_token = -1; + foreach (var assembly in ResolvedAssemblies) { + updateNameWidth (assembly); + updateAssemblyCount (assembly); + + if (android_runtime_jnienv_class_token != -1) { continue; pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly.ItemSpec) + "\","); } @@ -55,7 +287,124 @@ public override bool RunTask () // Only copy to the real location if the contents actually changed var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "MonoPackageManager_Resources.java")); - Files.CopyIfStreamChanged (pkgmgr.BaseStream, dest); + bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); + if (haveRuntimeConfigBlob) { + List objectFilePaths = ELFEmbeddingHelper.EmbedBinary ( + Log, + SupportedAbis, + AndroidBinUtilsDirectory, + RuntimeConfigBinFilePath, + ELFEmbeddingHelper.KnownEmbedItems.RuntimeConfig, + EnvironmentOutputDirectory + ); + } + + var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); + var appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { + UsesMonoAOT = usesMonoAOT, + UsesMonoLLVM = EnableLLVM, + UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, + MonoAOTMode = aotMode.ToString ().ToLowerInvariant (), + AotEnableLazyLoad = AndroidAotEnableLazyLoad, + AndroidPackageName = AndroidPackageName, + BrokenExceptionTransitions = environmentParser.BrokenExceptionTransitions, + PackageNamingPolicy = pnp, + BoundExceptionType = boundExceptionType, + JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.Template != null ? NativeCodeGenState.Template.JniAddNativeMethodRegistrationAttributePresent : false, + HaveRuntimeConfigBlob = haveRuntimeConfigBlob, + NumberOfAssembliesInApk = assemblyCount, + BundledAssemblyNameWidth = assemblyNameWidth, + MonoComponents = (MonoComponent)monoComponents, + NativeLibraries = uniqueNativeLibraries, + HaveAssemblyStore = UseAssemblyStore, + AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, + JNIEnvInitializeToken = jnienv_initialize_method_token, + JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, + JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, + JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, + MarshalMethodsEnabled = EnableMarshalMethods, + IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), + }; + LLVMIR.LlvmIrModule appConfigModule = appConfigAsmGen.Construct (); + + foreach (string abi in SupportedAbis) { + string targetAbi = abi.ToLowerInvariant (); + string environmentBaseAsmFilePath = Path.Combine (EnvironmentOutputDirectory, $"environment.{targetAbi}"); + string marshalMethodsBaseAsmFilePath = Path.Combine (EnvironmentOutputDirectory, $"marshal_methods.{targetAbi}"); + string environmentLlFilePath = $"{environmentBaseAsmFilePath}.ll"; + string marshalMethodsLlFilePath = $"{marshalMethodsBaseAsmFilePath}.ll"; + AndroidTargetArch targetArch = GetAndroidTargetArchForAbi (abi); + + using var appConfigWriter = MemoryStreamPool.Shared.CreateStreamWriter (); + try { + appConfigAsmGen.Generate (appConfigModule, targetArch, appConfigWriter, environmentLlFilePath); + } catch { + throw; + } finally { + appConfigWriter.Flush (); + Files.CopyIfStreamChanged (appConfigWriter.BaseStream, environmentLlFilePath); + } + + MarshalMethodsNativeAssemblyGenerator marshalMethodsAsmGen; + if (enableMarshalMethods) { + marshalMethodsAsmGen = new MarshalMethodsNativeAssemblyGenerator ( + Log, + assemblyCount, + uniqueAssemblyNames, + EnsureCodeGenState (targetArch) + ); + } else { + marshalMethodsAsmGen = new MarshalMethodsNativeAssemblyGenerator ( + Log, + targetArch, + assemblyCount, + uniqueAssemblyNames + ); + } + + LLVMIR.LlvmIrModule marshalMethodsModule = marshalMethodsAsmGen.Construct (); + using var marshalMethodsWriter = MemoryStreamPool.Shared.CreateStreamWriter (); + try { + marshalMethodsAsmGen.Generate (marshalMethodsModule, targetArch, marshalMethodsWriter, marshalMethodsLlFilePath); + } catch { + throw; + } finally { + marshalMethodsWriter.Flush (); + Files.CopyIfStreamChanged (marshalMethodsWriter.BaseStream, marshalMethodsLlFilePath); + } + } + + NativeCodeGenState EnsureCodeGenState (AndroidTargetArch targetArch) + { + if (nativeCodeGenStates == null || !nativeCodeGenStates.TryGetValue (targetArch, out NativeCodeGenState? state)) { + throw new InvalidOperationException ($"Internal error: missing native code generation state for architecture '{targetArch}'"); + } + + return state; + } + + void AddEnvironmentVariable (string name, string value) + { + if (Char.IsUpper(name [0]) || !Char.IsLetter(name [0])) + environmentVariables [ValidAssemblerString (name)] = ValidAssemblerString (value); + else + systemProperties [ValidAssemblerString (name)] = ValidAssemblerString (value); + } + + void AddEnvironmentVariableLine (string l) + { + string line = l?.Trim (); + if (String.IsNullOrEmpty (line) || line [0] == '#') + return; + + string[] nv = line.Split (new char[]{'='}, 2); + AddEnvironmentVariable (nv[0].Trim (), nv.Length < 2 ? String.Empty : nv[1].Trim ()); + } + + string ValidAssemblerString (string s) + { + return s.Replace ("\"", "\\\""); + } } return !Log.HasLoggedErrors; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs index 3dd7b1863cb..8ad37974dd1 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs @@ -102,7 +102,7 @@ public static string WrapIt (TaskLoggingHelper log, Config config, AndroidTarget File.Copy (stubPath, outputFile, overwrite: true); string quotedOutputFile = MonoAndroidHelper.QuoteFileNameArgument (outputFile); - string objcopy = Path.Combine (config.AndroidBinUtilsDirectory, MonoAndroidHelper.GetExecutablePath (config.AndroidBinUtilsDirectory, "llvm-objcopy")); + string objcopy = MonoAndroidHelper.GetLlvmObjcopyPath (config.AndroidBinUtilsDirectory);; var args = new List { "--add-section", $"payload={MonoAndroidHelper.QuoteFileNameArgument (payloadFilePath)}", diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index 518477d9ec4..7937192bf79 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -783,26 +783,9 @@ public static string QuoteFileNameArgument (string? fileName) return builder.ToString (); } - public static AndroidRuntime ParseAndroidRuntime (string androidRuntime) + public static string GetLlvmObjcopyPath (string androidBinUtilsDirectory) { - if (string.Equals (androidRuntime, "CoreCLR", StringComparison.OrdinalIgnoreCase)) - return AndroidRuntime.CoreCLR; - if (string.Equals (androidRuntime, "NativeAOT", StringComparison.OrdinalIgnoreCase)) - return AndroidRuntime.NativeAOT; - - // Default runtime is MonoVM - return AndroidRuntime.MonoVM; - } - - public static JavaPeerStyle ParseCodeGenerationTarget (string codeGenerationTarget) - { - if (Enum.TryParse (codeGenerationTarget, ignoreCase: true, out JavaPeerStyle style)) - return style; - - // Default is XAJavaInterop1 - return JavaPeerStyle.XAJavaInterop1; + return Path.Combine (androidBinUtilsDirectory, MonoAndroidHelper.GetExecutablePath (androidBinUtilsDirectory, "llvm-objcopy")); } - - public static object GetProjectBuildSpecificTaskObjectKey (object key, string workingDirectory, string intermediateOutputPath) => (key, workingDirectory, intermediateOutputPath); } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 6421833e60e..b1a1c14e7c0 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1880,9 +1880,36 @@ because xbuild doesn't support framework reference assemblies. + ResolvedAssemblies="@(_ResolvedAssemblies)" + ResolvedUserAssemblies="@(_ResolvedUserAssemblies)" + SatelliteAssemblies="@(_AndroidResolvedSatellitePaths)" + NativeLibraries="@(AndroidNativeLibrary);@(EmbeddedNativeLibrary);@(FrameworkNativeLibrary)" + MonoComponents="@(_MonoComponent)" + MainAssembly="$(TargetPath)" + OutputDirectory="$(_AndroidIntermediateJavaSourceDirectory)mono" + EnvironmentOutputDirectory="$(IntermediateOutputPath)android" + TargetFrameworkVersion="$(TargetFrameworkVersion)" + Manifest="$(IntermediateOutputPath)android\AndroidManifest.xml" + Environments="@(_EnvironmentFiles)" + AndroidAotMode="$(AndroidAotMode)" + AndroidAotEnableLazyLoad="$(AndroidAotEnableLazyLoad)" + EnableLLVM="$(EnableLLVM)" + HttpClientHandlerType="$(AndroidHttpClientHandlerType)" + TlsProvider="$(AndroidTlsProvider)" + Debug="$(AndroidIncludeDebugSymbols)" + AndroidSequencePointsMode="$(_SequencePointsMode)" + EnableSGenConcurrent="$(AndroidEnableSGenConcurrent)" + SupportedAbis="@(_BuildTargetAbis)" + AndroidPackageName="$(_AndroidPackage)" + EnablePreloadAssembliesDefault="$(_AndroidEnablePreloadAssembliesDefault)" + PackageNamingPolicy="$(AndroidPackageNamingPolicy)" + BoundExceptionType="$(AndroidBoundExceptionType)" + RuntimeConfigBinFilePath="$(_BinaryRuntimeConfigPath)" + UseAssemblyStore="$(AndroidUseAssemblyStore)" + EnableMarshalMethods="$(_AndroidUseMarshalMethods)" + CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" + AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" + > Date: Mon, 7 Oct 2024 21:48:51 +0200 Subject: [PATCH 02/60] Use llvm-mc to embed the binary, this way we have full control --- .../Tasks/GeneratePackageManagerJava.cs | 7 + .../Utilities/ELFEmbeddingHelper.cs | 191 ++++++++++++++++++ .../Utilities/MonoAndroidHelper.cs | 7 +- .../Xamarin.Android.Common.targets | 3 + src/native/mono/monodroid/monodroid-glue.cc | 5 + .../xamarin-app-stub/application_dso_stub.cc | 3 + .../mono/xamarin-app-stub/xamarin-app.hh | 5 +- 7 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 91e5e21ab27..53225aa1557 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -65,6 +65,9 @@ public override bool RunTask () [Required] public string AndroidBinUtilsDirectory { get; set; } + [Output] + public ITaskItem[] EmbeddedObjectFiles { get; set; } + public bool EnableMarshalMethods { get; set; } public string RuntimeConfigBinFilePath { get; set; } public string BoundExceptionType { get; set; } @@ -297,6 +300,10 @@ void AddEnvironment () ELFEmbeddingHelper.KnownEmbedItems.RuntimeConfig, EnvironmentOutputDirectory ); + + EmbeddedObjectFiles = objectFilePaths.ToArray (); + } else { + EmbeddedObjectFiles = Array.Empty (); } var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs new file mode 100644 index 00000000000..5195c4b2d17 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Xamarin.Android.Tools; + +namespace Xamarin.Android.Tasks; + +class ELFEmbeddingHelper +{ + public sealed class EmbedItem + { + public readonly string SymbolName; + public readonly string BaseFileName; + + public EmbedItem (string symbolName, string baseFileName) + { + SymbolName = symbolName; + BaseFileName = baseFileName; + } + } + + public static class KnownEmbedItems + { + public static readonly EmbedItem RuntimeConfig = new ("embedded_runtime_config", "runtime_config"); + } + + sealed class LlvmMcTargetConfig + { + public readonly string TargetArch; + public readonly string TripleArch; + public readonly string TripleApiPrefix; + public readonly string AssemblerDirectivePrefix; + public readonly string SizeType; + public readonly uint WordSize; + + public LlvmMcTargetConfig (string targetArch, string tripleArch, string tripleApiPrefix, string assemblerDirectivePrefix, string sizeType, uint wordSize) + { + TargetArch = targetArch; + TripleArch = tripleArch; + TripleApiPrefix = tripleApiPrefix; + AssemblerDirectivePrefix = assemblerDirectivePrefix; + SizeType = sizeType; + WordSize = wordSize; + } + } + + static readonly Dictionary llvmMcConfigs = new () { + { AndroidTargetArch.Arm64, new ("aarch64", "aarch64", "android", "@", ".xword", 8) }, + { AndroidTargetArch.Arm, new ("arm", "armv7a", "androideabi", "%", ".long", 4) }, + { AndroidTargetArch.X86_64, new ("x86-64", "x86_64", "android", "@", ".quad", 8) }, + { AndroidTargetArch.X86, new ("x86", "i686", "android", "@", ".long", 4) }, + }; + + static readonly Encoding asmFileEncoding = new UTF8Encoding (false); + + public static List EmbedBinary ( + TaskLoggingHelper log, + ICollection supportedAbis, + string androidBinUtilsDirectory, + string inputFile, + EmbedItem embedItem, + string outputDirectory) + { + if (supportedAbis.Count < 1) { + throw new ArgumentException ("At least one target ABI must be present", nameof (supportedAbis)); + } + + string llvmMcPath = GetLlvmMcPath (androidBinUtilsDirectory); + var ret = new List (); + foreach (string abi in supportedAbis) { + EmbedBinary ( + log, + ret, + llvmMcPath, + abi, + inputFile, + outputDirectory, + embedItem + ); + } + + return ret; + } + + public static List EmbedBinary ( + TaskLoggingHelper log, + string abi, + string androidBinUtilsDirectory, + string inputFile, + EmbedItem embedItem, + string outputDirectory) + { + if (String.IsNullOrEmpty (abi)) { + throw new ArgumentException ("Must be a supported ABI name", nameof (abi)); + } + + var ret = new List (); + EmbedBinary ( + log, + ret, + GetLlvmMcPath (androidBinUtilsDirectory), + abi, + inputFile, + outputDirectory, + embedItem + ); + return ret; + } + + static void EmbedBinary ( + TaskLoggingHelper log, + List resultItems, + string llvmMcPath, + string abi, + string inputFile, + string outputDirectory, + EmbedItem embedItem) + { + string outputFile = Path.Combine (outputDirectory, $"embed_{embedItem.BaseFileName}.{abi.ToLowerInvariant ()}.o"); + DoEmbed (log, MonoAndroidHelper.AbiToTargetArch (abi), llvmMcPath, inputFile, outputFile, embedItem); + if (!File.Exists (outputFile)) { + return; + } + + var taskItem = new TaskItem (outputFile); + taskItem.SetMetadata ("Abi", abi); + taskItem.SetMetadata ("RuntimeIdentifier", MonoAndroidHelper.AbiToRid (abi)); + resultItems.Add (taskItem); + } + + static void DoEmbed ( + TaskLoggingHelper log, + AndroidTargetArch arch, + string llvmMcPath, + string inputFile, + string outputFile, + EmbedItem item) + { + if (!llvmMcConfigs.TryGetValue (arch, out LlvmMcTargetConfig cfg)) { + throw new NotSupportedException ($"Internal error: unsupported target arch '{arch}'"); + } + + var fi = new FileInfo (inputFile); + long inputFileSize = fi.Length; + string asmInputFile = Path.ChangeExtension (outputFile, ".s"); + + using var fs = File.Open (asmInputFile, FileMode.Create, FileAccess.Write, FileShare.Read); + using var sw = new StreamWriter (fs, asmFileEncoding); + + string symbolName = item.SymbolName; + sw.WriteLine ($".section .rodata,\"a\",{cfg.AssemblerDirectivePrefix}progbits"); + sw.WriteLine (".p2align 3, 0x00"); // Put the data at 4k boundary + sw.WriteLine (); + sw.WriteLine ($".global {symbolName}"); + sw.WriteLine ($".type {symbolName},{cfg.AssemblerDirectivePrefix}object"); + sw.WriteLine ($"{symbolName}:"); + sw.WriteLine ($"\t.incbin \"{inputFile}\""); + sw.WriteLine ($"\t.size {symbolName}, {inputFileSize}"); + sw.WriteLine (); + + symbolName += "_size"; + sw.WriteLine ($".global {symbolName}"); + sw.WriteLine ($"{symbolName}:"); + sw.WriteLine ($"\t{cfg.SizeType}\t{inputFileSize}"); + sw.WriteLine ($"\t.size {symbolName}, {cfg.WordSize}"); + + sw.Flush (); + sw.Close (); + + var args = new List { + $"--arch={cfg.TargetArch}", + "--assemble", + "--filetype=obj", + "-g", + $"--triple={cfg.TripleArch}-linux-{cfg.TripleApiPrefix}{XABuildConfig.AndroidMinimumDotNetApiLevel}", + "-o", MonoAndroidHelper.QuoteFileNameArgument (outputFile), + MonoAndroidHelper.QuoteFileNameArgument (asmInputFile), + }; + + int ret = MonoAndroidHelper.RunProcess (llvmMcPath, String.Join (" ", args), log); + if (ret != 0) { + return; + } + } + + static string GetLlvmMcPath (string androidBinUtilsDirectory) => MonoAndroidHelper.GetLlvmMcPath (androidBinUtilsDirectory); +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index 7937192bf79..9276ba600ca 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -783,9 +783,12 @@ public static string QuoteFileNameArgument (string? fileName) return builder.ToString (); } - public static string GetLlvmObjcopyPath (string androidBinUtilsDirectory) + public static string GetLlvmObjcopyPath (string androidBinUtilsDirectory) => GetBinUtilsToolPath (androidBinUtilsDirectory, "llvm-objcopy"); + public static string GetLlvmMcPath (string androidBinUtilsDirectory) => GetBinUtilsToolPath (androidBinUtilsDirectory, "llvm-mc"); + + static string GetBinUtilsToolPath (string androidBinUtilsDirectory, string toolName) { - return Path.Combine (androidBinUtilsDirectory, MonoAndroidHelper.GetExecutablePath (androidBinUtilsDirectory, "llvm-objcopy")); + return Path.Combine (androidBinUtilsDirectory, MonoAndroidHelper.GetExecutablePath (androidBinUtilsDirectory, toolName)); } } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index b1a1c14e7c0..bd4487759e1 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1869,6 +1869,7 @@ because xbuild doesn't support framework reference assemblies. <_GeneratePackageManagerJavaInputs Include="@(_GenerateJavaStubsInputs)" /> + <_GeneratePackageManagerJavaInputs Include="$(_BinaryRuntimeConfigPath)" /> @@ -1910,6 +1911,7 @@ because xbuild doesn't support framework reference assemblies. CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" > + + diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index d8c722f48f2..7ad85eddf1b 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -1406,6 +1406,11 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl Logger::init_logging_categories (mono_log_mask_raw, mono_log_level_raw); + log_warn (LOG_DEFAULT, "Embedded runtime config size: %zu", embedded_runtime_config_size); + if (embedded_runtime_config_size > 0) { + log_warn (LOG_DEFAULT, "First byte of embedded runtime config: 0x%x", embedded_runtime_config[0]); + } + std::unique_ptr mono_log_mask (mono_log_mask_raw); std::unique_ptr mono_log_level (mono_log_level_raw); diff --git a/src/native/mono/xamarin-app-stub/application_dso_stub.cc b/src/native/mono/xamarin-app-stub/application_dso_stub.cc index 0316a55408b..2e3253e7213 100644 --- a/src/native/mono/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/mono/xamarin-app-stub/application_dso_stub.cc @@ -305,3 +305,6 @@ const JniRemappingTypeReplacementEntry jni_remapping_type_replacements[] = { .replacement = "another/replacement/java/type", }, }; + +size_t embedded_runtime_config_size = 0; +uint8_t embedded_runtime_config[0]; diff --git a/src/native/mono/xamarin-app-stub/xamarin-app.hh b/src/native/mono/xamarin-app-stub/xamarin-app.hh index 5b058a99d2d..ab6dc846840 100644 --- a/src/native/mono/xamarin-app-stub/xamarin-app.hh +++ b/src/native/mono/xamarin-app-stub/xamarin-app.hh @@ -394,7 +394,6 @@ MONO_API MONO_API_EXPORT const MarshalMethodName mm_method_names[]; #endif // def RELEASE -using get_function_pointer_fn = void(*)(uint32_t mono_image_index, uint32_t class_index, uint32_t method_token, void*& target_ptr); -MONO_API MONO_API_EXPORT void xamarin_app_init (JNIEnv *env, get_function_pointer_fn fn) noexcept; - +MONO_API MONO_API_EXPORT size_t embedded_runtime_config_size; +MONO_API MONO_API_EXPORT uint8_t embedded_runtime_config[]; #endif // __XAMARIN_ANDROID_TYPEMAP_H From d01e4e1cffd8999a875866dbbf7eaba147d76d7b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 8 Oct 2024 11:51:24 +0200 Subject: [PATCH 03/60] Runtime config binary blob is now fully embedded --- .../Utilities/ELFEmbeddingHelper.cs | 6 +++++- .../mono/monodroid/embedded-assemblies-zip.cc | 14 +++++++------- src/native/mono/monodroid/monodroid-glue.cc | 16 ++++++++++------ src/native/mono/runtime-base/android-system.cc | 2 ++ 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs index 5195c4b2d17..62da88708c7 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs @@ -144,9 +144,13 @@ static void DoEmbed ( throw new NotSupportedException ($"Internal error: unsupported target arch '{arch}'"); } + inputFile = Path.GetFullPath (inputFile); + outputFile = Path.GetFullPath (outputFile); + var fi = new FileInfo (inputFile); long inputFileSize = fi.Length; string asmInputFile = Path.ChangeExtension (outputFile, ".s"); + string sanitizedInputFilePath = inputFile.Replace ("\\", "\\\\"); using var fs = File.Open (asmInputFile, FileMode.Create, FileAccess.Write, FileShare.Read); using var sw = new StreamWriter (fs, asmFileEncoding); @@ -158,7 +162,7 @@ static void DoEmbed ( sw.WriteLine ($".global {symbolName}"); sw.WriteLine ($".type {symbolName},{cfg.AssemblerDirectivePrefix}object"); sw.WriteLine ($"{symbolName}:"); - sw.WriteLine ($"\t.incbin \"{inputFile}\""); + sw.WriteLine ($"\t.incbin \"{sanitizedInputFilePath}\""); sw.WriteLine ($"\t.size {symbolName}, {inputFileSize}"); sw.WriteLine (); diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 95c36da3f3c..1894a0e83d1 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -62,13 +62,13 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector 0) { + size_t blob_time_index; if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::RuntimeConfigBlob); } runtime_config_args.kind = 1; - EmbeddedAssemblies::get_runtime_config_blob (runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); +// embeddedAssemblies.get_runtime_config_blob (runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); + runtime_config_args.runtimeconfig.data.data = reinterpret_cast(embedded_runtime_config); + runtime_config_args.runtimeconfig.data.data_len = static_cast(embedded_runtime_config_size); monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); if (FastTiming::enabled ()) [[unlikely]] { @@ -1406,10 +1410,10 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl Logger::init_logging_categories (mono_log_mask_raw, mono_log_level_raw); - log_warn (LOG_DEFAULT, "Embedded runtime config size: %zu", embedded_runtime_config_size); - if (embedded_runtime_config_size > 0) { - log_warn (LOG_DEFAULT, "First byte of embedded runtime config: 0x%x", embedded_runtime_config[0]); - } + // log_warn (LOG_DEFAULT, "Embedded runtime config size: %zu", embedded_runtime_config_size); + // if (embedded_runtime_config_size > 0) { + // log_warn (LOG_DEFAULT, "First byte of embedded runtime config: 0x%x", embedded_runtime_config[0]); + // } std::unique_ptr mono_log_mask (mono_log_mask_raw); std::unique_ptr mono_log_level (mono_log_level_raw); diff --git a/src/native/mono/runtime-base/android-system.cc b/src/native/mono/runtime-base/android-system.cc index 0fcd825bead..e4cbbcec6ce 100644 --- a/src/native/mono/runtime-base/android-system.cc +++ b/src/native/mono/runtime-base/android-system.cc @@ -741,10 +741,12 @@ AndroidSystem::setup_apk_directories (unsigned short running_on_cpu, jstring_arr if (have_split_apks) { if (Util::ends_with (apk, SharedConstants::split_config_abi_apk_name)) { + log_warn (LOG_ASSEMBLY, "Here #1"); add_apk_libdir (apk, number_of_added_directories, abi); break; } } else { + log_warn (LOG_ASSEMBLY, "Here #2"); add_apk_libdir (apk, number_of_added_directories, abi); } } From 514a28ab919aa3ecf15361d1ba69e247614c3a95 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 8 Oct 2024 17:53:04 +0200 Subject: [PATCH 04/60] Remove debug spam --- src/native/mono/runtime-base/android-system.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/native/mono/runtime-base/android-system.cc b/src/native/mono/runtime-base/android-system.cc index e4cbbcec6ce..0fcd825bead 100644 --- a/src/native/mono/runtime-base/android-system.cc +++ b/src/native/mono/runtime-base/android-system.cc @@ -741,12 +741,10 @@ AndroidSystem::setup_apk_directories (unsigned short running_on_cpu, jstring_arr if (have_split_apks) { if (Util::ends_with (apk, SharedConstants::split_config_abi_apk_name)) { - log_warn (LOG_ASSEMBLY, "Here #1"); add_apk_libdir (apk, number_of_added_directories, abi); break; } } else { - log_warn (LOG_ASSEMBLY, "Here #2"); add_apk_libdir (apk, number_of_added_directories, abi); } } From 0081c367a360e9be6a79cbf57d7f1eeaa582226a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 9 Oct 2024 17:23:08 +0200 Subject: [PATCH 05/60] New target to build embedded assembly store --- .../Microsoft.Android.Sdk.After.targets | 1 + ...crosoft.Android.Sdk.AssemblyStores.targets | 31 +++++++++++++++++++ .../Tasks/CreateEmbeddedAssemblyStore.cs | 14 +++++++++ 3 files changed, 46 insertions(+) create mode 100644 src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets index 8a64f834b80..c01bf0248cd 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets @@ -29,4 +29,5 @@ This file is imported *after* the Microsoft.NET.Sdk/Sdk.targets. + diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets new file mode 100644 index 00000000000..afa905adcac --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets @@ -0,0 +1,31 @@ + + + + + + + + <_EmbeddedAssemblyStoreObjectFile Include="$(_NativeAssemblySourceDir)embed_assembly_store.%(_BuildTargetAbis.Identity).o" /> + + + + + + + + + + + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs new file mode 100644 index 00000000000..d68e6d386f5 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs @@ -0,0 +1,14 @@ +using Xamarin.Android.Tools; +using Microsoft.Android.Build.Tasks; + +namespace Xamarin.Android.Tasks; + +public class CreateEmbeddedAssemblyStore : AndroidTask +{ + public override string TaskPrefix => "CEAS"; + + public override bool RunTask () + { + return !Log.HasLoggedErrors; + } +} From 5d91471a42906afc51562b29d2e0122661e2df21 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 9 Oct 2024 17:24:11 +0200 Subject: [PATCH 06/60] New task to build embedded assembly store --- .../Tasks/CreateEmbeddedAssemblyStore.cs | 22 ++++++++++++++++++- .../Utilities/ELFEmbeddingHelper.cs | 1 + .../Xamarin.Android.Common.targets | 6 ++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs index d68e6d386f5..357575e5fdd 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs @@ -1,5 +1,7 @@ -using Xamarin.Android.Tools; + using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Xamarin.Android.Tools; namespace Xamarin.Android.Tasks; @@ -7,6 +9,24 @@ public class CreateEmbeddedAssemblyStore : AndroidTask { public override string TaskPrefix => "CEAS"; + [Required] + public string AndroidBinUtilsDirectory { get; set; } + + [Required] + public string AppSharedLibrariesDir { get; set; } + + [Required] + public ITaskItem[] ResolvedUserAssemblies { get; set; } + + [Required] + public ITaskItem[] ResolvedFrameworkAssemblies { get; set; } + + [Output] + public ITaskItem[] NativeAssemblySources { get; set; } + + [Output] + public ITaskItem[] EmbeddedObjectFiles { get; set; } + public override bool RunTask () { return !Log.HasLoggedErrors; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs index 62da88708c7..56f399913f2 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs @@ -26,6 +26,7 @@ public EmbedItem (string symbolName, string baseFileName) public static class KnownEmbedItems { public static readonly EmbedItem RuntimeConfig = new ("embedded_runtime_config", "runtime_config"); + public static readonly EmbedItem AssemblyStore = new ("embedded_assembly_store", "assembly_store"); } sealed class LlvmMcTargetConfig diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index bd4487759e1..6e7c3fd2cc1 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -362,9 +362,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' ">False <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' ">$(AndroidEnableMarshalMethods) - - <_AndroidUseManagedMarshalMethodsLookup Condition=" '$(_AndroidUseManagedMarshalMethodsLookup)' == '' and '$(_AndroidUseMarshalMethods)' == 'True' and '$(_AndroidRuntime)' != 'MonoVM' ">True - <_AndroidUseManagedMarshalMethodsLookup Condition=" '$(_AndroidUseManagedMarshalMethodsLookup)' == '' ">False + <_AndroidEmbedAssemblyStoreInRuntime Condition=" '$(AndroidUseAssemblyStore)' == 'True' And '$(_AndroidEmbedAssemblyStoreInRuntime)' == '' ">True @@ -2199,7 +2197,7 @@ because xbuild doesn't support framework reference assemblies. Date: Wed, 9 Oct 2024 18:03:38 +0200 Subject: [PATCH 07/60] Move some of assembly packaging code to a helper class --- .../Utilities/AssemblyPackagingHelper.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs index 1599a8e581e..ca9bd62ea33 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs @@ -10,7 +10,11 @@ namespace Xamarin.Android.Tasks; static class AssemblyPackagingHelper { +<<<<<<< HEAD public static void AddAssembliesFromCollection (TaskLoggingHelper Log, ICollection SupportedAbis, ICollection assemblies, Action doAddAssembly) +======= + public static void AddAssembliesFromCollection (TaskLoggingHelper Log, ICollection SupportedAbis, ICollection assemblies, Action> doAddAssemblies) +>>>>>>> c4d883405 (Move some of assembly packaging code to a helper class) { Dictionary> perArchAssemblies = MonoAndroidHelper.GetPerArchAssemblies ( assemblies, @@ -28,6 +32,7 @@ public static void AddAssembliesFromCollection (TaskLoggingHelper Log, ICollecti foreach (var kvp in perArchAssemblies) { Log.LogDebugMessage ($"Adding assemblies for architecture '{kvp.Key}'"); +<<<<<<< HEAD DoAddAssembliesFromArchCollection (Log, kvp.Key, kvp.Value, doAddAssembly); } } @@ -40,6 +45,9 @@ static void DoAddAssembliesFromArchCollection (TaskLoggingHelper Log, AndroidTar } doAddAssembly (Log, arch, assembly); +======= + doAddAssemblies (kvp.Key, kvp.Value); +>>>>>>> c4d883405 (Move some of assembly packaging code to a helper class) } } } From 297097be1d67a435d024554b6ac61728ac10d499 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 9 Oct 2024 18:25:26 +0200 Subject: [PATCH 08/60] Move more assembly packaging code to the helper class --- .../Utilities/AssemblyPackagingHelper.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs index ca9bd62ea33..1599a8e581e 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs @@ -10,11 +10,7 @@ namespace Xamarin.Android.Tasks; static class AssemblyPackagingHelper { -<<<<<<< HEAD public static void AddAssembliesFromCollection (TaskLoggingHelper Log, ICollection SupportedAbis, ICollection assemblies, Action doAddAssembly) -======= - public static void AddAssembliesFromCollection (TaskLoggingHelper Log, ICollection SupportedAbis, ICollection assemblies, Action> doAddAssemblies) ->>>>>>> c4d883405 (Move some of assembly packaging code to a helper class) { Dictionary> perArchAssemblies = MonoAndroidHelper.GetPerArchAssemblies ( assemblies, @@ -32,7 +28,6 @@ public static void AddAssembliesFromCollection (TaskLoggingHelper Log, ICollecti foreach (var kvp in perArchAssemblies) { Log.LogDebugMessage ($"Adding assemblies for architecture '{kvp.Key}'"); -<<<<<<< HEAD DoAddAssembliesFromArchCollection (Log, kvp.Key, kvp.Value, doAddAssembly); } } @@ -45,9 +40,6 @@ static void DoAddAssembliesFromArchCollection (TaskLoggingHelper Log, AndroidTar } doAddAssembly (Log, arch, assembly); -======= - doAddAssemblies (kvp.Key, kvp.Value); ->>>>>>> c4d883405 (Move some of assembly packaging code to a helper class) } } } From 45ad89ac7f636c60ed19aac8eddf82a990c8bc92 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 9 Oct 2024 20:43:18 +0200 Subject: [PATCH 09/60] Almost there, TBC --- ...crosoft.Android.Sdk.AssemblyStores.targets | 7 +- .../Microsoft.Android.Sdk.BuildOrder.targets | 1 - .../Tasks/CreateEmbeddedAssemblyStore.cs | 54 ++++ .../Xamarin.Android.Common.targets | 249 ++++++++++-------- 4 files changed, 193 insertions(+), 118 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets index afa905adcac..ba76fad8ce1 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets @@ -17,8 +17,13 @@ + ResolvedFrameworkAssemblies="@(_ShrunkFrameworkAssemblies)" + SupportedAbis="@(_BuildTargetAbis)"> diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets index 17558b8efcd..b3285c44966 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets @@ -62,7 +62,6 @@ properties that determine build ordering. <_PrepareBuildApkDependsOnTargets> _SetLatestTargetFrameworkVersion; _GetLibraryImports; - _RemoveRegisterAttribute; _ResolveAssemblies; _ResolveSatellitePaths; _CreatePackageWorkspace; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs index 357575e5fdd..3d272f3b933 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs @@ -1,6 +1,9 @@ +using System; +using System.Collections.Generic; using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; using Xamarin.Android.Tools; namespace Xamarin.Android.Tasks; @@ -15,12 +18,27 @@ public class CreateEmbeddedAssemblyStore : AndroidTask [Required] public string AppSharedLibrariesDir { get; set; } + [Required] + public string CompressedAssembliesDir { get; set; } + + [Required] + public bool Debug { get; set; } + + [Required] + public bool EnableCompression { get; set; } + + [Required] + public string ProjectFullPath { get; set; } + [Required] public ITaskItem[] ResolvedUserAssemblies { get; set; } [Required] public ITaskItem[] ResolvedFrameworkAssemblies { get; set; } + [Required] + public string [] SupportedAbis { get; set; } + [Output] public ITaskItem[] NativeAssemblySources { get; set; } @@ -29,6 +47,42 @@ public class CreateEmbeddedAssemblyStore : AndroidTask public override bool RunTask () { + bool compress = !Debug && EnableCompression; + IDictionary>? compressedAssembliesInfo = null; + + if (compress) { + string key = CompressedAssemblyInfo.GetKey (ProjectFullPath); + Log.LogDebugMessage ($"[{TaskPrefix}] Retrieving assembly compression info with key '{key}'"); + compressedAssembliesInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal>> (key, RegisteredTaskObjectLifetime.Build); + if (compressedAssembliesInfo == null) { + throw new InvalidOperationException ($"Assembly compression info not found for key '{key}'. Compression will not be performed."); + } + } + + var storeBuilder = new AssemblyStoreBuilder (Log); + + // Add user assemblies + AssemblyPackagingHelper.AddAssembliesFromCollection (Log, SupportedAbis, ResolvedUserAssemblies, DoAddAssembliesFromArchCollection); + + // Add framework assemblies + AssemblyPackagingHelper.AddAssembliesFromCollection (Log, SupportedAbis, ResolvedFrameworkAssemblies, DoAddAssembliesFromArchCollection); + return !Log.HasLoggedErrors; + + void DoAddAssembliesFromArchCollection (TaskLoggingHelper log, AndroidTargetArch arch, ITaskItem assembly) + { + string sourcePath = CompressAssembly (assembly); + storeBuilder.AddAssembly (sourcePath, assembly, includeDebugSymbols: Debug); + return; + } + + string CompressAssembly (ITaskItem assembly) + { + if (!compress) { + return assembly.ItemSpec; + } + + return AssemblyCompression.Compress (Log, assembly, compressedAssembliesInfo, CompressedAssembliesDir); + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 6e7c3fd2cc1..9af4d2a1589 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -311,9 +311,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' And '$(EmbedAssembliesIntoApk)' == 'False' ">True <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' ">False - - <_AndroidUseCLR Condition=" '$(_AndroidRuntime)' == 'CoreCLR' ">True - <_AndroidUseCLR Condition=" '$(_AndroidRuntime)' != 'CoreCLR' ">False + <_AndroidCompressedAssembliesDir>$(IntermediateOutputPath)android\lz4 @@ -2067,6 +2065,7 @@ because xbuild doesn't support framework reference assemblies. <_CompileToDalvikDependsOnTargets> _CompileJava; + _RemoveRegisterAttribute; _CreateApplicationSharedLibraries; _GetMonoPlatformJarPath; _GetLibraryImports; @@ -2197,7 +2196,7 @@ because xbuild doesn't support framework reference assemblies. - + CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + + + - - - - - - - - - - - + IntermediateOutputPath="$(IntermediateOutputPath)"> + CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + + - - <_ApkOutputPath>$(ApkFileIntermediate) - - - - <_NativeLibraries Include="@(_AndroidNativeLibraryForFastDev)" /> - <_DalvikClasses Include="@(_DexFileForFastDev)" /> - - - - <_ApkOutputPath>$(_BaseZipIntermediate) - <_BundleNativeLibraries>$(_BundleResultNativeLibraries) - - - - <_NativeLibraries Include="@(AndroidNativeLibrary)" /> - <_DalvikClasses Include="@(_DexFile)" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + + + + CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + + + Date: Thu, 10 Oct 2024 11:33:07 +0200 Subject: [PATCH 10/60] Assembly store embedding works --- ...crosoft.Android.Sdk.AssemblyStores.targets | 1 + .../Tasks/CreateEmbeddedAssemblyStore.cs | 37 +++++++++++++++++++ .../Utilities/AssemblyStoreGenerator.cs | 5 ++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets index ba76fad8ce1..c7185129668 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets @@ -17,6 +17,7 @@ (); + var sourceFiles = new List (); + Dictionary assemblyStorePaths = storeBuilder.Generate (Path.Combine (AppSharedLibrariesDir, "embedded")); + foreach (var kvp in assemblyStorePaths) { + string abi = MonoAndroidHelper.ArchToAbi (kvp.Key); + string inputFile = kvp.Value; + + List items = ELFEmbeddingHelper.EmbedBinary ( + Log, + abi, + AndroidBinUtilsDirectory, + inputFile, + ELFEmbeddingHelper.KnownEmbedItems.AssemblyStore, + AssemblySourcesDir + ); + + if (items.Count == 0) { + continue; + } + + objectFiles.AddRange (items); + foreach (ITaskItem objectItem in items) { + var sourceItem = new TaskItem ( + Path.ChangeExtension (objectItem.ItemSpec, ".s"), + objectItem.CloneCustomMetadata () + ); + sourceFiles.Add (sourceItem); + } + } + + NativeAssemblySources = sourceFiles.ToArray (); + EmbeddedObjectFiles = objectFiles.ToArray (); + return !Log.HasLoggedErrors; void DoAddAssembliesFromArchCollection (TaskLoggingHelper log, AndroidTargetArch arch, ITaskItem assembly) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.cs index 024f2cf0ac2..f061412a125 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.cs @@ -104,7 +104,8 @@ string Generate (string baseOutputDirectory, AndroidTargetArch arch, List (); var descriptors = new List (); ulong namesSize = 0; @@ -118,7 +119,7 @@ string Generate (string baseOutputDirectory, AndroidTargetArch arch, List Date: Thu, 10 Oct 2024 18:05:33 +0200 Subject: [PATCH 11/60] Actually use the embedded assembly store --- .../Xamarin.Android.Common.targets | 4 + .../mono/monodroid/embedded-assemblies-zip.cc | 89 +++++++++++-------- .../mono/monodroid/embedded-assemblies.hh | 14 +-- .../xamarin-app-stub/application_dso_stub.cc | 3 + .../mono/xamarin-app-stub/xamarin-app.hh | 3 + 5 files changed, 69 insertions(+), 44 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 9af4d2a1589..1706e4fb6b0 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2379,6 +2379,7 @@ because xbuild doesn't support framework reference assemblies. AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" IntermediateOutputPath="$(IntermediateOutputPath)"> CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)"> CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)"> CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)"> CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)"> c } } + +[[gnu::always_inline]] void +EmbeddedAssemblies::verify_assembly_store_and_set_info (void *data_start, const char *name) noexcept +{ + auto header = static_cast(data_start); + + if (header->magic != ASSEMBLY_STORE_MAGIC) { + Helpers::abort_application ( + LOG_ASSEMBLY, + Util::monodroid_strdup_printf ( + "Assembly store '%s' is not a valid .NET for Android assembly store file", + entry_name.get () + ) + ); + } + + if (header->version != ASSEMBLY_STORE_FORMAT_VERSION) { + Helpers::abort_application ( + LOG_ASSEMBLY, + Util::monodroid_strdup_printf ( + "Assembly store '%s' uses format version 0x%x, instead of the expected 0x%x", + entry_name.get (), + header->version, + ASSEMBLY_STORE_FORMAT_VERSION + ) + ); + } + + constexpr size_t header_size = sizeof(AssemblyStoreHeader); + + assembly_store.data_start = static_cast(data_start); + assembly_store.assembly_count = header->entry_count; + assembly_store.index_entry_count = header->index_entry_count; + assembly_store.assemblies = reinterpret_cast(assembly_store.data_start + header_size + header->index_size); + assembly_store_hashes = reinterpret_cast(assembly_store.data_start + header_size); + + number_of_found_assemblies += assembly_store.assembly_count; + number_of_mapped_assembly_stores++; + have_and_want_debug_symbols = register_debug_symbols; +} + inline void EmbeddedAssemblies::map_assembly_store (dynamic_local_string const& entry_name, ZipEntryLoadState &state) noexcept { @@ -219,42 +260,8 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string } auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (assembly_store_map, entry_name.get ()); - log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size); - auto header = static_cast(payload_start); - - if (header->magic != ASSEMBLY_STORE_MAGIC) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Assembly store '{}' is not a valid .NET for Android assembly store file", - optional_string (entry_name.get ()) - ) - ); - } - - if (header->version != ASSEMBLY_STORE_FORMAT_VERSION) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Assembly store '{}' uses format version {:x}, instead of the expected {:x}", - optional_string (entry_name.get ()), - header->version, - ASSEMBLY_STORE_FORMAT_VERSION - ) - ); - } - - constexpr size_t header_size = sizeof(AssemblyStoreHeader); - - assembly_store.data_start = static_cast(payload_start); - assembly_store.assembly_count = header->entry_count; - assembly_store.index_entry_count = header->index_entry_count; - assembly_store.assemblies = reinterpret_cast(assembly_store.data_start + header_size + header->index_size); - assembly_store_hashes = reinterpret_cast(assembly_store.data_start + header_size); - - number_of_found_assemblies += assembly_store.assembly_count; - number_of_mapped_assembly_stores++; - have_and_want_debug_symbols = register_debug_symbols; + log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: %p; size: %zu", payload_start, payload_size); + verify_assembly_store_and_set_info (payload_start, entry_name.get ()); } [[gnu::always_inline]] void @@ -265,9 +272,15 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& } dynamic_local_string entry_name; - bool assembly_store_found = false; + bool assembly_store_found = embedded_assembly_store_size != 0; + if (assembly_store_found) { + log_debug (LOG_ASSEMBLY, "Got embedded assembly store, size %zu", embedded_assembly_store_size); + verify_assembly_store_and_set_info (embedded_assembly_store, "embedded"); + log_debug (LOG_ASSEMBLY, "Looking for DSOs in APK"); + } else { + log_debug (LOG_ASSEMBLY, "Looking for assembly store ('%s') and DSOs in APK", assembly_store_file_path.data ()); + } - log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ()); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index f3447a69840..ed5608e9d2e 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -375,12 +375,14 @@ namespace xamarin::android::internal { static const TypeMapModuleEntry* binary_search (uint32_t key, const TypeMapModuleEntry *arr, uint32_t n) noexcept; #endif template - static void set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; - static void set_assembly_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; - static void set_debug_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; - static void map_assembly_store (dynamic_local_string const& entry_name, ZipEntryLoadState &state) noexcept; - static const AssemblyStoreIndexEntry* find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept; - static void store_individual_assembly_data (dynamic_local_string const& entry_name, ZipEntryLoadState const& state, monodroid_should_register should_register) noexcept; + void set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; + void set_assembly_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; + void set_debug_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; + + void verify_assembly_store_and_set_info (void *data_start, const char *name) noexcept; + void map_assembly_store (dynamic_local_string const& entry_name, ZipEntryLoadState &state) noexcept; + const AssemblyStoreIndexEntry* find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept; + void store_individual_assembly_data (dynamic_local_string const& entry_name, ZipEntryLoadState const& state, monodroid_should_register should_register) noexcept; constexpr static size_t get_mangled_name_max_size_overhead () { diff --git a/src/native/mono/xamarin-app-stub/application_dso_stub.cc b/src/native/mono/xamarin-app-stub/application_dso_stub.cc index 2e3253e7213..49588a88e38 100644 --- a/src/native/mono/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/mono/xamarin-app-stub/application_dso_stub.cc @@ -308,3 +308,6 @@ const JniRemappingTypeReplacementEntry jni_remapping_type_replacements[] = { size_t embedded_runtime_config_size = 0; uint8_t embedded_runtime_config[0]; + +size_t embedded_assembly_store_size = 0; +uint8_t embedded_assembly_store[0]; diff --git a/src/native/mono/xamarin-app-stub/xamarin-app.hh b/src/native/mono/xamarin-app-stub/xamarin-app.hh index ab6dc846840..3e89c184057 100644 --- a/src/native/mono/xamarin-app-stub/xamarin-app.hh +++ b/src/native/mono/xamarin-app-stub/xamarin-app.hh @@ -396,4 +396,7 @@ MONO_API MONO_API_EXPORT const MarshalMethodName mm_method_names[]; MONO_API MONO_API_EXPORT size_t embedded_runtime_config_size; MONO_API MONO_API_EXPORT uint8_t embedded_runtime_config[]; + +MONO_API MONO_API_EXPORT size_t embedded_assembly_store_size; +MONO_API MONO_API_EXPORT uint8_t embedded_assembly_store[]; #endif // __XAMARIN_ANDROID_TYPEMAP_H From 12afaf79bb159cc834e9333debd261ba5cbb9328 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 10 Oct 2024 22:28:02 +0200 Subject: [PATCH 12/60] A handful of bugfixes and performance tweaks --- .../Tasks/GeneratePackageManagerJava.cs | 4 ++++ ...pplicationConfigNativeAssemblyGenerator.cs | 19 +++++++++++++++++++ .../Xamarin.Android.Common.targets | 2 ++ src/native/mono/monodroid/monodroid-glue.cc | 4 ++-- .../mono/runtime-base/android-system.cc | 18 +++--------------- src/native/mono/runtime-base/util.cc | 8 ++++---- src/native/mono/runtime-base/util.hh | 2 +- 7 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 53225aa1557..0596d932246 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -65,6 +65,9 @@ public override bool RunTask () [Required] public string AndroidBinUtilsDirectory { get; set; } + [Required] + public bool AssemblyStoreEmbeddedInRuntime { get; set; } + [Output] public ITaskItem[] EmbeddedObjectFiles { get; set; } @@ -331,6 +334,7 @@ void AddEnvironment () JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, MarshalMethodsEnabled = EnableMarshalMethods, IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), + AssemblyStoreEmbeddedInRuntime = UseAssemblyStore && AssemblyStoreEmbeddedInRuntime, }; LLVMIR.LlvmIrModule appConfigModule = appConfigAsmGen.Construct (); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs index 5844b9fb427..d4349ed1661 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs @@ -197,6 +197,7 @@ sealed class XamarinAndroidBundledAssembly public bool MarshalMethodsEnabled { get; set; } public bool ManagedMarshalMethodsLookupEnabled { get; set; } public bool IgnoreSplitConfigs { get; set; } + public bool AssemblyStoreEmbeddedInRuntime { get; set; } public ApplicationConfigNativeAssemblyGenerator (IDictionary environmentVariables, IDictionary systemProperties, TaskLoggingHelper log) : base (log) @@ -306,6 +307,24 @@ protected override void Construct (LlvmIrModule module) module.Add (bundled_assemblies); AddAssemblyStores (module); + + if (AssemblyStoreEmbeddedInRuntime) { + return; + } + + // Need these to keep ABI compatibility with `libxamarin-app.so` used at the runtime's build time + var embedded_assembly_store_size = new LlvmIrGlobalVariable ( + (ulong)0, + "embedded_assembly_store_size", + LlvmIrVariableOptions.GlobalConstant + ); + module.Add (embedded_assembly_store_size); + + var embedded_assembly_store = new LlvmIrGlobalVariable (typeof (byte[]), "embedded_assembly_store", LlvmIrVariableOptions.GlobalWritable) { + ZeroInitializeArray = true, + ArrayItemCount = 0, + }; + module.Add (embedded_assembly_store); } void AddAssemblyStores (LlvmIrModule module) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 1706e4fb6b0..bd921b66859 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -361,6 +361,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' ">False <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' ">$(AndroidEnableMarshalMethods) <_AndroidEmbedAssemblyStoreInRuntime Condition=" '$(AndroidUseAssemblyStore)' == 'True' And '$(_AndroidEmbedAssemblyStoreInRuntime)' == '' ">True + <_AndroidEmbedAssemblyStoreInRuntime Condition="'$(_AndroidEmbedAssemblyStoreInRuntime)' == '' ">False @@ -1906,6 +1907,7 @@ because xbuild doesn't support framework reference assemblies. EnableMarshalMethods="$(_AndroidUseMarshalMethods)" CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" + AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)" > diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 425edd15d56..727681bf268 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -1159,8 +1159,8 @@ MonodroidRuntime::set_profile_options () noexcept .append (OUTPUT_ARG) .append (output_path.get (), output_path.length ()); } - if (Util::create_directory (AndroidSystem::override_dirs[0], 0) < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", optional_string (AndroidSystem::override_dirs[0]), std::strerror (errno)); + if (Util::create_directory (AndroidSystem::override_dirs[0], 0777, 000) < 0) { + log_warn (LOG_DEFAULT, "Failed to create directory '%s'. %s", AndroidSystem::override_dirs[0], std::strerror (errno)); } log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", optional_string (value.get ())); diff --git a/src/native/mono/runtime-base/android-system.cc b/src/native/mono/runtime-base/android-system.cc index 0fcd825bead..62c358f3816 100644 --- a/src/native/mono/runtime-base/android-system.cc +++ b/src/native/mono/runtime-base/android-system.cc @@ -262,26 +262,14 @@ AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] co return 0; } -// TODO: review this. Do we really have to create the dir in release? void AndroidSystem::create_update_dir (char *override_dir) noexcept { -#if defined (RELEASE) - /* - * Don't create .__override__ on Release builds, because Google requires - * that pre-loaded apps not create world-writable directories. - * - * However, if any logging is enabled (which should _not_ happen with - * pre-loaded apps!), we need the .__override__ directory... - */ - if (log_categories == 0 && monodroid_get_system_property (SharedConstants::DEBUG_MONO_PROFILE_PROPERTY, nullptr) == 0) { - return; - } -#endif // def RELEASE - override_dirs [0] = override_dir; +#if defined(DEBUG) + log_debug (LOG_DEFAULT, "Creating public update directory: `%s`", override_dir); Util::create_public_directory (override_dir); - log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); +#endif } bool diff --git a/src/native/mono/runtime-base/util.cc b/src/native/mono/runtime-base/util.cc index fda41ecfd88..b017af23220 100644 --- a/src/native/mono/runtime-base/util.cc +++ b/src/native/mono/runtime-base/util.cc @@ -147,14 +147,14 @@ Util::path_combine (const char *path1, const char *path2) void Util::create_public_directory (const char *dir) { - int ret = create_directory (dir, 0777); + int ret = create_directory (dir, 0777, 0); if (ret < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create public directory '%s'. %s", dir, std::strerror (errno)); } } int -Util::create_directory (const char *pathname, mode_t mode) +Util::create_directory (const char *pathname, mode_t mode, mode_t mask) { if (mode <= 0) mode = DEFAULT_DIRECTORY_MODE; @@ -163,7 +163,7 @@ Util::create_directory (const char *pathname, mode_t mode) errno = EINVAL; return -1; } - mode_t oldumask = umask (022); + mode_t oldumask = umask (mask); std::unique_ptr path {strdup_new (pathname)}; int rv, ret = 0; for (char *d = path.get (); d != nullptr && *d; ++d) { diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index a43009478ae..3bfd897658f 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -69,7 +69,7 @@ namespace xamarin::android static char *monodroid_strdup_vprintf (const char *format, va_list vargs); static char* path_combine (const char *path1, const char *path2); static void create_public_directory (const char *dir); - static int create_directory (const char *pathname, mode_t mode); + static int create_directory (const char *pathname, mode_t mode, mode_t mask = 022); static void set_world_accessable (const char *path); static auto set_world_accessible (int fd) noexcept -> bool; static void set_user_executable (const char *path); From 15a5bf444da285ffa26e778078740d6ee874cd78 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 11 Oct 2024 11:42:08 +0200 Subject: [PATCH 13/60] Fix DSO count when building Also, runtime config blob will no longer be packaged in the APK, stop checking whether it was found. --- .../Tasks/GeneratePackageManagerJava.cs | 31 +++++++++++++++++-- ...pplicationConfigNativeAssemblyGenerator.cs | 3 +- .../mono/monodroid/embedded-assemblies.hh | 17 +++++----- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 0596d932246..20c501d58ac 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -285,10 +285,34 @@ void AddEnvironment () // pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly) + "\","); //} - pkgmgr.WriteLine ("\t};"); + var uniqueNativeLibraries = new List (); + + // Number of DSOs that will be packaged, it may be different to the number of items in the above + // `uniqueNativeLibraries` list. + uint packagedNativeLibrariesCount = 0; + var seenNativeLibraryNames = new HashSet (StringComparer.OrdinalIgnoreCase); + if (NativeLibraries != null) { + foreach (ITaskItem item in NativeLibraries) { + // We don't care about different ABIs here, just the file name + string name = Path.GetFileName (item.ItemSpec); + if (seenNativeLibraryNames.Contains (name)) { + continue; + } - pkgmgr.WriteLine ("}"); - pkgmgr.Flush (); + if (!ELFHelper.IsEmptyAOTLibrary (Log, item.ItemSpec)) { + packagedNativeLibrariesCount++; + } + + seenNativeLibraryNames.Add (name); + uniqueNativeLibraries.Add (item); + } + + // libxamarin-app.so is not in NativeLibraries, but we must count it + if (!seenNativeLibraryNames.Contains ("libxamarin-app.so")) { + uniqueNativeLibraries.Add (new TaskItem ("libxamarin-app.so")); + packagedNativeLibrariesCount++; + } + } // Only copy to the real location if the contents actually changed var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "MonoPackageManager_Resources.java")); @@ -326,6 +350,7 @@ void AddEnvironment () BundledAssemblyNameWidth = assemblyNameWidth, MonoComponents = (MonoComponent)monoComponents, NativeLibraries = uniqueNativeLibraries, + PackagedNativeLibrariesCount = packagedNativeLibrariesCount, HaveAssemblyStore = UseAssemblyStore, AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, JNIEnvInitializeToken = jnienv_initialize_method_token, diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs index d4349ed1661..097f84dea99 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs @@ -194,6 +194,7 @@ sealed class XamarinAndroidBundledAssembly public MonoComponent MonoComponents { get; set; } public PackageNamingPolicy PackageNamingPolicy { get; set; } public List NativeLibraries { get; set; } + public uint PackagedNativeLibrariesCount { get; set; } public bool MarshalMethodsEnabled { get; set; } public bool ManagedMarshalMethodsLookupEnabled { get; set; } public bool IgnoreSplitConfigs { get; set; } @@ -248,7 +249,7 @@ protected override void Construct (LlvmIrModule module) environment_variable_count = (uint)(environmentVariables == null ? 0 : environmentVariables.Count * 2), system_property_count = (uint)(systemProperties == null ? 0 : systemProperties.Count * 2), number_of_assemblies_in_apk = (uint)NumberOfAssembliesInApk, - number_of_shared_libraries = (uint)NativeLibraries.Count, + number_of_shared_libraries = PackagedNativeLibrariesCount, bundled_assembly_name_width = (uint)BundledAssemblyNameWidth, number_of_dso_cache_entries = (uint)dsoCache.Count, number_of_aot_cache_entries = (uint)aotDsoCache.Count, diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index ed5608e9d2e..a58835f6fb7 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -351,8 +351,7 @@ namespace xamarin::android::internal { static bool all_required_zip_entries_found () noexcept { return - number_of_mapped_assembly_stores == number_of_assembly_store_files && number_of_zip_dso_entries >= application_config.number_of_shared_libraries - && ((application_config.have_runtime_config_blob && runtime_config_blob_found) || !application_config.have_runtime_config_blob); + number_of_mapped_assembly_stores == number_of_assembly_store_files && number_of_zip_dso_entries >= application_config.number_of_shared_libraries; } [[gnu::always_inline]] static c_unique_ptr to_utf8 (const MonoString *s) noexcept @@ -461,13 +460,13 @@ namespace xamarin::android::internal { #endif // DEBUG static inline const char *assemblies_prefix_override = nullptr; - static inline md_mmap_info runtime_config_blob_mmap{}; - static inline void *runtime_config_data = nullptr; - static inline size_t runtime_config_data_size = 0uz; - static inline bool runtime_config_blob_found = false; - static inline uint32_t number_of_mapped_assembly_stores = 0u; - static inline uint32_t number_of_zip_dso_entries = 0u; - static inline bool need_to_scan_more_apks = true; + md_mmap_info runtime_config_blob_mmap{}; + void *runtime_config_data = nullptr; + size_t runtime_config_data_size = 0uz; + bool runtime_config_blob_found = embedded_runtime_config_size > 0u; + uint32_t number_of_mapped_assembly_stores = 0u; + uint32_t number_of_zip_dso_entries = 0u; + bool need_to_scan_more_apks = true; static inline AssemblyStoreIndexEntry *assembly_store_hashes = nullptr; static inline xamarin::android::mutex assembly_decompress_mutex {}; From 9391224699f7085312efd3b2c70a82d4665f2e65 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 11 Oct 2024 12:14:24 +0200 Subject: [PATCH 14/60] Don't allocate memory for ZIP Central Directory data Instead use `mmap` --- .../mono/monodroid/embedded-assemblies-zip.cc | 56 ++++++++++--------- .../mono/monodroid/embedded-assemblies.hh | 15 ++--- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index c7236d4edbb..ac69313bf23 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -15,8 +15,8 @@ using namespace xamarin::android::internal; -[[gnu::always_inline]] bool -EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector const& buf, dynamic_local_string &entry_name, ZipEntryLoadState &state) noexcept +force_inline bool +EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::span const& buf, dynamic_local_string &entry_name, ZipEntryLoadState &state) noexcept { entry_name.clear (); @@ -150,8 +150,8 @@ EmbeddedAssemblies::store_individual_assembly_data (dynamic_local_string const& buf, uint32_t num_entries, [[maybe_unused]] monodroid_should_register should_register, ZipEntryLoadState &state) noexcept +force_inline void +EmbeddedAssemblies::zip_load_individual_assembly_entries (std::span const& buf, uint32_t num_entries, [[maybe_unused]] monodroid_should_register should_register, ZipEntryLoadState &state) noexcept { // TODO: do away with all the string manipulation here. Replace it with generating xxhash for the entry name dynamic_local_string entry_name; @@ -264,8 +264,8 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string verify_assembly_store_and_set_info (payload_start, entry_name.get ()); } -[[gnu::always_inline]] void -EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& buf, uint32_t num_entries, ZipEntryLoadState &state) noexcept +force_inline void +EmbeddedAssemblies::zip_load_assembly_store_entries (std::span const& buf, uint32_t num_entries, ZipEntryLoadState &state) noexcept { if (all_required_zip_entries_found ()) { return; @@ -344,26 +344,28 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus ) ); } -#ifdef DEBUG - log_info (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); - log_info (LOG_ASSEMBLY, "Central directory size: {}", cd_size); - log_info (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); -#endif - off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); - if (retval < 0) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Failed to seek to central directory position in APK: {}. retval={} errno={}, File={}", - std::strerror (errno), - retval, - errno, - optional_string (apk_name) - ) - ); - } - std::vector buf (cd_size); + md_mmap_info apk_map = md_mmap_apk_file (fd, cd_offset, cd_size, apk_name); + + log_debug (LOG_ASSEMBLY, "Central directory offset: %u", cd_offset); + log_debug (LOG_ASSEMBLY, "Central directory size: %u", cd_size); + log_debug (LOG_ASSEMBLY, "Central directory entries: %u", cd_entries); + + // off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); + // if (retval < 0) { + // Helpers::abort_application ( + // LOG_ASSEMBLY, + // Util::monodroid_strdup_printf ( + // "Failed to seek to central directory position in APK: %s. retval=%d errno=%d, File=%s", + // std::strerror (errno), + // retval, + // errno, + // apk_name + // ) + // ); + // } + + std::span buf (reinterpret_cast(apk_map.area), apk_map.size); const auto [prefix, prefix_len] = get_assemblies_prefix_and_length (); ZipEntryLoadState state { .file_fd = fd, @@ -399,6 +401,8 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus } else { zip_load_individual_assembly_entries (buf, cd_entries, should_register, state); } + + // TODO: unmap here } template @@ -660,7 +664,7 @@ EmbeddedAssemblies::zip_read_field (T const& buf, size_t index, size_t count, dy } bool -EmbeddedAssemblies::zip_read_entry_info (std::vector const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state) noexcept +EmbeddedAssemblies::zip_read_entry_info (std::span const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state) { constexpr size_t CD_COMPRESSION_METHOD_OFFSET = 10uz; constexpr size_t CD_UNCOMPRESSED_SIZE_OFFSET = 24uz; diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index a58835f6fb7..635f7b973ef 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -267,12 +268,12 @@ namespace xamarin::android::internal { static void get_assembly_data (XamarinAndroidBundledAssembly const& e, uint8_t*& assembly_data, uint32_t& assembly_data_size) noexcept; static void get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, uint8_t*& assembly_data, uint32_t& assembly_data_size) noexcept; - static void zip_load_entries (int fd, const char *apk_name, monodroid_should_register should_register) noexcept; - static void zip_load_individual_assembly_entries (std::vector const& buf, uint32_t num_entries, monodroid_should_register should_register, ZipEntryLoadState &state) noexcept; - static void zip_load_assembly_store_entries (std::vector const& buf, uint32_t num_entries, ZipEntryLoadState &state) noexcept; - static bool zip_load_entry_common (size_t entry_index, std::vector const& buf, dynamic_local_string &entry_name, ZipEntryLoadState &state) noexcept; - static bool zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; - static bool zip_adjust_data_offset (int fd, ZipEntryLoadState &state) noexcept; + void zip_load_entries (int fd, const char *apk_name, monodroid_should_register should_register); + void zip_load_individual_assembly_entries (std::span const& buf, uint32_t num_entries, monodroid_should_register should_register, ZipEntryLoadState &state) noexcept; + void zip_load_assembly_store_entries (std::span const& buf, uint32_t num_entries, ZipEntryLoadState &state) noexcept; + bool zip_load_entry_common (size_t entry_index, std::span const& buf, dynamic_local_string &entry_name, ZipEntryLoadState &state) noexcept; + bool zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries); + bool zip_adjust_data_offset (int fd, ZipEntryLoadState &state); template static bool zip_extract_cd_info (std::array const& buf, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; @@ -292,7 +293,7 @@ namespace xamarin::android::internal { template static bool zip_read_field (T const& buf, size_t index, size_t count, dynamic_local_string& characters) noexcept; - static bool zip_read_entry_info (std::vector const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state) noexcept; + bool zip_read_entry_info (std::span const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state); [[gnu::always_inline]] static std::tuple get_wrapper_dso_payload_pointer_and_size (md_mmap_info const& map_info, const char *file_name) noexcept From 955da119afab124db6889a1cf223c563a60b1848 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 11 Oct 2024 19:43:06 +0200 Subject: [PATCH 15/60] Experimenting with zip scanning performance --- .../mono/monodroid/embedded-assemblies-zip.cc | 10 ++--- .../mono/monodroid/embedded-assemblies.cc | 45 ------------------- .../mono/monodroid/embedded-assemblies.hh | 38 +++++++++++++++- 3 files changed, 40 insertions(+), 53 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index ac69313bf23..df93b483a01 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -328,6 +328,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::span const& b } } +[[gnu::flatten]] void EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unused]] monodroid_should_register should_register) noexcept { @@ -335,7 +336,7 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus uint32_t cd_size; uint16_t cd_entries; - if (!zip_read_cd_info (fd, cd_offset, cd_size, cd_entries)) { + if (!zip_read_cd_info (fd, cd_offset, cd_size, cd_entries)) [[unlikely]] { Helpers::abort_application ( LOG_ASSEMBLY, std::format ( @@ -345,14 +346,12 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus ); } - md_mmap_info apk_map = md_mmap_apk_file (fd, cd_offset, cd_size, apk_name); - log_debug (LOG_ASSEMBLY, "Central directory offset: %u", cd_offset); log_debug (LOG_ASSEMBLY, "Central directory size: %u", cd_size); log_debug (LOG_ASSEMBLY, "Central directory entries: %u", cd_entries); // off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); - // if (retval < 0) { + // if (retval < 0) [[unlikely]] { // Helpers::abort_application ( // LOG_ASSEMBLY, // Util::monodroid_strdup_printf ( @@ -365,7 +364,6 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus // ); // } - std::span buf (reinterpret_cast(apk_map.area), apk_map.size); const auto [prefix, prefix_len] = get_assemblies_prefix_and_length (); ZipEntryLoadState state { .file_fd = fd, @@ -402,7 +400,7 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus zip_load_individual_assembly_entries (buf, cd_entries, should_register, state); } - // TODO: unmap here + //delete[] raw_data; } template diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index c35324f408b..98e80d8a289 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -910,51 +910,6 @@ EmbeddedAssemblies::typemap_managed_to_java (MonoReflectionType *reflection_type return ret; } -EmbeddedAssemblies::md_mmap_info -EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, const char* filename) -{ - md_mmap_info file_info; - md_mmap_info mmap_info; - - size_t pageSize = static_cast(Util::monodroid_getpagesize ()); - size_t offsetFromPage = offset % pageSize; - size_t offsetPage = offset - offsetFromPage; - size_t offsetSize = size + offsetFromPage; - - mmap_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast(offsetPage)); - - if (mmap_info.area == MAP_FAILED) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Could not mmap APK fd {}: {}; File={}", - fd, - strerror (errno), - optional_string (filename) - ) - ); - } - - mmap_info.size = offsetSize; - file_info.area = pointer_add (mmap_info.area, offsetFromPage); - file_info.size = size; - - log_info ( - LOG_ASSEMBLY, - " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", - mmap_info.area, - pointer_add (mmap_info.area, mmap_info.size), - mmap_info.size, - file_info.area, - pointer_add (file_info.area, file_info.size), - file_info.size, - fd, - optional_string (filename) - ); - - return file_info; -} - void EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodroid_should_register should_register) noexcept { diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 635f7b973ef..63ac8bd655a 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -27,7 +27,7 @@ #include #include "cppcompat.hh" #include "shared-constants.hh" -#include +#include "xxhash.hh" #include "util.hh" #include @@ -259,7 +259,41 @@ namespace xamarin::android::internal { static const TypeMapEntry *typemap_managed_to_java (const char *managed_type_name) noexcept; #endif // DEBUG - static md_mmap_info md_mmap_apk_file (int fd, uint32_t offset, size_t size, const char* filename); + [[gnu::always_inline]] + static md_mmap_info md_mmap_apk_file (int fd, uint32_t offset, size_t size, const char* filename, md_mmap_info &original_info, md_mmap_info &adjusted_info) noexcept + { + size_t pageSize = static_cast(Util::monodroid_getpagesize ()); + size_t offsetFromPage = offset % pageSize; + size_t offsetPage = offset - offsetFromPage; + size_t offsetSize = size + offsetFromPage; + + original_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast(offsetPage)); + + if (original_info.area == MAP_FAILED) { + log_fatal (LOG_DEFAULT, "Could not `mmap` apk fd %d entry `%s`: %s", fd, filename, strerror (errno)); + Helpers::abort_application (); + } + + original_info.size = offsetSize; + adjusted_info.area = (void*)((const char*)original_info.area + offsetFromPage); + adjusted_info.size = size; + + log_info (LOG_ASSEMBLY, " mmap_start: %08p mmap_end: %08p mmap_len: % 12u file_start: %08p file_end: %08p file_len: % 12u apk descriptor: %d file: %s", + original_info.area, reinterpret_cast (original_info.area) + original_info.size, original_info.size, + adjusted_info.area, reinterpret_cast (adjusted_info.area) + adjusted_info.size, adjusted_info.size, fd, filename); + + return adjusted_info; + } + + [[gnu::flatten, gnu::always_inline]] + static md_mmap_info md_mmap_apk_file (int fd, uint32_t offset, size_t size, const char* filename) noexcept + { + md_mmap_info file_info; + md_mmap_info mmap_info; + + return md_mmap_apk_file (fd, offset, size, filename, mmap_info, file_info); + } + static MonoAssembly* open_from_bundles_full (MonoAssemblyName *aname, char **assemblies_path, void *user_data); static MonoAssembly* open_from_bundles (MonoAssemblyLoadContextGCHandle alc_gchandle, MonoAssemblyName *aname, char **assemblies_path, void *user_data, MonoError *error); From dee133a2fa956967e4aae3b3bb3bde5839573af6 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 15 Oct 2024 12:16:50 +0200 Subject: [PATCH 16/60] Post rebase fixups --- src/native/mono/monodroid/embedded-assemblies.hh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 63ac8bd655a..f040c3be509 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -270,17 +270,25 @@ namespace xamarin::android::internal { original_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast(offsetPage)); if (original_info.area == MAP_FAILED) { - log_fatal (LOG_DEFAULT, "Could not `mmap` apk fd %d entry `%s`: %s", fd, filename, strerror (errno)); - Helpers::abort_application (); + Helpers::abort_application ( + LOG_ASSEMBLY, + Util::monodroid_strdup_printf ( + "Could not mmap APK fd %d: %s; File=%s", + fd, + strerror (errno), + filename + ) + ); } original_info.size = offsetSize; adjusted_info.area = (void*)((const char*)original_info.area + offsetFromPage); adjusted_info.size = size; - log_info (LOG_ASSEMBLY, " mmap_start: %08p mmap_end: %08p mmap_len: % 12u file_start: %08p file_end: %08p file_len: % 12u apk descriptor: %d file: %s", + log_info (LOG_ASSEMBLY, "mmap_start: %08p mmap_end: %08p mmap_len: % 12u file_start: %08p file_end: %08p file_len: % 12u; apk descriptor: %d; file: %s", original_info.area, reinterpret_cast (original_info.area) + original_info.size, original_info.size, - adjusted_info.area, reinterpret_cast (adjusted_info.area) + adjusted_info.size, adjusted_info.size, fd, filename); + adjusted_info.area, reinterpret_cast (adjusted_info.area) + adjusted_info.size, adjusted_info.size, fd, filename + ); return adjusted_info; } From a27f435fc08d8801232d77699d047922fb511612 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 15 Oct 2024 12:31:45 +0200 Subject: [PATCH 17/60] More post rebase fixups --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index df93b483a01..cedf27e29d0 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -194,7 +194,7 @@ EmbeddedAssemblies::verify_assembly_store_and_set_info (void *data_start, const LOG_ASSEMBLY, Util::monodroid_strdup_printf ( "Assembly store '%s' is not a valid .NET for Android assembly store file", - entry_name.get () + name ) ); } @@ -204,7 +204,7 @@ EmbeddedAssemblies::verify_assembly_store_and_set_info (void *data_start, const LOG_ASSEMBLY, Util::monodroid_strdup_printf ( "Assembly store '%s' uses format version 0x%x, instead of the expected 0x%x", - entry_name.get (), + name, header->version, ASSEMBLY_STORE_FORMAT_VERSION ) From 963d76077346b51d9fbccafe0a95949cdc1874b9 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 15 Oct 2024 16:29:28 +0200 Subject: [PATCH 18/60] seek and ye shall read --- .../mono/monodroid/embedded-assemblies-zip.cc | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index cedf27e29d0..3171778d719 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -350,19 +350,19 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus log_debug (LOG_ASSEMBLY, "Central directory size: %u", cd_size); log_debug (LOG_ASSEMBLY, "Central directory entries: %u", cd_entries); - // off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); - // if (retval < 0) [[unlikely]] { - // Helpers::abort_application ( - // LOG_ASSEMBLY, - // Util::monodroid_strdup_printf ( - // "Failed to seek to central directory position in APK: %s. retval=%d errno=%d, File=%s", - // std::strerror (errno), - // retval, - // errno, - // apk_name - // ) - // ); - // } + off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); + if (retval < 0) [[unlikely]] { + Helpers::abort_application ( + LOG_ASSEMBLY, + Util::monodroid_strdup_printf ( + "Failed to seek to central directory position in APK: %s. retval=%d errno=%d, File=%s", + std::strerror (errno), + retval, + errno, + apk_name + ) + ); + } const auto [prefix, prefix_len] = get_assemblies_prefix_and_length (); ZipEntryLoadState state { From 460dc65947817a88b901a455885cb83e490bc596 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 16 Oct 2024 14:05:16 +0200 Subject: [PATCH 19/60] Details, details... --- .../Xamarin.Android.Common.targets | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index bd921b66859..5c685584b63 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2379,8 +2379,8 @@ because xbuild doesn't support framework reference assemblies. ZipAlignmentPages="$(AndroidZipAlignment)" UseAssemblyStore="$(AndroidUseAssemblyStore)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - IntermediateOutputPath="$(IntermediateOutputPath)"> - CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + IntermediateOutputPath="$(IntermediateOutputPath)" + CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)" AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)"> @@ -2450,8 +2450,8 @@ because xbuild doesn't support framework reference assemblies. CheckedBuild="$(_AndroidCheckedBuild)" ZipAlignmentPages="$(AndroidZipAlignment)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - IntermediateOutputPath="$(IntermediateOutputPath)"> - CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + IntermediateOutputPath="$(IntermediateOutputPath)" + CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)" AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)"> @@ -2525,8 +2525,8 @@ because xbuild doesn't support framework reference assemblies. ZipFlushSizeLimit="$(_ZipFlushSizeLimit)" ExcludeFiles="@(AndroidPackagingOptionsExclude)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - IntermediateOutputPath="$(IntermediateOutputPath)"> - CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + IntermediateOutputPath="$(IntermediateOutputPath)" + CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)" AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)"> @@ -2566,8 +2566,8 @@ because xbuild doesn't support framework reference assemblies. ZipFlushSizeLimit="$(_ZipFlushSizeLimit)" ExcludeFiles="@(AndroidPackagingOptionsExclude)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - IntermediateOutputPath="$(IntermediateOutputPath)"> - CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)"> + IntermediateOutputPath="$(IntermediateOutputPath)" + CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)" AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)"> From 001cfd8eb7c4592f48323bbd6f0a6cee2d465e53 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 16 Oct 2024 17:38:54 +0200 Subject: [PATCH 20/60] Cleanup --- .../Xamarin.Android.Common.targets | 10 ++++++---- src/native/mono/monodroid/embedded-assemblies-zip.cc | 11 ----------- src/native/mono/monodroid/embedded-assemblies.hh | 7 +------ src/native/mono/monodroid/monodroid-glue.cc | 7 ------- 4 files changed, 7 insertions(+), 28 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 5c685584b63..038628923a1 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -311,6 +311,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' And '$(EmbedAssembliesIntoApk)' == 'False' ">True <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' ">False + <_AndroidCompressedAssembliesDir>$(IntermediateOutputPath)android\lz4 @@ -2067,7 +2068,7 @@ because xbuild doesn't support framework reference assemblies. <_CompileToDalvikDependsOnTargets> _CompileJava; - _RemoveRegisterAttribute; + _RemoveRegisterAttribute; _CreateApplicationSharedLibraries; _GetMonoPlatformJarPath; _GetLibraryImports; @@ -2371,7 +2372,6 @@ because xbuild doesn't support framework reference assemblies. ProjectFullPath="$(MSBuildProjectFullPath)" IncludeWrapSh="$(AndroidIncludeWrapSh)" CheckedBuild="$(_AndroidCheckedBuild)" - RuntimeConfigBinFilePath="$(_BinaryRuntimeConfigPath)" ExcludeFiles="@(AndroidPackagingOptionsExclude)" IncludeFiles="@(AndroidPackagingOptionsInclude)" ZipFlushFilesLimit="$(_ZipFlushFilesLimit)" @@ -2448,6 +2448,10 @@ because xbuild doesn't support framework reference assemblies. SupportedAbis="@(_BuildTargetAbis)" IncludeWrapSh="$(AndroidIncludeWrapSh)" CheckedBuild="$(_AndroidCheckedBuild)" + ExcludeFiles="@(AndroidPackagingOptionsExclude)" + IncludeFiles="@(AndroidPackagingOptionsInclude)" + ZipFlushFilesLimit="$(_ZipFlushFilesLimit)" + ZipFlushSizeLimit="$(_ZipFlushSizeLimit)" ZipAlignmentPages="$(AndroidZipAlignment)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" IntermediateOutputPath="$(IntermediateOutputPath)" @@ -2520,7 +2524,6 @@ because xbuild doesn't support framework reference assemblies. ProjectFullPath="$(MSBuildProjectFullPath)" IncludeWrapSh="$(AndroidIncludeWrapSh)" CheckedBuild="$(_AndroidCheckedBuild)" - RuntimeConfigBinFilePath="$(_BinaryRuntimeConfigPath)" ZipFlushFilesLimit="$(_ZipFlushFilesLimit)" ZipFlushSizeLimit="$(_ZipFlushSizeLimit)" ExcludeFiles="@(AndroidPackagingOptionsExclude)" @@ -2561,7 +2564,6 @@ because xbuild doesn't support framework reference assemblies. ProjectFullPath="$(MSBuildProjectFullPath)" IncludeWrapSh="$(AndroidIncludeWrapSh)" CheckedBuild="$(_AndroidCheckedBuild)" - RuntimeConfigBinFilePath="$(_BinaryRuntimeConfigPath)" ZipFlushFilesLimit="$(_ZipFlushFilesLimit)" ZipFlushSizeLimit="$(_ZipFlushSizeLimit)" ExcludeFiles="@(AndroidPackagingOptionsExclude)" diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 3171778d719..a554f3ef9bf 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -62,14 +62,6 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::span const& b dynamic_local_string entry_name; bool assembly_store_found = embedded_assembly_store_size != 0; if (assembly_store_found) { - log_debug (LOG_ASSEMBLY, "Got embedded assembly store, size %zu", embedded_assembly_store_size); verify_assembly_store_and_set_info (embedded_assembly_store, "embedded"); log_debug (LOG_ASSEMBLY, "Looking for DSOs in APK"); } else { @@ -399,8 +390,6 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus } else { zip_load_individual_assembly_entries (buf, cd_entries, should_register, state); } - - //delete[] raw_data; } template diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index f040c3be509..db110d7f426 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -194,12 +194,7 @@ namespace xamarin::android::internal { runtime_config_data_size = 0uz; } - static bool have_runtime_config_blob () noexcept - { - return application_config.have_runtime_config_blob && runtime_config_blob_mmap.area != nullptr; - } - - static bool keep_scanning () noexcept + bool keep_scanning () const noexcept { return need_to_scan_more_apks; } diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 727681bf268..df82db42457 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -728,7 +728,6 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks gather_bundled_assemblies (runtimeApks, &user_assemblies_count, have_split_apks); - // if (embeddedAssemblies.have_runtime_config_blob ()) { if (embedded_runtime_config_size > 0) { size_t blob_time_index; if (FastTiming::enabled ()) [[unlikely]] { @@ -736,7 +735,6 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks } runtime_config_args.kind = 1; -// embeddedAssemblies.get_runtime_config_blob (runtime_config_args.runtimeconfig.data.data, runtime_config_args.runtimeconfig.data.data_len); runtime_config_args.runtimeconfig.data.data = reinterpret_cast(embedded_runtime_config); runtime_config_args.runtimeconfig.data.data_len = static_cast(embedded_runtime_config_size); monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); @@ -1410,11 +1408,6 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl Logger::init_logging_categories (mono_log_mask_raw, mono_log_level_raw); - // log_warn (LOG_DEFAULT, "Embedded runtime config size: %zu", embedded_runtime_config_size); - // if (embedded_runtime_config_size > 0) { - // log_warn (LOG_DEFAULT, "First byte of embedded runtime config: 0x%x", embedded_runtime_config[0]); - // } - std::unique_ptr mono_log_mask (mono_log_mask_raw); std::unique_ptr mono_log_level (mono_log_level_raw); From 0907f4d76cb5b6c4e9c44804bc5dc202a67bb767 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 16 Oct 2024 17:39:06 +0200 Subject: [PATCH 21/60] Teach assembly store explorer about embedded stores --- .../Utilities/ELFHelper.Basic.cs | 61 ++++++++++++++++ .../Utilities/ELFHelper.cs | 26 +------ .../AssemblyStore/ELFPayloadError.cs | 1 + .../AssemblyStore/StoreReader_V2.cs | 47 ++++++++---- .../AssemblyStore/Utils.cs | 73 +++++++++++++++---- .../assembly-store-reader.csproj | 1 + 6 files changed, 155 insertions(+), 54 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.Basic.cs diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.Basic.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.Basic.cs new file mode 100644 index 00000000000..df401b2f462 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.Basic.cs @@ -0,0 +1,61 @@ +using System; + +using ELFSharp.ELF; +using ELFSharp.ELF.Sections; + +namespace Xamarin.Android.Tasks; + +static partial class ELFHelper +{ + public static ISymbolTable? GetSymbolTable (IELF elf, string sectionName) + { + ISection? section = GetSection (elf, sectionName); + if (section == null) { + return null; + } + + var symtab = section as ISymbolTable; + if (symtab == null) { + return null; + } + + return symtab; + } + + public static ISection? GetSection (IELF elf, string sectionName) + { + if (!elf.TryGetSection (sectionName, out ISection section)) { + return null; + } + + return section; + } + + public static SymbolEntry? FindSymbol (ISymbolTable? symbolTable, string symbolName) where T: struct + { + if (symbolTable == null) { + return null; + } + + ISymbolEntry? symbol = null; + foreach (ISymbolEntry entry in symbolTable.Entries) { + if (String.Compare (entry.Name, symbolName, StringComparison.Ordinal) != 0) { + continue; + } + + symbol = entry; + break; + } + + if (symbol == null) { + return null; + } + + Type t = typeof(T); + if (t == typeof(ulong) || t == typeof(uint)) { + return (SymbolEntry)symbol; + } + + throw new InvalidOperationException ($"Only `ulong` and `uint` types are accepted"); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs index 5c4879dc323..f51b9fb30b9 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs @@ -16,7 +16,7 @@ namespace Xamarin.Android.Tasks { - static class ELFHelper + static partial class ELFHelper { public static void AssertValidLibraryAlignment (TaskLoggingHelper log, int alignmentInPages, string path, ITaskItem? item) { @@ -226,29 +226,5 @@ bool IsNonEmptyCodeSymbol (SymbolEntry? symbolEntry) where T : struct return size != 0 && symbolEntry.PointedSection.Type == ELFSectionType.ProgBits; } } - - static ISymbolTable? GetSymbolTable (IELF elf, string sectionName) - { - ISection? section = GetSection (elf, sectionName); - if (section == null) { - return null; - } - - var symtab = section as ISymbolTable; - if (symtab == null) { - return null; - } - - return symtab; - } - - static ISection? GetSection (IELF elf, string sectionName) - { - if (!elf.TryGetSection (sectionName, out ISection section)) { - return null; - } - - return section; - } } } diff --git a/tools/assembly-store-reader-mk2/AssemblyStore/ELFPayloadError.cs b/tools/assembly-store-reader-mk2/AssemblyStore/ELFPayloadError.cs index 932f151c80f..78372c26853 100644 --- a/tools/assembly-store-reader-mk2/AssemblyStore/ELFPayloadError.cs +++ b/tools/assembly-store-reader-mk2/AssemblyStore/ELFPayloadError.cs @@ -8,4 +8,5 @@ enum ELFPayloadError NotSharedLibrary, NotLittleEndian, NoPayloadSection, + NoEmbeddedStore, } diff --git a/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs b/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs index a43960102e2..1fc93530a66 100644 --- a/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs +++ b/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs @@ -86,6 +86,19 @@ public StoreReader_V2 (Stream store, string path) protected override ulong GetStoreStartDataOffset () => elfOffset; + string PayloadErrorToString (ELFPayloadError error) + { + return error switch { + ELFPayloadError.NotELF => $"Store '{StorePath}' is not a valid ELF binary", + ELFPayloadError.LoadFailed => $"Store '{StorePath}' could not be loaded", + ELFPayloadError.NotSharedLibrary => $"Store '{StorePath}' is not a shared ELF library", + ELFPayloadError.NotLittleEndian => $"Store '{StorePath}' is not a little-endian ELF image", + ELFPayloadError.NoPayloadSection => $"Store '{StorePath}' does not contain the 'payload' section", + ELFPayloadError.NoEmbeddedStore => $"Store '{StorePath}' does not contain embedded data blob", + _ => $"Unknown ELF payload section error for store '{StorePath}': {error}" + }; + } + protected override bool IsSupported () { StoreStream.Seek (0, SeekOrigin.Begin); @@ -94,22 +107,19 @@ protected override bool IsSupported () uint magic = reader.ReadUInt32 (); if (magic == Utils.ELF_MAGIC) { ELFPayloadError error; - (elfOffset, _, error) = Utils.FindELFPayloadSectionOffsetAndSize (StoreStream); - + (elfOffset, _, error) = Utils.FindEmbeddedStoreOffsetAndSize (StoreStream); if (error != ELFPayloadError.None) { - string message = error switch { - ELFPayloadError.NotELF => $"Store '{StorePath}' is not a valid ELF binary", - ELFPayloadError.LoadFailed => $"Store '{StorePath}' could not be loaded", - ELFPayloadError.NotSharedLibrary => $"Store '{StorePath}' is not a shared ELF library", - ELFPayloadError.NotLittleEndian => $"Store '{StorePath}' is not a little-endian ELF image", - ELFPayloadError.NoPayloadSection => $"Store '{StorePath}' does not contain the 'payload' section", - _ => $"Unknown ELF payload section error for store '{StorePath}': {error}" - }; - Log.Debug (message); - } else if (elfOffset >= 0) { - StoreStream.Seek ((long)elfOffset, SeekOrigin.Begin); - magic = reader.ReadUInt32 (); + MaybeLogError (error); + + (elfOffset, _, error) = Utils.FindELFPayloadSectionOffsetAndSize (StoreStream); + if (error != ELFPayloadError.None) { + MaybeLogError (error); + return false; + } } + + StoreStream.Seek ((long)elfOffset, SeekOrigin.Begin); + magic = reader.ReadUInt32 (); } if (magic != Utils.ASSEMBLY_STORE_MAGIC) { @@ -129,6 +139,15 @@ protected override bool IsSupported () header = new Header (magic, version, entry_count, index_entry_count, index_size); return true; + + void MaybeLogError (ELFPayloadError error) + { + if (error == ELFPayloadError.None) { + return; + } + + Log.Debug (PayloadErrorToString (error)); + } } protected override void Prepare () diff --git a/tools/assembly-store-reader-mk2/AssemblyStore/Utils.cs b/tools/assembly-store-reader-mk2/AssemblyStore/Utils.cs index 284f501c9ac..2e2f03e5e52 100644 --- a/tools/assembly-store-reader-mk2/AssemblyStore/Utils.cs +++ b/tools/assembly-store-reader-mk2/AssemblyStore/Utils.cs @@ -4,6 +4,7 @@ using ELFSharp.ELF; using ELFSharp.ELF.Sections; +using Xamarin.Android.Tasks; using Xamarin.Tools.Zip; namespace Xamarin.Android.AssemblyStore; @@ -29,31 +30,28 @@ static class Utils public static readonly ArrayPool BytePool = ArrayPool.Shared; - public static (ulong offset, ulong size, ELFPayloadError error) FindELFPayloadSectionOffsetAndSize (Stream stream) + static (bool is64, IELF? elf, ELFPayloadError error) TryOpenELF (Stream stream) { + bool is64 = false; stream.Seek (0, SeekOrigin.Begin); Class elfClass = ELFReader.CheckELFType (stream); if (elfClass == Class.NotELF) { - return ReturnError (null, ELFPayloadError.NotELF); + return ReturnError (is64, null, ELFPayloadError.NotELF); } if (!ELFReader.TryLoad (stream, shouldOwnStream: false, out IELF? elf)) { - return ReturnError (elf, ELFPayloadError.LoadFailed); + return ReturnError (is64, elf, ELFPayloadError.LoadFailed); } if (elf.Type != FileType.SharedObject) { - return ReturnError (elf, ELFPayloadError.NotSharedLibrary); + return ReturnError (is64, elf, ELFPayloadError.NotSharedLibrary); } if (elf.Endianess != ELFSharp.Endianess.LittleEndian) { - return ReturnError (elf, ELFPayloadError.NotLittleEndian); - } - - if (!elf.TryGetSection ("payload", out ISection? payloadSection)) { - return ReturnError (elf, ELFPayloadError.NoPayloadSection); + return ReturnError (is64, elf, ELFPayloadError.NotLittleEndian); } - bool is64 = elf.Machine switch { + is64 = elf.Machine switch { Machine.ARM => false, Machine.Intel386 => false, @@ -63,6 +61,51 @@ public static (ulong offset, ulong size, ELFPayloadError error) FindELFPayloadSe _ => throw new NotSupportedException ($"Unsupported ELF architecture '{elf.Machine}'") }; + return (is64, elf, ELFPayloadError.None); + + (bool is64, IELF? elf, ELFPayloadError error) ReturnError (bool is64, IELF? elf, ELFPayloadError error) + { + elf?.Dispose (); + + return (is64, null, error); + } + } + + public static (ulong offset, ulong size, ELFPayloadError error) FindEmbeddedStoreOffsetAndSize (Stream stream) + { + (bool is64, IELF? elf, ELFPayloadError error) = TryOpenELF (stream); + if (elf == null || error != ELFPayloadError.None) { + return ReturnError (elf, error); + } + + const string SymbolName = "embedded_assembly_store"; + ISymbolTable? dynsym = ELFHelper.GetSymbolTable (elf, ".dynsym"); + if (is64) { + SymbolEntry? symbol = ELFHelper.FindSymbol (dynsym, SymbolName); + if (symbol != null) { + return (symbol.Value, symbol.Size, ELFPayloadError.None); + } + } else { + SymbolEntry? symbol = ELFHelper.FindSymbol (dynsym, SymbolName); + if (symbol != null) { + return ((ulong)symbol.Value, (ulong)symbol.Size, ELFPayloadError.None); + } + } + + return (0, 0, ELFPayloadError.NoEmbeddedStore); + } + + public static (ulong offset, ulong size, ELFPayloadError error) FindELFPayloadSectionOffsetAndSize (Stream stream) + { + (bool is64, IELF? elf, ELFPayloadError error) = TryOpenELF (stream); + if (elf == null || error != ELFPayloadError.None) { + return ReturnError (elf, error); + } + + if (!elf.TryGetSection ("payload", out ISection? payloadSection)) { + return ReturnError (elf, ELFPayloadError.NoPayloadSection); + } + ulong offset; ulong size; @@ -84,13 +127,13 @@ public static (ulong offset, ulong size, ELFPayloadError error) FindELFPayloadSe { return ((ulong)payload.Offset, (ulong)payload.Size); } + } - (ulong offset, ulong size, ELFPayloadError error) ReturnError (IELF? elf, ELFPayloadError error) - { - elf?.Dispose (); + static (ulong offset, ulong size, ELFPayloadError error) ReturnError (IELF? elf, ELFPayloadError error) + { + elf?.Dispose (); - return (0, 0, error); - } + return (0, 0, error); } public static (FileFormat format, FileInfo? info) DetectFileFormat (string path) diff --git a/tools/assembly-store-reader-mk2/assembly-store-reader.csproj b/tools/assembly-store-reader-mk2/assembly-store-reader.csproj index ec4c90fecb1..3bd2852d04e 100644 --- a/tools/assembly-store-reader-mk2/assembly-store-reader.csproj +++ b/tools/assembly-store-reader-mk2/assembly-store-reader.csproj @@ -24,6 +24,7 @@ + From 94d1a6a3cada80f7b4f00b4bb1cbfb4bc96412f4 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 16 Oct 2024 17:47:22 +0200 Subject: [PATCH 22/60] Teach store v2 reader to look in `libxamarin-app.so`, too --- .../AssemblyStore/StoreReader_V2.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs b/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs index 1fc93530a66..1ba0cb8b488 100644 --- a/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs +++ b/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs @@ -40,6 +40,11 @@ static StoreReader_V2 () GetArchPath (AndroidTargetArch.Arm), GetArchPath (AndroidTargetArch.X86_64), GetArchPath (AndroidTargetArch.X86), + + GetArchPath (AndroidTargetArch.Arm64, embeddedBlob: true), + GetArchPath (AndroidTargetArch.Arm, embeddedBlob: true), + GetArchPath (AndroidTargetArch.X86_64, embeddedBlob: true), + GetArchPath (AndroidTargetArch.X86, embeddedBlob: true), }; ApkPaths = paths.AsReadOnly (); AabBasePaths = ApkPaths; @@ -50,10 +55,15 @@ static StoreReader_V2 () GetArchPath (AndroidTargetArch.Arm, AabBaseDir), GetArchPath (AndroidTargetArch.X86_64, AabBaseDir), GetArchPath (AndroidTargetArch.X86, AabBaseDir), + + GetArchPath (AndroidTargetArch.Arm64, AabBaseDir, embeddedBlob: true), + GetArchPath (AndroidTargetArch.Arm, AabBaseDir, embeddedBlob: true), + GetArchPath (AndroidTargetArch.X86_64, AabBaseDir, embeddedBlob: true), + GetArchPath (AndroidTargetArch.X86, AabBaseDir, embeddedBlob: true), }; AabPaths = paths.AsReadOnly (); - string GetArchPath (AndroidTargetArch arch, string? root = null) + string GetArchPath (AndroidTargetArch arch, string? root = null, bool embeddedBlob = false) { const string LibDirName = "lib"; @@ -65,7 +75,9 @@ string GetArchPath (AndroidTargetArch arch, string? root = null) root = LibDirName; } parts.Add (abi); - parts.Add (GetBlobName (abi)); + parts.Add ( + embeddedBlob ? "libxamarin-app.so" : GetBlobName (abi) + ); return MonoAndroidHelper.MakeZipArchivePath (root, parts); } From fd91482020fdf1b3ca782d6ce307b40b77fb468b Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 16 Oct 2024 17:48:55 +0200 Subject: [PATCH 23/60] Nicer --- .../AssemblyStore/StoreReader_V2.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs b/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs index 1ba0cb8b488..fbccf1bdb94 100644 --- a/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs +++ b/tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs @@ -75,9 +75,7 @@ string GetArchPath (AndroidTargetArch arch, string? root = null, bool embeddedBl root = LibDirName; } parts.Add (abi); - parts.Add ( - embeddedBlob ? "libxamarin-app.so" : GetBlobName (abi) - ); + parts.Add (GetBlobName (abi, embeddedBlob)); return MonoAndroidHelper.MakeZipArchivePath (root, parts); } @@ -94,7 +92,7 @@ public StoreReader_V2 (Stream store, string path) }; } - static string GetBlobName (string abi) => $"libassemblies.{abi}.blob.so"; + static string GetBlobName (string abi, bool embeddedBlob) => embeddedBlob ? "libxamarin-app.so" : $"libassemblies.{abi}.blob.so"; protected override ulong GetStoreStartDataOffset () => elfOffset; From 7a063b31e89efe523f193f6bdcdd5ec7a8de9622 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 17 Oct 2024 10:02:47 +0200 Subject: [PATCH 24/60] The runtime configuration blob is now part of `libxamarin-app.so` --- .../Tests/Xamarin.Android.Build.Tests/PackagingTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs index 21f48d77025..23cca31ecbe 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs @@ -129,7 +129,6 @@ public void CheckIncludedAssemblies ([Values (false, true)] bool usesAssemblySto "System.Collections.dll", "System.Collections.Concurrent.dll", "System.Text.RegularExpressions.dll", - "libarc.bin.so", }; using (var b = CreateApkBuilder ()) { From f9f555636323408b1c1da0a09f266c66e704ec8a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 17 Oct 2024 11:14:14 +0200 Subject: [PATCH 25/60] Optionally produce "empty" embed.*.s files Even though we might not have any content to embed, we need the symbols to be present, because they're part of the `libxamarin-app.so` ABI expected by `libmonodroid.so` --- .../Tasks/CreateEmbeddedAssemblyStore.cs | 3 +- .../Tasks/GeneratePackageManagerJava.cs | 29 +++++----- .../Utilities/ELFEmbeddingHelper.cs | 58 ++++++++++++++----- 3 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs index 26c5394ff9e..288f52be3db 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs @@ -84,7 +84,8 @@ public override bool RunTask () AndroidBinUtilsDirectory, inputFile, ELFEmbeddingHelper.KnownEmbedItems.AssemblyStore, - AssemblySourcesDir + AssemblySourcesDir, + missingContentOK: false ); if (items.Count == 0) { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 20c501d58ac..72ed235721a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -62,7 +62,9 @@ public override bool RunTask () [Required] public bool EnablePreloadAssembliesDefault { get; set; } - [Required] + // This property should be required but it can't, because during design time builds there's no + // value to pass and MSBuild signals an error that a required property wasn't given a value. + //[Required] public string AndroidBinUtilsDirectory { get; set; } [Required] @@ -318,20 +320,17 @@ void AddEnvironment () var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "MonoPackageManager_Resources.java")); bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); - if (haveRuntimeConfigBlob) { - List objectFilePaths = ELFEmbeddingHelper.EmbedBinary ( - Log, - SupportedAbis, - AndroidBinUtilsDirectory, - RuntimeConfigBinFilePath, - ELFEmbeddingHelper.KnownEmbedItems.RuntimeConfig, - EnvironmentOutputDirectory - ); - - EmbeddedObjectFiles = objectFilePaths.ToArray (); - } else { - EmbeddedObjectFiles = Array.Empty (); - } + List objectFilePaths = ELFEmbeddingHelper.EmbedBinary ( + Log, + SupportedAbis, + AndroidBinUtilsDirectory, + RuntimeConfigBinFilePath, + ELFEmbeddingHelper.KnownEmbedItems.RuntimeConfig, + EnvironmentOutputDirectory, + missingContentOK: !haveRuntimeConfigBlob + ); + + EmbeddedObjectFiles = objectFilePaths.ToArray (); var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); var appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs index 56f399913f2..9116cabcd58 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs @@ -62,9 +62,10 @@ public static List EmbedBinary ( TaskLoggingHelper log, ICollection supportedAbis, string androidBinUtilsDirectory, - string inputFile, + string? inputFile, EmbedItem embedItem, - string outputDirectory) + string outputDirectory, + bool missingContentOK) { if (supportedAbis.Count < 1) { throw new ArgumentException ("At least one target ABI must be present", nameof (supportedAbis)); @@ -80,7 +81,8 @@ public static List EmbedBinary ( abi, inputFile, outputDirectory, - embedItem + embedItem, + missingContentOK ); } @@ -91,9 +93,10 @@ public static List EmbedBinary ( TaskLoggingHelper log, string abi, string androidBinUtilsDirectory, - string inputFile, + string? inputFile, EmbedItem embedItem, - string outputDirectory) + string outputDirectory, + bool missingContentOK) { if (String.IsNullOrEmpty (abi)) { throw new ArgumentException ("Must be a supported ABI name", nameof (abi)); @@ -107,7 +110,8 @@ public static List EmbedBinary ( abi, inputFile, outputDirectory, - embedItem + embedItem, + missingContentOK ); return ret; } @@ -119,10 +123,11 @@ static void EmbedBinary ( string abi, string inputFile, string outputDirectory, - EmbedItem embedItem) + EmbedItem embedItem, + bool missingContentOK) { string outputFile = Path.Combine (outputDirectory, $"embed_{embedItem.BaseFileName}.{abi.ToLowerInvariant ()}.o"); - DoEmbed (log, MonoAndroidHelper.AbiToTargetArch (abi), llvmMcPath, inputFile, outputFile, embedItem); + DoEmbed (log, MonoAndroidHelper.AbiToTargetArch (abi), llvmMcPath, inputFile, outputFile, embedItem, missingContentOK); if (!File.Exists (outputFile)) { return; } @@ -137,33 +142,54 @@ static void DoEmbed ( TaskLoggingHelper log, AndroidTargetArch arch, string llvmMcPath, - string inputFile, + string? inputFile, string outputFile, - EmbedItem item) + EmbedItem item, + bool missingContentOK) { if (!llvmMcConfigs.TryGetValue (arch, out LlvmMcTargetConfig cfg)) { throw new NotSupportedException ($"Internal error: unsupported target arch '{arch}'"); } - inputFile = Path.GetFullPath (inputFile); + bool haveInputFile = !String.IsNullOrEmpty (inputFile); + if (!haveInputFile) { + if (!missingContentOK) { + throw new InvalidOperationException ("Internal error: input file must be specified"); + } + } else { + inputFile = Path.GetFullPath (inputFile); + } outputFile = Path.GetFullPath (outputFile); - var fi = new FileInfo (inputFile); - long inputFileSize = fi.Length; + long inputFileSize = 0; + string? sanitizedInputFilePath = null; + + if (haveInputFile) { + var fi = new FileInfo (inputFile); + if (fi.Exists) { + inputFileSize = fi.Length; + sanitizedInputFilePath = inputFile.Replace ("\\", "\\\\"); + } else if (!missingContentOK) { + throw new InvalidOperationException ($"Internal error: input file '{inputFile}' does not exist"); + } + } + string asmInputFile = Path.ChangeExtension (outputFile, ".s"); - string sanitizedInputFilePath = inputFile.Replace ("\\", "\\\\"); using var fs = File.Open (asmInputFile, FileMode.Create, FileAccess.Write, FileShare.Read); using var sw = new StreamWriter (fs, asmFileEncoding); string symbolName = item.SymbolName; sw.WriteLine ($".section .rodata,\"a\",{cfg.AssemblerDirectivePrefix}progbits"); - sw.WriteLine (".p2align 3, 0x00"); // Put the data at 4k boundary + sw.WriteLine (".p2align 3, 0x00"); // Put the data at the 4k boundary sw.WriteLine (); sw.WriteLine ($".global {symbolName}"); sw.WriteLine ($".type {symbolName},{cfg.AssemblerDirectivePrefix}object"); sw.WriteLine ($"{symbolName}:"); - sw.WriteLine ($"\t.incbin \"{sanitizedInputFilePath}\""); + + if (!String.IsNullOrEmpty (sanitizedInputFilePath)) { + sw.WriteLine ($"\t.incbin \"{sanitizedInputFilePath}\""); + } sw.WriteLine ($"\t.size {symbolName}, {inputFileSize}"); sw.WriteLine (); From b04f22eff91c96186990fc413fcbd9962232be08 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 17 Oct 2024 11:31:59 +0200 Subject: [PATCH 26/60] Don't embed assembly store when fastdev is used --- src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 038628923a1..62a3adba302 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -361,7 +361,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' ">False <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' ">$(AndroidEnableMarshalMethods) - <_AndroidEmbedAssemblyStoreInRuntime Condition=" '$(AndroidUseAssemblyStore)' == 'True' And '$(_AndroidEmbedAssemblyStoreInRuntime)' == '' ">True + <_AndroidEmbedAssemblyStoreInRuntime Condition=" '$(AndroidUseAssemblyStore)' == 'True' And '$(EmbedAssembliesIntoApk)' == 'true' And '$(_AndroidEmbedAssemblyStoreInRuntime)' == '' ">True <_AndroidEmbedAssemblyStoreInRuntime Condition="'$(_AndroidEmbedAssemblyStoreInRuntime)' == '' ">False From d53f711a93ca30312070570c68f0203ac2a105fe Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 17 Oct 2024 13:24:11 +0200 Subject: [PATCH 27/60] Let's see if designer tests pass now --- .../Tasks/GeneratePackageManagerJava.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 72ed235721a..7c651a4155b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -62,12 +62,11 @@ public override bool RunTask () [Required] public bool EnablePreloadAssembliesDefault { get; set; } - // This property should be required but it can't, because during design time builds there's no - // value to pass and MSBuild signals an error that a required property wasn't given a value. + // These two properties should be required but they will require modifying `monodroid` first //[Required] public string AndroidBinUtilsDirectory { get; set; } - [Required] + //[Required] public bool AssemblyStoreEmbeddedInRuntime { get; set; } [Output] From 1070f1cdde0a1d81b02373cf56791f560622b92d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 18 Oct 2024 12:40:36 +0200 Subject: [PATCH 28/60] Expect the unexpected, DTB doesn't specify any ABIs --- .../Utilities/ELFEmbeddingHelper.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs index 9116cabcd58..e58f2b94d5e 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text; +using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Xamarin.Android.Tools; @@ -67,12 +68,13 @@ public static List EmbedBinary ( string outputDirectory, bool missingContentOK) { + var ret = new List (); if (supportedAbis.Count < 1) { - throw new ArgumentException ("At least one target ABI must be present", nameof (supportedAbis)); + log.LogDebugMessage ("ELFEmbeddingHelper: at least one target ABI must be specified. Probably a DTB build, skipping generation."); + return ret; } string llvmMcPath = GetLlvmMcPath (androidBinUtilsDirectory); - var ret = new List (); foreach (string abi in supportedAbis) { EmbedBinary ( log, @@ -98,11 +100,12 @@ public static List EmbedBinary ( string outputDirectory, bool missingContentOK) { + var ret = new List (); if (String.IsNullOrEmpty (abi)) { - throw new ArgumentException ("Must be a supported ABI name", nameof (abi)); + log.LogDebugMessage ("ELFEmbeddingHelper: ABI must be specified. Probably a DTB build, skipping generation."); + return ret; } - var ret = new List (); EmbedBinary ( log, ret, From 91f740f2251868dc464ea85eec0b7cea3a30d829 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 18 Oct 2024 19:31:34 +0200 Subject: [PATCH 29/60] [WIP] Builds but doesn't work --- ...crosoft.Android.Sdk.AssemblyStores.targets | 7 +- .../Tasks/CompileNativeAssembly.cs | 21 +- ...teCompressedAssembliesNativeSourceFiles.cs | 2 +- .../Tasks/GeneratePackageManagerJava.cs | 2 +- .../Tasks/PrepareAbiItems.cs | 37 +--- .../Utilities/AssemblyCompression.cs | 5 +- .../Utilities/ELFEmbeddingHelper.cs | 10 +- .../Utilities/MonoAndroidHelper.cs | 19 +- .../Utilities/NativeAssemblerCompilation.cs | 199 ++++++++++++++++++ .../Utilities/NativeAssemblerItemsHelper.cs | 65 ++++++ .../Xamarin.Android.Common.targets | 86 +++----- .../AssemblyStore/StoreReader_V2.cs | 10 +- 12 files changed, 339 insertions(+), 124 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerCompilation.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerItemsHelper.cs diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets index c7185129668..dee4e5d46be 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets @@ -7,13 +7,17 @@ <_EmbeddedAssemblyStoreObjectFile Include="$(_NativeAssemblySourceDir)embed_assembly_store.%(_BuildTargetAbis.Identity).o" /> + + + <_EmbeddedAssemblyStoreSourceFiles Include="@(_EmbeddedAssemblyStoreObjectFile->'$([System.IO.Path]::ChangeExtension('%(Identity)', '.s'))')" /> + + Outputs="@(_EmbeddedAssemblyStoreObjectFile);@(_EmbeddedAssemblyStoreSourceFiles)"> - diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs index 9d6d324f678..1504b5b6562 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs @@ -99,9 +99,24 @@ void RunAssembler (Config config) } } + static readonly List llcArguments = new () { + "-O2", + "--debugger-tune=lldb", // NDK uses lldb now + "--debugify-level=location+variables", + "--fatal-warnings", + "--filetype=obj", + "--relocation-model=pic", + }; + + static readonly List llvmMcArguments = new () { + "--assemble", + "--filetype=obj", + "-g", + }; + IEnumerable GetAssemblerConfigs () { - const string assemblerOptions = + const string llcOptions = "-O2 " + "--debugger-tune=lldb " + // NDK uses lldb now "--debugify-level=location+variables " + @@ -113,14 +128,14 @@ IEnumerable GetAssemblerConfigs () foreach (ITaskItem item in Sources) { // We don't need the directory since our WorkingDirectory is where all the sources are string sourceFile = Path.GetFileName (item.ItemSpec); - string outputFile = QuoteFileName (sourceFile.Replace (".ll", ".o")); + string outputFile = QuoteFileName (Path.ChangeExtension (sourceFile, ".o")); string executableDir = Path.GetDirectoryName (llcPath); string executableName = MonoAndroidHelper.GetExecutablePath (executableDir, Path.GetFileName (llcPath)); yield return new Config { InputSource = item.ItemSpec, AssemblerPath = Path.Combine (executableDir, executableName), - AssemblerOptions = $"{assemblerOptions} -o={outputFile} {QuoteFileName (sourceFile)}", + AssemblerOptions = $"{llcOptions} -o={outputFile} {QuoteFileName (sourceFile)}", }; } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateCompressedAssembliesNativeSourceFiles.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateCompressedAssembliesNativeSourceFiles.cs index fd6b78fcebd..be5346385bf 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateCompressedAssembliesNativeSourceFiles.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateCompressedAssembliesNativeSourceFiles.cs @@ -66,7 +66,7 @@ void GenerateCompressedAssemblySources () var assemblyKey = CompressedAssemblyInfo.GetDictionaryKey (assembly); if (assemblies.ContainsKey (assemblyKey)) { - Log.LogDebugMessage ($"Skipping duplicate assembly: {assembly.ItemSpec} (arch {MonoAndroidHelper.GetAssemblyAbi(assembly)})"); + Log.LogDebugMessage ($"Skipping duplicate assembly: {assembly.ItemSpec} (arch {MonoAndroidHelper.GetItemAbi(assembly)})"); continue; } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 7c651a4155b..d3f79f66af1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -249,7 +249,7 @@ void AddEnvironment () uniqueAssemblyNames.Add (assemblyName); } - string abi = MonoAndroidHelper.GetAssemblyAbi (assembly); + string abi = MonoAndroidHelper.GetItemAbi (assembly); archAssemblyNames ??= new HashSet (StringComparer.OrdinalIgnoreCase); if (!archAssemblyNames.Contains (assemblyName)) { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs index cad5439df21..41328dbf299 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs @@ -1,5 +1,3 @@ -using System; -using System.IO; using System.Collections.Generic; using Microsoft.Build.Framework; @@ -10,13 +8,6 @@ namespace Xamarin.Android.Tasks { public class PrepareAbiItems : AndroidTask { - const string ArmV7a = "armeabi-v7a"; - const string TypeMapBase = "typemaps"; - const string EnvBase = "environment"; - const string CompressedAssembliesBase = "compressed_assemblies"; - const string JniRemappingBase = "jni_remap"; - const string MarshalMethodsBase = "marshal_methods"; - public override string TaskPrefix => "PAI"; [Required] @@ -28,45 +19,23 @@ public class PrepareAbiItems : AndroidTask [Required] public string Mode { get; set; } = ""; - [Required] - public bool Debug { get; set; } - [Output] public ITaskItem[]? AssemblySources { get; set; } - [Output] - public ITaskItem[]? AssemblyIncludes { get; set; } - public override bool RunTask () { var sources = new List (); - var includes = new List (); - string baseName; - - if (String.Compare ("typemap", Mode, StringComparison.OrdinalIgnoreCase) == 0) { - baseName = TypeMapBase; - } else if (String.Compare ("environment", Mode, StringComparison.OrdinalIgnoreCase) == 0) { - baseName = EnvBase; - } else if (String.Compare ("compressed", Mode, StringComparison.OrdinalIgnoreCase) == 0) { - baseName = CompressedAssembliesBase; - } else if (String.Compare ("jniremap", Mode, StringComparison.OrdinalIgnoreCase) == 0) { - baseName = JniRemappingBase; - } else if (String.Compare ("marshal_methods", Mode, StringComparison.OrdinalIgnoreCase) == 0) { - baseName = MarshalMethodsBase; - } else { - Log.LogError ($"Unknown mode: {Mode}"); - return false; - } TaskItem item; + NativeAssemblerItemsHelper.KnownMode mode = NativeAssemblerItemsHelper.ToKnownMode (Mode); foreach (string abi in BuildTargetAbis) { - item = new TaskItem (Path.Combine (NativeSourcesDir, $"{baseName}.{abi}.ll")); + item = new TaskItem (NativeAssemblerItemsHelper.GetSourcePath (Log, mode, NativeSourcesDir, abi)); item.SetMetadata ("abi", abi); + item.SetMetadata ("RuntimeIdentifier", MonoAndroidHelper.AbiToRid (abi)); sources.Add (item); } AssemblySources = sources.ToArray (); - AssemblyIncludes = includes.ToArray (); return !Log.HasLoggedErrors; } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyCompression.cs b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyCompression.cs index 9ef32a4dcb8..af7f97cdcd5 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyCompression.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyCompression.cs @@ -170,9 +170,8 @@ static string GetCompressedAssemblyOutputDirectory (ITaskItem assembly, string c { string assemblyOutputDir; string subDirectory = assembly.GetMetadata ("DestinationSubDirectory"); - string abi = MonoAndroidHelper.GetAssemblyAbi (assembly); - - if (!string.IsNullOrEmpty (subDirectory) && !(subDirectory.EndsWith ($"{abi}/", StringComparison.Ordinal) || subDirectory.EndsWith ($"{abi}\\", StringComparison.Ordinal))) { + string abi = MonoAndroidHelper.GetItemAbi (assembly); + if (!String.IsNullOrEmpty (subDirectory) && !(subDirectory.EndsWith ($"{abi}/", StringComparison.Ordinal) || subDirectory.EndsWith ($"{abi}\\", StringComparison.Ordinal))) { assemblyOutputDir = Path.Combine (compressedOutputDir, abi, subDirectory); } else { assemblyOutputDir = Path.Combine (compressedOutputDir, abi); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs index e58f2b94d5e..714269b37b7 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs @@ -215,10 +215,12 @@ static void DoEmbed ( MonoAndroidHelper.QuoteFileNameArgument (asmInputFile), }; - int ret = MonoAndroidHelper.RunProcess (llvmMcPath, String.Join (" ", args), log); - if (ret != 0) { - return; - } + // int ret = MonoAndroidHelper.RunProcess (llvmMcPath, String.Join (" ", args), log); + // File.Copy (asmInputFile, $"/tmp/{Path.GetFileName (asmInputFile)}", true); + // File.Copy (outputFile, $"/tmp/{Path.GetFileName (outputFile)}", true); + // if (ret != 0) { + // return; + // } } static string GetLlvmMcPath (string androidBinUtilsDirectory) => MonoAndroidHelper.GetLlvmMcPath (androidBinUtilsDirectory); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index 9276ba600ca..7724a979335 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -568,29 +568,17 @@ public static int ConvertSupportedOSPlatformVersionToApiLevel (string version) } #if MSBUILD - public static string GetAssemblyAbi (ITaskItem asmItem) + public static string GetItemAbi (ITaskItem asmItem) { string? abi = asmItem.GetMetadata ("Abi"); if (String.IsNullOrEmpty (abi)) { - throw new InvalidOperationException ($"Internal error: assembly '{asmItem}' lacks ABI metadata"); + throw new InvalidOperationException ($"Internal error: item '{asmItem}' lacks ABI metadata"); } return abi; } - public static AndroidTargetArch GetTargetArch (ITaskItem asmItem) => AbiToTargetArch (GetAssemblyAbi (asmItem)); - - - public static AndroidTargetArch GetRequiredValidArchitecture (ITaskItem item) - { - AndroidTargetArch ret = GetTargetArch (item); - - if (ret == AndroidTargetArch.None) { - throw new InvalidOperationException ($"Internal error: assembly '{item}' doesn't target any architecture."); - } - - return ret; - } + public static AndroidTargetArch GetTargetArch (ITaskItem asmItem) => AbiToTargetArch (GetItemAbi (asmItem)); #endif // MSBUILD static string GetToolsRootDirectoryRelativePath (string androidBinUtilsDirectory) @@ -785,6 +773,7 @@ public static string QuoteFileNameArgument (string? fileName) public static string GetLlvmObjcopyPath (string androidBinUtilsDirectory) => GetBinUtilsToolPath (androidBinUtilsDirectory, "llvm-objcopy"); public static string GetLlvmMcPath (string androidBinUtilsDirectory) => GetBinUtilsToolPath (androidBinUtilsDirectory, "llvm-mc"); + public static string GetLlvmLlcPath (string androidBinUtilsDirectory) => GetBinUtilsToolPath (androidBinUtilsDirectory, "llc"); static string GetBinUtilsToolPath (string androidBinUtilsDirectory, string toolName) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerCompilation.cs b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerCompilation.cs new file mode 100644 index 00000000000..78a3b33d90e --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerCompilation.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading; + +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Xamarin.Android.Tools; + +namespace Xamarin.Android.Tasks; + +class NativeAssemblerCompilation +{ + public sealed class AssemblerConfig + { + public readonly string ExecutablePath; + public readonly string Options; + public readonly string InputSource; + + public AssemblerConfig (string executablePath, string options, string inputSource) + { + ExecutablePath = executablePath; + Options = options; + InputSource = inputSource; + } + } + + public sealed class AssemblerRunContext + { + public readonly TaskLoggingHelper Log; + public readonly Action? RegisterForCancellation; + public readonly Action? Cancel; + public readonly string? WorkingDirectory; + + public AssemblerRunContext (TaskLoggingHelper log, string? workingDirectory = null, Action? registerForCancellation = null, Action? cancel = null) + { + Log = log; + RegisterForCancellation = registerForCancellation; + Cancel = cancel; + WorkingDirectory = workingDirectory; + } + } + + public sealed class LlvmMcTargetConfig + { + public readonly string TargetArch; + public readonly string TripleArch; + public readonly string TripleApiPrefix; + public readonly string AssemblerDirectivePrefix; + public readonly string SizeType; + public readonly uint WordSize; + + public LlvmMcTargetConfig (string targetArch, string tripleArch, string tripleApiPrefix, string assemblerDirectivePrefix, string sizeType, uint wordSize) + { + TargetArch = targetArch; + TripleArch = tripleArch; + TripleApiPrefix = tripleApiPrefix; + AssemblerDirectivePrefix = assemblerDirectivePrefix; + SizeType = sizeType; + WordSize = wordSize; + } + } + + static readonly Dictionary llvmMcConfigs = new () { + { AndroidTargetArch.Arm64, new ("aarch64", "aarch64", "android", "@", ".xword", 8) }, + { AndroidTargetArch.Arm, new ("arm", "armv7a", "androideabi", "%", ".long", 4) }, + { AndroidTargetArch.X86_64, new ("x86-64", "x86_64", "android", "@", ".quad", 8) }, + { AndroidTargetArch.X86, new ("x86", "i686", "android", "@", ".long", 4) }, + }; + + static readonly List llcArguments = new () { + "-O2", + "--debugger-tune=lldb", // NDK uses lldb now + "--debugify-level=location+variables", + "--fatal-warnings", + "--filetype=obj", + "--relocation-model=pic", + }; + + static readonly List llvmMcArguments = new () { + "--assemble", + "--filetype=obj", + "-g", + }; + + public static AssemblerConfig GetAssemblerConfig (string androidBinUtilsDir, ITaskItem source, bool stripFilePaths) + { + string sourceFile = stripFilePaths ? Path.GetFileName (source.ItemSpec) : source.ItemSpec; + string sourceExtension = Path.GetExtension (sourceFile); + string executable; + var arguments = new List (); + + if (String.Compare (".ll", sourceExtension, StringComparison.OrdinalIgnoreCase) == 0) { + executable = MonoAndroidHelper.GetLlvmLlcPath (androidBinUtilsDir); + arguments.AddRange (llcArguments); + } else if (String.Compare (".s", sourceExtension, StringComparison.OrdinalIgnoreCase) == 0) { + executable = MonoAndroidHelper.GetLlvmMcPath (androidBinUtilsDir); + arguments.AddRange (llvmMcArguments); + + LlvmMcTargetConfig cfg = GetLlvmMcConfig (MonoAndroidHelper.GetTargetArch (source)); + arguments.Add ($"--arch={cfg.TargetArch}"); + arguments.Add ($"--triple={cfg.TripleArch}-linux-{cfg.TripleApiPrefix}{XABuildConfig.AndroidMinimumDotNetApiLevel}"); + } else { + throw new InvalidOperationException ($"Internal exception: unknown native assembler source {source.ItemSpec}"); + } + + string outputFile = Path.ChangeExtension (sourceFile, ".o"); + arguments.Add ("-o"); + arguments.Add (MonoAndroidHelper.QuoteFileNameArgument (outputFile)); + arguments.Add (MonoAndroidHelper.QuoteFileNameArgument (sourceFile)); + + return new AssemblerConfig (executable, String.Join (" ", arguments), source.ItemSpec); + } + + public static LlvmMcTargetConfig GetLlvmMcConfig (AndroidTargetArch arch) + { + if (!llvmMcConfigs.TryGetValue (arch, out LlvmMcTargetConfig cfg)) { + throw new NotSupportedException ($"Internal error: unsupported target arch '{arch}'"); + } + + return cfg; + } + + public static void RunAssembler (AssemblerRunContext context, AssemblerConfig config) + { + var stdout_completed = new ManualResetEvent (false); + var stderr_completed = new ManualResetEvent (false); + var psi = new ProcessStartInfo () { + FileName = config.ExecutablePath, + Arguments = config.Options, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + WorkingDirectory = context.WorkingDirectory, + }; + + string assemblerName = Path.GetFileName (config.ExecutablePath); + context.Log.LogDebugMessage ($"[{assemblerName}] {psi.FileName} {psi.Arguments}"); + + var stdoutLines = new List (); + var stderrLines = new List (); + + using var proc = new Process (); + proc.OutputDataReceived += (s, e) => { + if (e.Data != null) { + OnOutputData (context, assemblerName, s, e); + stdoutLines.Add (e.Data); + } else + stdout_completed.Set (); + }; + + proc.ErrorDataReceived += (s, e) => { + if (e.Data != null) { + OnErrorData (context, assemblerName, s, e); + stderrLines.Add (e.Data); + } else + stderr_completed.Set (); + }; + + proc.StartInfo = psi; + proc.Start (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); + + if (context.RegisterForCancellation != null) { + context.RegisterForCancellation (proc); + } + + proc.WaitForExit (); + + if (psi.RedirectStandardError) { + stderr_completed.WaitOne (TimeSpan.FromSeconds (30)); + } + + if (psi.RedirectStandardOutput) { + stdout_completed.WaitOne (TimeSpan.FromSeconds (30)); + } + + if (proc.ExitCode != 0) { + var sb = MonoAndroidHelper.MergeStdoutAndStderrMessages (stdoutLines, stderrLines); + context.Log.LogCodedError ("XA3006", Properties.Resources.XA3006, Path.GetFileName (config.InputSource), sb.ToString ()); + context.Cancel?.Invoke (); + } + } + + static void OnOutputData (AssemblerRunContext context, string assemblerName, object sender, DataReceivedEventArgs e) + { + context.Log.LogDebugMessage ($"[{assemblerName} stdout] {e.Data}"); + } + + static void OnErrorData (AssemblerRunContext context, string assemblerName, object sender, DataReceivedEventArgs e) + { + context.Log.LogMessage ($"[{assemblerName} stderr] {e.Data}", MessageImportance.High); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerItemsHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerItemsHelper.cs new file mode 100644 index 00000000000..6f2df37c30a --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerItemsHelper.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; + +using Microsoft.Build.Utilities; + +namespace Xamarin.Android.Tasks; + +static class NativeAssemblerItemsHelper +{ + public enum KnownMode + { + CompressedAssemblies, + EmbeddedAssemblyStore, + EmbeddedRuntimeConfig, + Environment, + JNIRemap, + MarshalMethods, + TypeMap, + } + + sealed class ModeConfig + { + public readonly string FileNameBase; + public readonly string Extension; + + public ModeConfig (string fileNameBase, string extension) + { + FileNameBase = fileNameBase; + Extension = extension; + } + } + + const string LlvmIrExtension = "ll"; + const string NativeAssemblerExtension = "s"; + + static readonly Dictionary ModeConfigs = new () { + { KnownMode.CompressedAssemblies, new ("compressed_assemblies", LlvmIrExtension) }, + { KnownMode.EmbeddedAssemblyStore, new ("embed_assembly_store", NativeAssemblerExtension) }, + { KnownMode.EmbeddedRuntimeConfig, new ("embed_runtime_config", NativeAssemblerExtension) }, + { KnownMode.Environment, new ("environment", LlvmIrExtension) }, + { KnownMode.JNIRemap, new ("jni_remap", LlvmIrExtension) }, + { KnownMode.MarshalMethods, new ("marshal_methods", LlvmIrExtension) }, + { KnownMode.TypeMap, new ("typemaps", LlvmIrExtension) }, + }; + + public static string? GetSourcePath (TaskLoggingHelper log, KnownMode mode, string nativeSourcesDir, string abi) + { + if (!ModeConfigs.TryGetValue (mode, out ModeConfig config)) { + log.LogError ($"Unknown mode: {mode}"); + return null; + } + + return Path.Combine (nativeSourcesDir, $"{config.FileNameBase}.{abi.ToLowerInvariant ()}.{config.Extension}"); + } + + public static KnownMode ToKnownMode (string mode) + { + if (!Enum.TryParse (mode, ignoreCase: true, out KnownMode result)) { + throw new InvalidOperationException ($"Internal exception: uknown native assembler generator mode '{mode}'"); + } + + return result; + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 62a3adba302..15c55742b7b 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1534,10 +1534,8 @@ because xbuild doesn't support framework reference assemblies. + Mode="TypeMap"> - @@ -1680,7 +1678,6 @@ because xbuild doesn't support framework reference assemblies. - @@ -1752,24 +1749,27 @@ because xbuild doesn't support framework reference assemblies. + Mode="Environment"> + Mode="CompressedAssemblies"> + Mode="MarshalMethods"> + + + @@ -1794,8 +1794,7 @@ because xbuild doesn't support framework reference assemblies. + Mode="JNIRemap"> @@ -1908,54 +1907,11 @@ because xbuild doesn't support framework reference assemblies. EnableMarshalMethods="$(_AndroidUseMarshalMethods)" CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)" - > - - - - - - - - - + AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)" /> - + @@ -2181,6 +2137,18 @@ because xbuild doesn't support framework reference assemblies. <_NativeAssemblyTarget Include="@(_AndroidRemapAssemblySource->'$([System.IO.Path]::ChangeExtension('%(Identity)', '.o'))')"> %(_AndroidRemapAssemblySource.abi) + <_NativeAssemblyTarget Include="@(_EmbeddedRuntimeConfigAssemblySource->'$([System.IO.Path]::ChangeExtension('%(Identity)', '.o'))')"> + %(_EmbeddedRuntimeConfigAssemblySource.abi) + + + + + <_NativeAssemblySource Include="@(_AndroidRemapAssemblySource)" /> + <_NativeAssemblySource Include="@(_CompressedAssembliesAssemblySource)" /> + <_NativeAssemblySource Include="@(_EmbeddedRuntimeConfigAssemblySource)" /> + <_NativeAssemblySource Include="@(_EnvironmentAssemblySource)" /> + <_NativeAssemblySource Include="@(_MarshalMethodsAssemblySource)" /> + <_NativeAssemblySource Include="@(_TypeMapAssemblySource)" /> @@ -2200,10 +2168,10 @@ because xbuild doesn't support framework reference assemblies. 0) { + StoreStream.Seek ((long)elfOffset, SeekOrigin.Begin); + magic = reader.ReadUInt32 (); + } else { + return false; + } } if (magic != Utils.ASSEMBLY_STORE_MAGIC) { From 525dd96957fa167e0771e03aa29a4c7cbb61460c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 21 Oct 2024 21:14:13 +0200 Subject: [PATCH 30/60] Let's see how it works now --- ...crosoft.Android.Sdk.AssemblyStores.targets | 22 ++- .../Tasks/CompileNativeAssembly.cs | 139 +++--------------- .../Tasks/CreateEmbeddedAssemblyStore.cs | 26 +--- .../Tasks/GeneratePackageManagerJava.cs | 7 +- .../Utilities/ELFEmbeddingHelper.cs | 118 +++------------ .../Utilities/NativeAssemblerCompilation.cs | 11 +- .../Utilities/NativeAssemblerItemsHelper.cs | 6 + .../Xamarin.Android.Common.targets | 8 +- 8 files changed, 65 insertions(+), 272 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets index dee4e5d46be..c47516065c0 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets @@ -1,23 +1,22 @@ + - - - <_EmbeddedAssemblyStoreObjectFile Include="$(_NativeAssemblySourceDir)embed_assembly_store.%(_BuildTargetAbis.Identity).o" /> - - - - <_EmbeddedAssemblyStoreSourceFiles Include="@(_EmbeddedAssemblyStoreObjectFile->'$([System.IO.Path]::ChangeExtension('%(Identity)', '.s'))')" /> - + + + + Outputs="@(_EmbeddedAssemblyStoreSourceFiles)"> - - - + SupportedAbis="@(_BuildTargetAbis)" /> diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs index 1504b5b6562..4bfc03d9d26 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs @@ -2,12 +2,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Threading; using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -using Xamarin.Android.Tools; using Microsoft.Android.Build.Tasks; namespace Xamarin.Android.Tasks @@ -16,13 +12,6 @@ public class CompileNativeAssembly : AsyncTask { public override string TaskPrefix => "CNA"; - sealed class Config - { - public string? AssemblerPath; - public string? AssemblerOptions; - public string? InputSource; - } - [Required] public ITaskItem[] Sources { get; set; } = []; @@ -37,124 +26,34 @@ sealed class Config public override System.Threading.Tasks.Task RunTaskAsync () { - return this.WhenAll (GetAssemblerConfigs (), RunAssembler); + var context = new NativeAssemblerCompilation.AssemblerRunContext ( + Log, + Path.GetFullPath (WorkingDirectory), + registerForCancellation: RegisterForCancellation, + cancel: Cancel + ); + + return this.WhenAll ( + GetAssemblerConfigs (), + (NativeAssemblerCompilation.AssemblerConfig config) => NativeAssemblerCompilation.RunAssembler (context, config) + ); } - void RunAssembler (Config config) + void RegisterForCancellation (Process proc) { - var stdout_completed = new ManualResetEvent (false); - var stderr_completed = new ManualResetEvent (false); - var psi = new ProcessStartInfo () { - FileName = config.AssemblerPath, - Arguments = config.AssemblerOptions, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - WorkingDirectory = WorkingDirectory, - }; - - string assemblerName = Path.GetFileName (config.AssemblerPath); - LogDebugMessage ($"[LLVM llc] {psi.FileName} {psi.Arguments}"); - - var stdoutLines = new List (); - var stderrLines = new List (); - - using (var proc = new Process ()) { - proc.OutputDataReceived += (s, e) => { - if (e.Data != null) { - OnOutputData (assemblerName, s, e); - stdoutLines.Add (e.Data); - } else - stdout_completed.Set (); - }; - - proc.ErrorDataReceived += (s, e) => { - if (e.Data != null) { - OnErrorData (assemblerName, s, e); - stderrLines.Add (e.Data); - } else - stderr_completed.Set (); - }; - - proc.StartInfo = psi; - proc.Start (); - proc.BeginOutputReadLine (); - proc.BeginErrorReadLine (); - CancellationToken.Register (() => { try { proc.Kill (); } catch (Exception) { } }); - proc.WaitForExit (); - - if (psi.RedirectStandardError) - stderr_completed.WaitOne (TimeSpan.FromSeconds (30)); - - if (psi.RedirectStandardOutput) - stdout_completed.WaitOne (TimeSpan.FromSeconds (30)); - - if (proc.ExitCode != 0) { - var sb = MonoAndroidHelper.MergeStdoutAndStderrMessages (stdoutLines, stderrLines); - LogCodedError ("XA3006", Properties.Resources.XA3006, Path.GetFileName (config.InputSource), sb.ToString ()); - Cancel (); + CancellationToken.Register (() => { + try { + proc.Kill (); + } catch (Exception) { } - } + }); } - static readonly List llcArguments = new () { - "-O2", - "--debugger-tune=lldb", // NDK uses lldb now - "--debugify-level=location+variables", - "--fatal-warnings", - "--filetype=obj", - "--relocation-model=pic", - }; - - static readonly List llvmMcArguments = new () { - "--assemble", - "--filetype=obj", - "-g", - }; - - IEnumerable GetAssemblerConfigs () + IEnumerable GetAssemblerConfigs () { - const string llcOptions = - "-O2 " + - "--debugger-tune=lldb " + // NDK uses lldb now - "--debugify-level=location+variables " + - "--fatal-warnings " + - "--filetype=obj " + - "--relocation-model=pic"; - string llcPath = Path.Combine (AndroidBinUtilsDirectory, "llc"); - foreach (ITaskItem item in Sources) { - // We don't need the directory since our WorkingDirectory is where all the sources are - string sourceFile = Path.GetFileName (item.ItemSpec); - string outputFile = QuoteFileName (Path.ChangeExtension (sourceFile, ".o")); - string executableDir = Path.GetDirectoryName (llcPath); - string executableName = MonoAndroidHelper.GetExecutablePath (executableDir, Path.GetFileName (llcPath)); - - yield return new Config { - InputSource = item.ItemSpec, - AssemblerPath = Path.Combine (executableDir, executableName), - AssemblerOptions = $"{llcOptions} -o={outputFile} {QuoteFileName (sourceFile)}", - }; + yield return NativeAssemblerCompilation.GetAssemblerConfig (AndroidBinUtilsDirectory, item, stripFilePaths: true); } } - - void OnOutputData (string assemblerName, object sender, DataReceivedEventArgs e) - { - LogDebugMessage ($"[{assemblerName} stdout] {e.Data}"); - } - - void OnErrorData (string assemblerName, object sender, DataReceivedEventArgs e) - { - LogMessage ($"[{assemblerName} stderr] {e.Data}", MessageImportance.High); - } - - static string QuoteFileName (string fileName) - { - var builder = new CommandLineBuilder (); - builder.AppendFileNameIfNotNull (fileName); - return builder.ToString (); - } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs index 288f52be3db..2823af2c3e8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs @@ -43,12 +43,6 @@ public class CreateEmbeddedAssemblyStore : AndroidTask [Required] public string [] SupportedAbis { get; set; } - [Output] - public ITaskItem[] NativeAssemblySources { get; set; } - - [Output] - public ITaskItem[] EmbeddedObjectFiles { get; set; } - public override bool RunTask () { bool compress = !Debug && EnableCompression; @@ -71,14 +65,12 @@ public override bool RunTask () // Add framework assemblies AssemblyPackagingHelper.AddAssembliesFromCollection (Log, SupportedAbis, ResolvedFrameworkAssemblies, DoAddAssembliesFromArchCollection); - var objectFiles = new List (); - var sourceFiles = new List (); Dictionary assemblyStorePaths = storeBuilder.Generate (Path.Combine (AppSharedLibrariesDir, "embedded")); foreach (var kvp in assemblyStorePaths) { string abi = MonoAndroidHelper.ArchToAbi (kvp.Key); string inputFile = kvp.Value; - List items = ELFEmbeddingHelper.EmbedBinary ( + ELFEmbeddingHelper.EmbedBinary ( Log, abi, AndroidBinUtilsDirectory, @@ -87,24 +79,8 @@ public override bool RunTask () AssemblySourcesDir, missingContentOK: false ); - - if (items.Count == 0) { - continue; - } - - objectFiles.AddRange (items); - foreach (ITaskItem objectItem in items) { - var sourceItem = new TaskItem ( - Path.ChangeExtension (objectItem.ItemSpec, ".s"), - objectItem.CloneCustomMetadata () - ); - sourceFiles.Add (sourceItem); - } } - NativeAssemblySources = sourceFiles.ToArray (); - EmbeddedObjectFiles = objectFiles.ToArray (); - return !Log.HasLoggedErrors; void DoAddAssembliesFromArchCollection (TaskLoggingHelper log, AndroidTargetArch arch, ITaskItem assembly) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index d3f79f66af1..1ad4ee1fb58 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -69,9 +69,6 @@ public override bool RunTask () //[Required] public bool AssemblyStoreEmbeddedInRuntime { get; set; } - [Output] - public ITaskItem[] EmbeddedObjectFiles { get; set; } - public bool EnableMarshalMethods { get; set; } public string RuntimeConfigBinFilePath { get; set; } public string BoundExceptionType { get; set; } @@ -319,7 +316,7 @@ void AddEnvironment () var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "MonoPackageManager_Resources.java")); bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); - List objectFilePaths = ELFEmbeddingHelper.EmbedBinary ( + ELFEmbeddingHelper.EmbedBinary ( Log, SupportedAbis, AndroidBinUtilsDirectory, @@ -329,8 +326,6 @@ void AddEnvironment () missingContentOK: !haveRuntimeConfigBlob ); - EmbeddedObjectFiles = objectFilePaths.ToArray (); - var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); var appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { UsesMonoAOT = usesMonoAOT, diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs index 714269b37b7..2d6a2551765 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs @@ -4,7 +4,6 @@ using System.Text; using Microsoft.Android.Build.Tasks; -using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Xamarin.Android.Tools; @@ -16,50 +15,25 @@ public sealed class EmbedItem { public readonly string SymbolName; public readonly string BaseFileName; + public readonly NativeAssemblerItemsHelper.KnownMode NativeAssemblerMode; - public EmbedItem (string symbolName, string baseFileName) + public EmbedItem (string symbolName, string baseFileName, NativeAssemblerItemsHelper.KnownMode nativeAssemblerMode) { SymbolName = symbolName; BaseFileName = baseFileName; + NativeAssemblerMode = nativeAssemblerMode; } } public static class KnownEmbedItems { - public static readonly EmbedItem RuntimeConfig = new ("embedded_runtime_config", "runtime_config"); - public static readonly EmbedItem AssemblyStore = new ("embedded_assembly_store", "assembly_store"); + public static readonly EmbedItem RuntimeConfig = new ("embedded_runtime_config", "runtime_config", NativeAssemblerItemsHelper.KnownMode.EmbeddedRuntimeConfig); + public static readonly EmbedItem AssemblyStore = new ("embedded_assembly_store", "assembly_store", NativeAssemblerItemsHelper.KnownMode.EmbeddedAssemblyStore); } - sealed class LlvmMcTargetConfig - { - public readonly string TargetArch; - public readonly string TripleArch; - public readonly string TripleApiPrefix; - public readonly string AssemblerDirectivePrefix; - public readonly string SizeType; - public readonly uint WordSize; - - public LlvmMcTargetConfig (string targetArch, string tripleArch, string tripleApiPrefix, string assemblerDirectivePrefix, string sizeType, uint wordSize) - { - TargetArch = targetArch; - TripleArch = tripleArch; - TripleApiPrefix = tripleApiPrefix; - AssemblerDirectivePrefix = assemblerDirectivePrefix; - SizeType = sizeType; - WordSize = wordSize; - } - } - - static readonly Dictionary llvmMcConfigs = new () { - { AndroidTargetArch.Arm64, new ("aarch64", "aarch64", "android", "@", ".xword", 8) }, - { AndroidTargetArch.Arm, new ("arm", "armv7a", "androideabi", "%", ".long", 4) }, - { AndroidTargetArch.X86_64, new ("x86-64", "x86_64", "android", "@", ".quad", 8) }, - { AndroidTargetArch.X86, new ("x86", "i686", "android", "@", ".long", 4) }, - }; - static readonly Encoding asmFileEncoding = new UTF8Encoding (false); - public static List EmbedBinary ( + public static void EmbedBinary ( TaskLoggingHelper log, ICollection supportedAbis, string androidBinUtilsDirectory, @@ -68,30 +42,23 @@ public static List EmbedBinary ( string outputDirectory, bool missingContentOK) { - var ret = new List (); if (supportedAbis.Count < 1) { log.LogDebugMessage ("ELFEmbeddingHelper: at least one target ABI must be specified. Probably a DTB build, skipping generation."); - return ret; + return; } - string llvmMcPath = GetLlvmMcPath (androidBinUtilsDirectory); foreach (string abi in supportedAbis) { - EmbedBinary ( + DoEmbed ( log, - ret, - llvmMcPath, - abi, - inputFile, - outputDirectory, + MonoAndroidHelper.AbiToTargetArch (abi), + inputFile, outputDirectory, embedItem, missingContentOK ); } - - return ret; } - public static List EmbedBinary ( + public static void EmbedBinary ( TaskLoggingHelper log, string abi, string androidBinUtilsDirectory, @@ -100,59 +67,30 @@ public static List EmbedBinary ( string outputDirectory, bool missingContentOK) { - var ret = new List (); if (String.IsNullOrEmpty (abi)) { log.LogDebugMessage ("ELFEmbeddingHelper: ABI must be specified. Probably a DTB build, skipping generation."); - return ret; + return; } - EmbedBinary ( + DoEmbed ( log, - ret, - GetLlvmMcPath (androidBinUtilsDirectory), - abi, + MonoAndroidHelper.AbiToTargetArch (abi), inputFile, outputDirectory, embedItem, missingContentOK ); - return ret; - } - - static void EmbedBinary ( - TaskLoggingHelper log, - List resultItems, - string llvmMcPath, - string abi, - string inputFile, - string outputDirectory, - EmbedItem embedItem, - bool missingContentOK) - { - string outputFile = Path.Combine (outputDirectory, $"embed_{embedItem.BaseFileName}.{abi.ToLowerInvariant ()}.o"); - DoEmbed (log, MonoAndroidHelper.AbiToTargetArch (abi), llvmMcPath, inputFile, outputFile, embedItem, missingContentOK); - if (!File.Exists (outputFile)) { - return; - } - - var taskItem = new TaskItem (outputFile); - taskItem.SetMetadata ("Abi", abi); - taskItem.SetMetadata ("RuntimeIdentifier", MonoAndroidHelper.AbiToRid (abi)); - resultItems.Add (taskItem); } static void DoEmbed ( TaskLoggingHelper log, AndroidTargetArch arch, - string llvmMcPath, string? inputFile, - string outputFile, + string outputDirectory, EmbedItem item, bool missingContentOK) { - if (!llvmMcConfigs.TryGetValue (arch, out LlvmMcTargetConfig cfg)) { - throw new NotSupportedException ($"Internal error: unsupported target arch '{arch}'"); - } + NativeAssemblerCompilation.LlvmMcTargetConfig cfg = NativeAssemblerCompilation.GetLlvmMcConfig (arch); bool haveInputFile = !String.IsNullOrEmpty (inputFile); if (!haveInputFile) { @@ -162,7 +100,6 @@ static void DoEmbed ( } else { inputFile = Path.GetFullPath (inputFile); } - outputFile = Path.GetFullPath (outputFile); long inputFileSize = 0; string? sanitizedInputFilePath = null; @@ -177,9 +114,9 @@ static void DoEmbed ( } } - string asmInputFile = Path.ChangeExtension (outputFile, ".s"); + string asmSourceFile = NativeAssemblerItemsHelper.GetSourcePath (log, item.NativeAssemblerMode, outputDirectory, arch); - using var fs = File.Open (asmInputFile, FileMode.Create, FileAccess.Write, FileShare.Read); + using var fs = File.Open (asmSourceFile, FileMode.Create, FileAccess.Write, FileShare.Read); using var sw = new StreamWriter (fs, asmFileEncoding); string symbolName = item.SymbolName; @@ -204,24 +141,5 @@ static void DoEmbed ( sw.Flush (); sw.Close (); - - var args = new List { - $"--arch={cfg.TargetArch}", - "--assemble", - "--filetype=obj", - "-g", - $"--triple={cfg.TripleArch}-linux-{cfg.TripleApiPrefix}{XABuildConfig.AndroidMinimumDotNetApiLevel}", - "-o", MonoAndroidHelper.QuoteFileNameArgument (outputFile), - MonoAndroidHelper.QuoteFileNameArgument (asmInputFile), - }; - - // int ret = MonoAndroidHelper.RunProcess (llvmMcPath, String.Join (" ", args), log); - // File.Copy (asmInputFile, $"/tmp/{Path.GetFileName (asmInputFile)}", true); - // File.Copy (outputFile, $"/tmp/{Path.GetFileName (outputFile)}", true); - // if (ret != 0) { - // return; - // } } - - static string GetLlvmMcPath (string androidBinUtilsDirectory) => MonoAndroidHelper.GetLlvmMcPath (androidBinUtilsDirectory); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerCompilation.cs b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerCompilation.cs index 78a3b33d90e..6e4c08478ce 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerCompilation.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerCompilation.cs @@ -149,26 +149,25 @@ public static void RunAssembler (AssemblerRunContext context, AssemblerConfig co if (e.Data != null) { OnOutputData (context, assemblerName, s, e); stdoutLines.Add (e.Data); - } else + } else { stdout_completed.Set (); + } }; proc.ErrorDataReceived += (s, e) => { if (e.Data != null) { OnErrorData (context, assemblerName, s, e); stderrLines.Add (e.Data); - } else + } else { stderr_completed.Set (); + } }; proc.StartInfo = psi; proc.Start (); proc.BeginOutputReadLine (); proc.BeginErrorReadLine (); - - if (context.RegisterForCancellation != null) { - context.RegisterForCancellation (proc); - } + context.RegisterForCancellation?.Invoke (proc); proc.WaitForExit (); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerItemsHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerItemsHelper.cs index 6f2df37c30a..6781f2461eb 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerItemsHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/NativeAssemblerItemsHelper.cs @@ -3,6 +3,7 @@ using System.IO; using Microsoft.Build.Utilities; +using Xamarin.Android.Tools; namespace Xamarin.Android.Tasks; @@ -44,6 +45,11 @@ public ModeConfig (string fileNameBase, string extension) { KnownMode.TypeMap, new ("typemaps", LlvmIrExtension) }, }; + public static string? GetSourcePath (TaskLoggingHelper log, KnownMode mode, string nativeSourcesDir, AndroidTargetArch arch) + { + return GetSourcePath (log, mode, nativeSourcesDir, MonoAndroidHelper.ArchToAbi (arch)); + } + public static string? GetSourcePath (TaskLoggingHelper log, KnownMode mode, string nativeSourcesDir, string abi) { if (!ModeConfigs.TryGetValue (mode, out ModeConfig config)) { diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 15c55742b7b..c3c3700ac47 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2117,7 +2117,7 @@ because xbuild doesn't support framework reference assemblies. - + <_NativeAssemblyTarget Include="@(_TypeMapAssemblySource->'$([System.IO.Path]::ChangeExtension('%(Identity)', '.o'))')"> %(_TypeMapAssemblySource.abi) @@ -2137,6 +2137,9 @@ because xbuild doesn't support framework reference assemblies. <_NativeAssemblyTarget Include="@(_AndroidRemapAssemblySource->'$([System.IO.Path]::ChangeExtension('%(Identity)', '.o'))')"> %(_AndroidRemapAssemblySource.abi) + <_NativeAssemblyTarget Include="@(_EmbeddedAssemblyStoreSourceFiles->'$([System.IO.Path]::ChangeExtension('%(Identity)', '.o'))')"> + %(_EmbeddedAssemblyStoreSourceFiles.abi) + <_NativeAssemblyTarget Include="@(_EmbeddedRuntimeConfigAssemblySource->'$([System.IO.Path]::ChangeExtension('%(Identity)', '.o'))')"> %(_EmbeddedRuntimeConfigAssemblySource.abi) @@ -2145,6 +2148,7 @@ because xbuild doesn't support framework reference assemblies. <_NativeAssemblySource Include="@(_AndroidRemapAssemblySource)" /> <_NativeAssemblySource Include="@(_CompressedAssembliesAssemblySource)" /> + <_NativeAssemblySource Include="@(_EmbeddedAssemblyStoreSourceFiles)" /> <_NativeAssemblySource Include="@(_EmbeddedRuntimeConfigAssemblySource)" /> <_NativeAssemblySource Include="@(_EnvironmentAssemblySource)" /> <_NativeAssemblySource Include="@(_MarshalMethodsAssemblySource)" /> @@ -2167,7 +2171,7 @@ because xbuild doesn't support framework reference assemblies. Date: Tue, 22 Oct 2024 11:46:32 +0200 Subject: [PATCH 31/60] Always generate embedded store sources in CreateEmbeddedAssemblyStore --- ...crosoft.Android.Sdk.AssemblyStores.targets | 2 +- .../Tasks/CreateEmbeddedAssemblyStore.cs | 25 +++++++++++++++++++ .../Tasks/GeneratePackageManagerJava.cs | 6 +---- ...pplicationConfigNativeAssemblyGenerator.cs | 19 -------------- .../Xamarin.Android.Common.targets | 3 +-- 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets index c47516065c0..89da58cc4f1 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets @@ -13,7 +13,6 @@ @@ -21,6 +20,7 @@ AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" AppSharedLibrariesDir="$(_AndroidApplicationSharedLibraryPath)" AssemblySourcesDir="$(IntermediateOutputPath)android" + AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)" CompressedAssembliesDir="$(_AndroidCompressedAssembliesDir)\test\" Debug="$(AndroidIncludeDebugSymbols)" EnableCompression="$(AndroidEnableAssemblyCompression)" diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs index 2823af2c3e8..d6eda689509 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs @@ -25,6 +25,9 @@ public class CreateEmbeddedAssemblyStore : AndroidTask [Required] public string CompressedAssembliesDir { get; set; } + [Required] + public bool AssemblyStoreEmbeddedInRuntime { get; set; } + [Required] public bool Debug { get; set; } @@ -44,6 +47,28 @@ public class CreateEmbeddedAssemblyStore : AndroidTask public string [] SupportedAbis { get; set; } public override bool RunTask () + { + if (AssemblyStoreEmbeddedInRuntime) { + return EmbedAssemblyStore (); + } + + // Generate sources to satisfy libmonodroid's ABI requirements + foreach (string abi in SupportedAbis) { + ELFEmbeddingHelper.EmbedBinary ( + Log, + abi, + AndroidBinUtilsDirectory, + inputFile: null, + ELFEmbeddingHelper.KnownEmbedItems.AssemblyStore, + AssemblySourcesDir, + missingContentOK: true + ); + } + + return !Log.HasLoggedErrors; + } + + bool EmbedAssemblyStore () { bool compress = !Debug && EnableCompression; IDictionary>? compressedAssembliesInfo = null; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 1ad4ee1fb58..0e102d6f90d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -62,13 +62,10 @@ public override bool RunTask () [Required] public bool EnablePreloadAssembliesDefault { get; set; } - // These two properties should be required but they will require modifying `monodroid` first + // This property should be required but it will require modifying `monodroid` first //[Required] public string AndroidBinUtilsDirectory { get; set; } - //[Required] - public bool AssemblyStoreEmbeddedInRuntime { get; set; } - public bool EnableMarshalMethods { get; set; } public string RuntimeConfigBinFilePath { get; set; } public string BoundExceptionType { get; set; } @@ -352,7 +349,6 @@ void AddEnvironment () JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, MarshalMethodsEnabled = EnableMarshalMethods, IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), - AssemblyStoreEmbeddedInRuntime = UseAssemblyStore && AssemblyStoreEmbeddedInRuntime, }; LLVMIR.LlvmIrModule appConfigModule = appConfigAsmGen.Construct (); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs index 097f84dea99..d374df67dbb 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs @@ -198,7 +198,6 @@ sealed class XamarinAndroidBundledAssembly public bool MarshalMethodsEnabled { get; set; } public bool ManagedMarshalMethodsLookupEnabled { get; set; } public bool IgnoreSplitConfigs { get; set; } - public bool AssemblyStoreEmbeddedInRuntime { get; set; } public ApplicationConfigNativeAssemblyGenerator (IDictionary environmentVariables, IDictionary systemProperties, TaskLoggingHelper log) : base (log) @@ -308,24 +307,6 @@ protected override void Construct (LlvmIrModule module) module.Add (bundled_assemblies); AddAssemblyStores (module); - - if (AssemblyStoreEmbeddedInRuntime) { - return; - } - - // Need these to keep ABI compatibility with `libxamarin-app.so` used at the runtime's build time - var embedded_assembly_store_size = new LlvmIrGlobalVariable ( - (ulong)0, - "embedded_assembly_store_size", - LlvmIrVariableOptions.GlobalConstant - ); - module.Add (embedded_assembly_store_size); - - var embedded_assembly_store = new LlvmIrGlobalVariable (typeof (byte[]), "embedded_assembly_store", LlvmIrVariableOptions.GlobalWritable) { - ZeroInitializeArray = true, - ArrayItemCount = 0, - }; - module.Add (embedded_assembly_store); } void AddAssemblyStores (LlvmIrModule module) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index c3c3700ac47..f88a86453b5 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1906,8 +1906,7 @@ because xbuild doesn't support framework reference assemblies. UseAssemblyStore="$(AndroidUseAssemblyStore)" EnableMarshalMethods="$(_AndroidUseMarshalMethods)" CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" - AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - AssemblyStoreEmbeddedInRuntime="$(_AndroidEmbedAssemblyStoreInRuntime)" /> + AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" /> From b3b644d857672c656c86250a6eb84cad4048af39 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 22 Oct 2024 16:46:39 +0200 Subject: [PATCH 32/60] Let's see... --- .../Microsoft.Android.Sdk.AssemblyResolution.targets | 4 ++-- .../Microsoft.Android.Sdk.AssemblyStores.targets | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets index 6c3a48b3131..cc91d4a18d7 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets @@ -204,7 +204,7 @@ _ResolveAssemblies MSBuild target. - + <_ResolvedAssemblies Include="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " /> <_ResolvedUserAssemblies Include="@(ResolvedUserAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " /> <_ResolvedFrameworkAssemblies Include="@(ResolvedFrameworkAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " /> @@ -213,7 +213,7 @@ _ResolveAssemblies MSBuild target. <_ShrunkUserAssemblies Include="@(_ResolvedUserAssemblies)" /> <_ShrunkFrameworkAssemblies Include="@(_ResolvedFrameworkAssemblies)" /> - + <_ResolvedAssemblies Include="@(ResolvedAssemblies)" /> <_ResolvedUserAssemblies Include="@(ResolvedUserAssemblies)" /> <_ResolvedFrameworkAssemblies Include="@(ResolvedFrameworkAssemblies)" /> diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets index 89da58cc4f1..22fa9dca278 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets @@ -8,13 +8,18 @@ BuildTargetAbis="@(_BuildTargetAbis)" NativeSourcesDir="$(_NativeAssemblySourceDir)" Mode="EmbeddedAssemblyStore"> - - + + + + + <_CreateEmbeddedAssemblyStoreAssembly Include="@(_ShrunkUserAssemblies);@(_AndroidResolvedSatellitePaths);@(_ShrunkFrameworkAssemblies)"/> + <_CreateEmbeddedAssemblyStoreAssembly Condition=" '@(_CreateEmbeddedAssemblyStoreAssembly->Count())' == '0' " Include="@(_ResolvedUserAssemblies);@(_ResolvedFrameworkAssemblies);@(_AndroidResolvedSatellitePaths)" /> + Date: Wed, 23 Oct 2024 13:09:41 +0200 Subject: [PATCH 33/60] Don't assume assemblies exist --- .../ApplicationAttribute.Partial.cs | 6 ++ .../InstrumentationAttribute.Partial.cs | 10 ++- .../PermissionAttribute.Partial.cs | 10 ++- .../PermissionGroupAttribute.Partial.cs | 10 ++- .../PermissionTreeAttribute.Partial.cs | 10 ++- .../SupportsGLTextureAttribute.Partial.cs | 9 +- .../UsesFeatureAttribute.Partial.cs | 9 +- .../UsesPermissionAttribute.Partial.cs | 6 ++ .../Tasks/GeneratePackageManagerJava.cs | 82 ++++++++++++++++++- .../Utilities/ManifestDocument.cs | 4 + 10 files changed, 143 insertions(+), 13 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/ApplicationAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/ApplicationAttribute.Partial.cs index 2997d50006e..1c8f86c9ac9 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/ApplicationAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/ApplicationAttribute.Partial.cs @@ -60,6 +60,12 @@ static partial void AddManualMapping () public static ApplicationAttribute FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { + // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of + // tests which check these situations. + if (provider == null) { + return null; + } + CustomAttribute attr = provider.GetCustomAttributes ("Android.App.ApplicationAttribute") .SingleOrDefault (); if (attr == null) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs index 98b5a0611fc..8aff5daaa87 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs @@ -13,11 +13,17 @@ namespace Android.App { partial class InstrumentationAttribute { - - ICollection? specified; + + ICollection specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { + // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of + // tests which check these situations. + if (provider == null) { + yield break; + } + foreach (CustomAttribute attr in provider.GetCustomAttributes ("Android.App.InstrumentationAttribute")) { InstrumentationAttribute self = new InstrumentationAttribute (); self.specified = mapping.Load (self, attr, cache); diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs index 2f85d446562..16d32e0bf5b 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs @@ -16,11 +16,17 @@ namespace Android.App { partial class PermissionAttribute { - - ICollection? specified; + + ICollection specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { + // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of + // tests which check these situations. + if (provider == null) { + yield break; + } + var attrs = provider.GetCustomAttributes ("Android.App.PermissionAttribute"); foreach (var attr in attrs) { PermissionAttribute self = new PermissionAttribute (); diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs index 51d1a9f0d95..1cda1eefe1b 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs @@ -16,11 +16,17 @@ namespace Android.App { partial class PermissionGroupAttribute { - - ICollection? specified; + + ICollection specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { + // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of + // tests which check these situations. + if (provider == null) { + yield break; + } + var attrs = provider.GetCustomAttributes ("Android.App.PermissionGroupAttribute"); foreach (var attr in attrs) { PermissionGroupAttribute self = new PermissionGroupAttribute (); diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs index 2c88bfdaaa7..5447164294c 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs @@ -16,11 +16,17 @@ namespace Android.App { partial class PermissionTreeAttribute { - - ICollection? specified; + + ICollection specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { + // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of + // tests which check these situations. + if (provider == null) { + yield break; + } + var attrs = provider.GetCustomAttributes ("Android.App.PermissionTreeAttribute"); foreach (var attr in attrs) { PermissionTreeAttribute self = new PermissionTreeAttribute (); diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs index b632f1e4717..15bd12f175c 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs @@ -31,16 +31,21 @@ internal XElement ToElement (string packageName, TypeDefinitionCache cache) public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { + // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of + // tests which check these situations. + if (provider == null) { + yield break; + } + var attrs = provider.GetCustomAttributes ("Android.App.SupportsGLTextureAttribute"); foreach (var attr in attrs) { if (attr.HasConstructorArguments && attr.ConstructorArguments.Count == 1) { SupportsGLTextureAttribute self = new SupportsGLTextureAttribute((string)attr.ConstructorArguments[0].Value); self.specified = mapping.Load (self, attr, cache); self.specified.Add("Name"); - yield return self; + yield return self; } } } } } - diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs index 86ecc5f825c..90d4d29b7be 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs @@ -37,12 +37,18 @@ internal XElement ToElement (string packageName, TypeDefinitionCache cache) public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { + // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of + // tests which check these situations. + if (provider == null) { + yield break; + } + var attrs = provider.GetCustomAttributes ("Android.App.UsesFeatureAttribute"); foreach (var attr in attrs) { UsesFeatureAttribute self = new UsesFeatureAttribute (); - if (attr.HasProperties) { + if (attr.HasProperties) { // handle the case where the user sets additional properties self.specified = mapping.Load (self, attr, cache); if (self.specified.Contains("GLESVersion") && self.GLESVersion==0) { @@ -66,4 +72,3 @@ public static IEnumerable FromCustomAttributeProvider (ICu } } } - diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesPermissionAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesPermissionAttribute.Partial.cs index 7b957979b72..48648aceefc 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesPermissionAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesPermissionAttribute.Partial.cs @@ -16,6 +16,12 @@ partial class UsesPermissionAttribute { public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { + // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of + // tests which check these situations. + if (provider == null) { + yield break; + } + var attrs = provider.GetCustomAttributes ("Android.App.UsesPermissionAttribute"); foreach (var attr in attrs) { UsesPermissionAttribute self; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 0e102d6f90d..053a07a5eca 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -432,6 +432,86 @@ string ValidAssemblerString (string s) } } - return !Log.HasLoggedErrors; + bool ShouldIgnoreSplitConfigs () + { + if (String.IsNullOrEmpty (CustomBundleConfigFile)) { + return false; + } + + return BundleConfigSplitConfigsChecker.ShouldIgnoreSplitConfigs (Log, CustomBundleConfigFile); + } + + void GetRequiredTokens (string assemblyFilePath, out int android_runtime_jnienv_class_token, out int jnienv_initialize_method_token, out int jnienv_registerjninatives_method_token) + { + if (File.Exists (assemblyFilePath)) { + using var pe = new PEReader (File.OpenRead (assemblyFilePath)); + GetRequiredTokens (pe.GetMetadataReader (), out android_runtime_jnienv_class_token, out jnienv_initialize_method_token, out jnienv_registerjninatives_method_token); + } else { + android_runtime_jnienv_class_token = -1; + jnienv_initialize_method_token = -1; + jnienv_registerjninatives_method_token = -1; + Log.LogDebugMessage ($"Assembly '{assemblyFilePath}' does not exist, unable to read required tokens from it"); + return; + } + + if (android_runtime_jnienv_class_token == -1 || jnienv_initialize_method_token == -1 || jnienv_registerjninatives_method_token == -1) { + throw new InvalidOperationException ($"Unable to find the required Android.Runtime.JNIEnvInit method tokens for {assemblyFilePath}"); + } + } + + void GetRequiredTokens (MetadataReader reader, out int android_runtime_jnienv_class_token, out int jnienv_initialize_method_token, out int jnienv_registerjninatives_method_token) + { + android_runtime_jnienv_class_token = -1; + jnienv_initialize_method_token = -1; + jnienv_registerjninatives_method_token = -1; + + TypeDefinition? typeDefinition = null; + + foreach (TypeDefinitionHandle typeHandle in reader.TypeDefinitions) { + TypeDefinition td = reader.GetTypeDefinition (typeHandle); + if (!TypeMatches (td)) { + continue; + } + + typeDefinition = td; + android_runtime_jnienv_class_token = MetadataTokens.GetToken (reader, typeHandle); + break; + } + + if (typeDefinition == null) { + return; + } + + foreach (MethodDefinitionHandle methodHandle in typeDefinition.Value.GetMethods ()) { + MethodDefinition md = reader.GetMethodDefinition (methodHandle); + string name = reader.GetString (md.Name); + + if (jnienv_initialize_method_token == -1 && String.Compare (name, "Initialize", StringComparison.Ordinal) == 0) { + jnienv_initialize_method_token = MetadataTokens.GetToken (reader, methodHandle); + } else if (jnienv_registerjninatives_method_token == -1 && String.Compare (name, "RegisterJniNatives", StringComparison.Ordinal) == 0) { + jnienv_registerjninatives_method_token = MetadataTokens.GetToken (reader, methodHandle); + } + + if (jnienv_initialize_method_token != -1 && jnienv_registerjninatives_method_token != -1) { + break; + } + } + + + bool TypeMatches (TypeDefinition td) + { + string ns = reader.GetString (td.Namespace); + if (String.Compare (ns, "Android.Runtime", StringComparison.Ordinal) != 0) { + return false; + } + + string name = reader.GetString (td.Name); + if (String.Compare (name, "JNIEnvInit", StringComparison.Ordinal) != 0) { + return false; + } + + return true; + } + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs index 416ccb3f78f..0deaab05fe6 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs @@ -581,6 +581,10 @@ XElement CreateApplicationElement (XElement manifest, string applicationClass, L List usesConfigurationAttr = []; foreach (var assemblyPath in Assemblies) { var assembly = Resolver.GetAssembly (assemblyPath); + if (assembly == null) { + continue; + } + if (ApplicationAttribute.FromCustomAttributeProvider (assembly, cache) is ApplicationAttribute a) { assemblyAttr.Add (a); } From 85d9a169d6bf48bc2f8f067722391950aa5f041c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 23 Oct 2024 13:15:22 +0200 Subject: [PATCH 34/60] better --- .../Tasks/GeneratePackageManagerJava.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 053a07a5eca..538e796461c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -443,10 +443,7 @@ bool ShouldIgnoreSplitConfigs () void GetRequiredTokens (string assemblyFilePath, out int android_runtime_jnienv_class_token, out int jnienv_initialize_method_token, out int jnienv_registerjninatives_method_token) { - if (File.Exists (assemblyFilePath)) { - using var pe = new PEReader (File.OpenRead (assemblyFilePath)); - GetRequiredTokens (pe.GetMetadataReader (), out android_runtime_jnienv_class_token, out jnienv_initialize_method_token, out jnienv_registerjninatives_method_token); - } else { + if (!File.Exists (assemblyFilePath)) { android_runtime_jnienv_class_token = -1; jnienv_initialize_method_token = -1; jnienv_registerjninatives_method_token = -1; @@ -454,6 +451,9 @@ void GetRequiredTokens (string assemblyFilePath, out int android_runtime_jnienv_ return; } + using var pe = new PEReader (File.OpenRead (assemblyFilePath)); + GetRequiredTokens (pe.GetMetadataReader (), out android_runtime_jnienv_class_token, out jnienv_initialize_method_token, out jnienv_registerjninatives_method_token); + if (android_runtime_jnienv_class_token == -1 || jnienv_initialize_method_token == -1 || jnienv_registerjninatives_method_token == -1) { throw new InvalidOperationException ($"Unable to find the required Android.Runtime.JNIEnvInit method tokens for {assemblyFilePath}"); } From bdc737e9710560eed500a6fef4cb811b6fd57ee9 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 23 Oct 2024 13:18:47 +0200 Subject: [PATCH 35/60] Update apkdesc files --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 31 ++++---- .../BuildReleaseArm64XFormsDotNet.apkdesc | 78 +++++++++---------- 2 files changed, 53 insertions(+), 56 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index 0d09c5250f4..1a3c881a8eb 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc @@ -5,49 +5,46 @@ "Size": 3036 }, "classes.dex": { - "Size": 22484 + "Size": 389676 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 18288 + "Size": 18296 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { "Size": 86688 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 117712 + "Size": 116080 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22384 + "Size": 22408 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24392 + "Size": 24376 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { "Size": 25336 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 628216 + "Size": 634344 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 20056 + "Size": 20040 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21480 + "Size": 21584 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 20024 }, - "lib/arm64-v8a/libarc.bin.so": { - "Size": 18872 - }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1524752 + "Size": 493384 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3101112 + "Size": 3196512 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71976 @@ -62,16 +59,16 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 19536 + "Size": 15144 }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 3266 + "Size": 3167 }, "META-INF/MANIFEST.MF": { - "Size": 3139 + "Size": 3040 }, "res/drawable-hdpi-v4/icon.png": { "Size": 2178 @@ -98,5 +95,5 @@ "Size": 1904 } }, - "PackageSize": 3078677 + "PackageSize": 2865612 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index cf5b327b70c..e4bc24bb7e3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -35,22 +35,22 @@ "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 96104 + "Size": 94648 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 562336 + "Size": 522008 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 23224 + "Size": 22408 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { - "Size": 21456 + "Size": 21432 }, "lib/arm64-v8a/lib_netstandard.dll.so": { - "Size": 23096 + "Size": 23072 }, "lib/arm64-v8a/lib_System.Collections.Concurrent.dll.so": { - "Size": 29896 + "Size": 29792 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { "Size": 36304 @@ -59,40 +59,43 @@ "Size": 25776 }, "lib/arm64-v8a/lib_System.Collections.Specialized.dll.so": { - "Size": 23856 + "Size": 23840 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { "Size": 19608 }, "lib/arm64-v8a/lib_System.ComponentModel.Primitives.dll.so": { - "Size": 21336 + "Size": 21304 }, "lib/arm64-v8a/lib_System.ComponentModel.TypeConverter.dll.so": { - "Size": 42440 + "Size": 42456 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 24440 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 19472 + "Size": 19448 + }, + "lib/arm64-v8a/lib_System.Diagnostics.DiagnosticSource.dll.so": { + "Size": 28440 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { "Size": 24704 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 19856 + "Size": 19848 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 19456 + "Size": 19424 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { - "Size": 30064 + "Size": 30040 }, "lib/arm64-v8a/lib_System.Formats.Asn1.dll.so": { - "Size": 50312 + "Size": 49928 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 29496 + "Size": 29472 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { "Size": 33800 @@ -104,31 +107,31 @@ "Size": 40696 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 185864 + "Size": 185800 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { - "Size": 85904 + "Size": 89488 }, "lib/arm64-v8a/lib_System.Net.Primitives.dll.so": { - "Size": 42184 + "Size": 41112 }, "lib/arm64-v8a/lib_System.Net.Requests.dll.so": { - "Size": 21568 + "Size": 21544 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 27088 + "Size": 27064 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 967200 + "Size": 956568 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 216496 + "Size": 216720 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { - "Size": 62728 + "Size": 62184 }, "lib/arm64-v8a/lib_System.Private.Xml.dll.so": { - "Size": 236920 + "Size": 237120 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { "Size": 35600 @@ -137,7 +140,7 @@ "Size": 20264 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21488 + "Size": 21584 }, "lib/arm64-v8a/lib_System.Runtime.Numerics.dll.so": { "Size": 55784 @@ -146,22 +149,22 @@ "Size": 19376 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 20352 + "Size": 20328 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { "Size": 21472 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { - "Size": 81288 + "Size": 80496 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 187056 + "Size": 183584 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 19272 + "Size": 19248 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 19288 + "Size": 19264 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 22096 @@ -235,17 +238,14 @@ "lib/arm64-v8a/lib_Xamarin.Google.Android.Material.dll.so": { "Size": 84912 }, - "lib/arm64-v8a/libarc.bin.so": { - "Size": 18936 - }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { "Size": 36600 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1516584 + "Size": 493384 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3110944 + "Size": 3196512 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71952 @@ -260,7 +260,7 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 353048 + "Size": 122144 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -416,7 +416,7 @@ "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 98445 + "Size": 98562 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -443,7 +443,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98318 + "Size": 98435 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2483,5 +2483,5 @@ "Size": 812848 } }, - "PackageSize": 10955937 + "PackageSize": 10677500 } \ No newline at end of file From 5acd749e8ca0b7b899ba0269d64609b9977085f7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 23 Oct 2024 18:23:47 +0200 Subject: [PATCH 36/60] Load embedded assembly store also in filesystem mode --- .../mono/monodroid/embedded-assemblies-zip.cc | 2 +- .../mono/monodroid/embedded-assemblies.cc | 24 ++++++++++++------- .../mono/monodroid/embedded-assemblies.hh | 6 +++++ src/native/mono/runtime-base/monodroid-dl.hh | 4 ++-- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index a554f3ef9bf..7da208e26b0 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -266,7 +266,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::span const& b dynamic_local_string entry_name; bool assembly_store_found = embedded_assembly_store_size != 0; if (assembly_store_found) { - verify_assembly_store_and_set_info (embedded_assembly_store, "embedded"); + load_embedded_assembly_store (); log_debug (LOG_ASSEMBLY, "Looking for DSOs in APK"); } else { log_debug (LOG_ASSEMBLY, "Looking for assembly store ('%s') and DSOs in APK", assembly_store_file_path.data ()); diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 98e80d8a289..261ee52e230 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -1405,13 +1405,21 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look size_t EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_register) noexcept { - log_debug (LOG_ASSEMBLY, "Registering assemblies from the filesystem"sv); - constexpr bool LookForMangledNames = true; - size_t assembly_count = register_from_filesystem ( - AndroidSystem::app_lib_directories[0], - LookForMangledNames, - should_register - ); + size_t assembly_count; + + if (embedded_assembly_store_size > 0) { + log_debug (LOG_ASSEMBLY, "Filesystem mode, but registering assemblies from the embedded assembly store"); + load_embedded_assembly_store (); + assembly_count = assembly_store.assembly_count; + } else { + log_debug (LOG_ASSEMBLY, "Registering assemblies from the filesystem"); + constexpr bool LookForMangledNames = true; + assembly_count = register_from_filesystem ( + AndroidSystem::app_lib_directories[0], + LookForMangledNames, + should_register + ); + } #if defined(DEBUG) constexpr bool DoNotLookForMangledNames = false; @@ -1423,6 +1431,6 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r ); #endif - log_debug (LOG_ASSEMBLY, "Found {} assemblies on the filesystem", assembly_count); + log_debug (LOG_ASSEMBLY, "Found %zu assemblies", assembly_count); return assembly_count; } diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index db110d7f426..9b937c35c2a 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -417,6 +417,12 @@ namespace xamarin::android::internal { void set_debug_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; void verify_assembly_store_and_set_info (void *data_start, const char *name) noexcept; + + void load_embedded_assembly_store () noexcept + { + verify_assembly_store_and_set_info (embedded_assembly_store, "embedded"); + } + void map_assembly_store (dynamic_local_string const& entry_name, ZipEntryLoadState &state) noexcept; const AssemblyStoreIndexEntry* find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept; void store_individual_assembly_data (dynamic_local_string const& entry_name, ZipEntryLoadState const& state, monodroid_should_register should_register) noexcept; diff --git a/src/native/mono/runtime-base/monodroid-dl.hh b/src/native/mono/runtime-base/monodroid-dl.hh index 93cb8b70b48..4b5fbe1be0f 100644 --- a/src/native/mono/runtime-base/monodroid-dl.hh +++ b/src/native/mono/runtime-base/monodroid-dl.hh @@ -48,11 +48,11 @@ namespace xamarin::android::internal size_t arr_size; if constexpr (WhichCache == CacheKind::AOT) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in AOT cache", hash); + log_debug (LOG_ASSEMBLY, "Looking for hash 0x%zx in AOT cache", hash); arr = aot_dso_cache; arr_size = application_config.number_of_aot_cache_entries; } else if constexpr (WhichCache == CacheKind::DSO) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); + log_debug (LOG_ASSEMBLY, "Looking for hash 0x%zx in DSO cache", hash); arr = dso_cache; arr_size = application_config.number_of_dso_cache_entries; } From 7ce1f65fca5c9db86441fbe2fa4341b9d27d8c2e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 23 Oct 2024 18:29:51 +0200 Subject: [PATCH 37/60] Log it when an assembly is missing in ManifestDocument --- .../Utilities/ManifestDocument.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs index 0deaab05fe6..48369483e06 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs @@ -290,7 +290,7 @@ public IList Merge (TaskLoggingHelper log, TypeDefinitionCache cache, Li string.IsNullOrEmpty (VersionName) ? "1.0" : VersionName); } - app = CreateApplicationElement (manifest, applicationClass, subclasses, cache); + app = CreateApplicationElement (log, manifest, applicationClass, subclasses, cache); if (app.Attribute (androidNs + "label") == null && !string.IsNullOrEmpty (ApplicationLabel)) app.SetAttributeValue (androidNs + "label", ApplicationLabel); @@ -570,7 +570,7 @@ Func GetGenerator (T return null; } - XElement CreateApplicationElement (XElement manifest, string applicationClass, List subclasses, TypeDefinitionCache cache) + XElement CreateApplicationElement (TaskLoggingHelper log, XElement manifest, string applicationClass, List subclasses, TypeDefinitionCache cache) { var application = manifest.Descendants ("application").FirstOrDefault (); @@ -582,6 +582,7 @@ XElement CreateApplicationElement (XElement manifest, string applicationClass, L foreach (var assemblyPath in Assemblies) { var assembly = Resolver.GetAssembly (assemblyPath); if (assembly == null) { + log.LogDebugMessage ($"Assembly '{assemblyPath}' not found."); continue; } From b1adce328beb1d0a5838c7926f09a1347467df19 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 23 Oct 2024 21:02:49 +0200 Subject: [PATCH 38/60] Don't throw --- .../AssemblyStore/AssemblyStoreExplorer.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/assembly-store-reader-mk2/AssemblyStore/AssemblyStoreExplorer.cs b/tools/assembly-store-reader-mk2/AssemblyStore/AssemblyStoreExplorer.cs index d6a5a638302..aef64a09d3d 100644 --- a/tools/assembly-store-reader-mk2/AssemblyStore/AssemblyStoreExplorer.cs +++ b/tools/assembly-store-reader-mk2/AssemblyStore/AssemblyStoreExplorer.cs @@ -140,7 +140,19 @@ public static (IList? explorers, string? errorMessage) Op ZipEntry entry = zip.ReadEntry (path); var stream = new MemoryStream (); entry.Extract (stream); - ret.Add (new AssemblyStoreExplorer (stream, $"{fi.FullName}!{path}")); + AssemblyStoreExplorer? explorer = null; + try { + // It may throw when opening an apk without any assembly stores, in which case the v2 store reader would + // always find `libxamarin-app.so` and try to read the embedded store and fail, throwing from the explorer + // constructor. + explorer = new AssemblyStoreExplorer (stream, $"{fi.FullName}!{path}"); + } catch (NotSupportedException) { + // Ignore + } + + if (explorer != null) { + ret.Add (explorer); + } } if (ret.Count == 0) { From 9f858831bedec844adc9b5727d9501163693dc6e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 24 Oct 2024 15:49:21 +0200 Subject: [PATCH 39/60] Always create the destination directory --- src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs index 2d6a2551765..52704354a63 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs @@ -116,6 +116,7 @@ static void DoEmbed ( string asmSourceFile = NativeAssemblerItemsHelper.GetSourcePath (log, item.NativeAssemblerMode, outputDirectory, arch); + Directory.CreateDirectory (Path.GetDirectoryName (asmSourceFile)); using var fs = File.Open (asmSourceFile, FileMode.Create, FileAccess.Write, FileShare.Read); using var sw = new StreamWriter (fs, asmFileEncoding); From 0cfed0e13efb423f8830876314122bcfcb7f9aea Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 28 Oct 2024 12:26:17 +0100 Subject: [PATCH 40/60] Post-rebase fixups --- src/native/mono/monodroid/embedded-assemblies-zip.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 7da208e26b0..38f58276424 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -371,8 +371,10 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus .max_assembly_file_name_size = 0u, }; + std::unique_ptr raw_data (new uint8_t[cd_size]); + std::span buf (raw_data.get (), cd_size); ssize_t nread = read (fd, buf.data (), buf.size ()); - if (static_cast(nread) != cd_size) { + if (static_cast(nread) != cd_size) [[unlikely]] { Helpers::abort_application ( LOG_ASSEMBLY, std::format ( From fe9d6cdde6f99314e5f47af8edeee22185afad1a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 28 Oct 2024 14:29:50 +0100 Subject: [PATCH 41/60] Let's see what's in the override dir listing --- tests/MSBuildDeviceIntegration/Tests/InstallTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs index b5b7f7628d3..c515e8a5c92 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs @@ -201,6 +201,7 @@ public void InstallWithoutSharedRuntime () //Assert.AreEqual (0, RunAdbCommand ("shell pm list packages Mono.Android.DebugRuntime").Trim ().Length, // "The Shared Runtime should not have been installed."); var directorylist = GetContentFromAllOverrideDirectories (proj.PackageName, DeviceAbi); + Console.WriteLine ($"InstallWithoutSharedRuntime: directoryList == '{directorylist}'"); StringAssert.Contains ($"{proj.ProjectName}.dll", directorylist, $"{proj.ProjectName}.dll should exist in the .__override__/{DeviceAbi} directory."); StringAssert.Contains ($"System.Private.CoreLib.dll", directorylist, $"System.Private.CoreLib.dll should exist in the .__override__/{DeviceAbi} directory."); StringAssert.Contains ($"Mono.Android.dll", directorylist, $"Mono.Android.dll should exist in the .__override__/{DeviceAbi} directory."); @@ -546,7 +547,7 @@ public void IncrementalFastDeployment (string packageFormat) } long lib1FirstBuildSize = new FileInfo (Path.Combine (rootPath, lib1.ProjectName, lib1.OutputPath, "Library1.dll")).Length; - + using (var builder = CreateApkBuilder (Path.Combine (rootPath, app.ProjectName))) { builder.Verbosity = LoggerVerbosity.Detailed; builder.ThrowOnBuildFailure = false; @@ -653,7 +654,7 @@ public void AppWithAndroidJavaSource () public class TestJavaClass2 { public String test(){ - + return ""Java is called""; } }", @@ -671,7 +672,7 @@ public String test(){ public class TestJavaClass { public String test(){ - + return ""Java is called""; } }", From d58026930831adcaadaf667ea0b1ef88c1f408c9 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 28 Oct 2024 20:13:04 +0100 Subject: [PATCH 42/60] Let's see --- .../targets/Microsoft.Android.Sdk.AssemblyResolution.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets index cc91d4a18d7..6c3a48b3131 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets @@ -204,7 +204,7 @@ _ResolveAssemblies MSBuild target. - + <_ResolvedAssemblies Include="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " /> <_ResolvedUserAssemblies Include="@(ResolvedUserAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " /> <_ResolvedFrameworkAssemblies Include="@(ResolvedFrameworkAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " /> @@ -213,7 +213,7 @@ _ResolveAssemblies MSBuild target. <_ShrunkUserAssemblies Include="@(_ResolvedUserAssemblies)" /> <_ShrunkFrameworkAssemblies Include="@(_ResolvedFrameworkAssemblies)" /> - + <_ResolvedAssemblies Include="@(ResolvedAssemblies)" /> <_ResolvedUserAssemblies Include="@(ResolvedUserAssemblies)" /> <_ResolvedFrameworkAssemblies Include="@(ResolvedFrameworkAssemblies)" /> From 76295b657db88bf002b43735735689dd40642e03 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 29 Oct 2024 10:29:17 +0100 Subject: [PATCH 43/60] Cleanup --- .../Mono.Android/InstrumentationAttribute.Partial.cs | 2 +- .../Mono.Android/PermissionAttribute.Partial.cs | 2 +- .../Mono.Android/PermissionGroupAttribute.Partial.cs | 2 +- .../Mono.Android/PermissionTreeAttribute.Partial.cs | 2 +- .../Mono.Android/SupportsGLTextureAttribute.Partial.cs | 3 ++- .../Mono.Android/UsesFeatureAttribute.Partial.cs | 3 ++- tests/MSBuildDeviceIntegration/Tests/InstallTests.cs | 7 +++---- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs index 8aff5daaa87..3cedac868db 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs @@ -13,7 +13,7 @@ namespace Android.App { partial class InstrumentationAttribute { - + ICollection specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs index 16d32e0bf5b..ebabfbc9562 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs @@ -16,7 +16,7 @@ namespace Android.App { partial class PermissionAttribute { - + ICollection specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs index 1cda1eefe1b..99cedace7d6 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs @@ -16,7 +16,7 @@ namespace Android.App { partial class PermissionGroupAttribute { - + ICollection specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs index 5447164294c..79ca7af4999 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs @@ -16,7 +16,7 @@ namespace Android.App { partial class PermissionTreeAttribute { - + ICollection specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs index 15bd12f175c..dcf0dedcec6 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs @@ -43,9 +43,10 @@ public static IEnumerable FromCustomAttributeProvide SupportsGLTextureAttribute self = new SupportsGLTextureAttribute((string)attr.ConstructorArguments[0].Value); self.specified = mapping.Load (self, attr, cache); self.specified.Add("Name"); - yield return self; + yield return self; } } } } } + diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs index 90d4d29b7be..8ab6545d20d 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs @@ -48,7 +48,7 @@ public static IEnumerable FromCustomAttributeProvider (ICu UsesFeatureAttribute self = new UsesFeatureAttribute (); - if (attr.HasProperties) { + if (attr.HasProperties) { // handle the case where the user sets additional properties self.specified = mapping.Load (self, attr, cache); if (self.specified.Contains("GLESVersion") && self.GLESVersion==0) { @@ -72,3 +72,4 @@ public static IEnumerable FromCustomAttributeProvider (ICu } } } + diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs index c515e8a5c92..b5b7f7628d3 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallTests.cs @@ -201,7 +201,6 @@ public void InstallWithoutSharedRuntime () //Assert.AreEqual (0, RunAdbCommand ("shell pm list packages Mono.Android.DebugRuntime").Trim ().Length, // "The Shared Runtime should not have been installed."); var directorylist = GetContentFromAllOverrideDirectories (proj.PackageName, DeviceAbi); - Console.WriteLine ($"InstallWithoutSharedRuntime: directoryList == '{directorylist}'"); StringAssert.Contains ($"{proj.ProjectName}.dll", directorylist, $"{proj.ProjectName}.dll should exist in the .__override__/{DeviceAbi} directory."); StringAssert.Contains ($"System.Private.CoreLib.dll", directorylist, $"System.Private.CoreLib.dll should exist in the .__override__/{DeviceAbi} directory."); StringAssert.Contains ($"Mono.Android.dll", directorylist, $"Mono.Android.dll should exist in the .__override__/{DeviceAbi} directory."); @@ -547,7 +546,7 @@ public void IncrementalFastDeployment (string packageFormat) } long lib1FirstBuildSize = new FileInfo (Path.Combine (rootPath, lib1.ProjectName, lib1.OutputPath, "Library1.dll")).Length; - + using (var builder = CreateApkBuilder (Path.Combine (rootPath, app.ProjectName))) { builder.Verbosity = LoggerVerbosity.Detailed; builder.ThrowOnBuildFailure = false; @@ -654,7 +653,7 @@ public void AppWithAndroidJavaSource () public class TestJavaClass2 { public String test(){ - + return ""Java is called""; } }", @@ -672,7 +671,7 @@ public String test(){ public class TestJavaClass { public String test(){ - + return ""Java is called""; } }", From 1aebcf173722b54f68a76836c4eb923a36582f6d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 31 Oct 2024 09:10:59 +0100 Subject: [PATCH 44/60] Address feedback --- .../Mono.Android/ApplicationAttribute.Partial.cs | 6 ------ .../Mono.Android/InstrumentationAttribute.Partial.cs | 6 ------ .../Mono.Android/PermissionAttribute.Partial.cs | 6 ------ .../Mono.Android/PermissionGroupAttribute.Partial.cs | 6 ------ .../Mono.Android/PermissionTreeAttribute.Partial.cs | 6 ------ .../Mono.Android/SupportsGLTextureAttribute.Partial.cs | 6 ------ .../Mono.Android/UsesFeatureAttribute.Partial.cs | 6 ------ .../Mono.Android/UsesPermissionAttribute.Partial.cs | 6 ------ 8 files changed, 48 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/ApplicationAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/ApplicationAttribute.Partial.cs index 1c8f86c9ac9..2997d50006e 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/ApplicationAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/ApplicationAttribute.Partial.cs @@ -60,12 +60,6 @@ static partial void AddManualMapping () public static ApplicationAttribute FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { - // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of - // tests which check these situations. - if (provider == null) { - return null; - } - CustomAttribute attr = provider.GetCustomAttributes ("Android.App.ApplicationAttribute") .SingleOrDefault (); if (attr == null) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs index 3cedac868db..4a272d32110 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs @@ -18,12 +18,6 @@ partial class InstrumentationAttribute { public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { - // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of - // tests which check these situations. - if (provider == null) { - yield break; - } - foreach (CustomAttribute attr in provider.GetCustomAttributes ("Android.App.InstrumentationAttribute")) { InstrumentationAttribute self = new InstrumentationAttribute (); self.specified = mapping.Load (self, attr, cache); diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs index ebabfbc9562..1ca8b28ae39 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs @@ -21,12 +21,6 @@ partial class PermissionAttribute { public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { - // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of - // tests which check these situations. - if (provider == null) { - yield break; - } - var attrs = provider.GetCustomAttributes ("Android.App.PermissionAttribute"); foreach (var attr in attrs) { PermissionAttribute self = new PermissionAttribute (); diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs index 99cedace7d6..a1e00e4b68e 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs @@ -21,12 +21,6 @@ partial class PermissionGroupAttribute { public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { - // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of - // tests which check these situations. - if (provider == null) { - yield break; - } - var attrs = provider.GetCustomAttributes ("Android.App.PermissionGroupAttribute"); foreach (var attr in attrs) { PermissionGroupAttribute self = new PermissionGroupAttribute (); diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs index 79ca7af4999..0d388e440d3 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs @@ -21,12 +21,6 @@ partial class PermissionTreeAttribute { public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { - // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of - // tests which check these situations. - if (provider == null) { - yield break; - } - var attrs = provider.GetCustomAttributes ("Android.App.PermissionTreeAttribute"); foreach (var attr in attrs) { PermissionTreeAttribute self = new PermissionTreeAttribute (); diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs index dcf0dedcec6..b632f1e4717 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/SupportsGLTextureAttribute.Partial.cs @@ -31,12 +31,6 @@ internal XElement ToElement (string packageName, TypeDefinitionCache cache) public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { - // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of - // tests which check these situations. - if (provider == null) { - yield break; - } - var attrs = provider.GetCustomAttributes ("Android.App.SupportsGLTextureAttribute"); foreach (var attr in attrs) { if (attr.HasConstructorArguments && attr.ConstructorArguments.Count == 1) { diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs index 8ab6545d20d..86ecc5f825c 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesFeatureAttribute.Partial.cs @@ -37,12 +37,6 @@ internal XElement ToElement (string packageName, TypeDefinitionCache cache) public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { - // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of - // tests which check these situations. - if (provider == null) { - yield break; - } - var attrs = provider.GetCustomAttributes ("Android.App.UsesFeatureAttribute"); foreach (var attr in attrs) { diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesPermissionAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesPermissionAttribute.Partial.cs index 48648aceefc..7b957979b72 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesPermissionAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/UsesPermissionAttribute.Partial.cs @@ -16,12 +16,6 @@ partial class UsesPermissionAttribute { public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { - // `provider` might be null in situations when application configuration is broken, and it surfaces in a number of - // tests which check these situations. - if (provider == null) { - yield break; - } - var attrs = provider.GetCustomAttributes ("Android.App.UsesPermissionAttribute"); foreach (var attr in attrs) { UsesPermissionAttribute self; From 0f868e908d95206903c8f70a6345d280ad600d1a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 4 Nov 2024 19:38:39 +0100 Subject: [PATCH 45/60] Let's see what breaks --- .../targets/Microsoft.Android.Sdk.BuildOrder.targets | 1 + src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets index b3285c44966..17558b8efcd 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets @@ -62,6 +62,7 @@ properties that determine build ordering. <_PrepareBuildApkDependsOnTargets> _SetLatestTargetFrameworkVersion; _GetLibraryImports; + _RemoveRegisterAttribute; _ResolveAssemblies; _ResolveSatellitePaths; _CreatePackageWorkspace; diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index f88a86453b5..8f883501559 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2023,7 +2023,6 @@ because xbuild doesn't support framework reference assemblies. <_CompileToDalvikDependsOnTargets> _CompileJava; - _RemoveRegisterAttribute; _CreateApplicationSharedLibraries; _GetMonoPlatformJarPath; _GetLibraryImports; From 98514e53f47274d91ad4541fcd55380d02626a4d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 5 Nov 2024 09:32:05 +0100 Subject: [PATCH 46/60] Revert "Let's see what breaks" This reverts commit bc478708dd1afa809c4197a867ba018d0c6395e7. It broke 481 tests --- .../targets/Microsoft.Android.Sdk.BuildOrder.targets | 1 - src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets index 17558b8efcd..b3285c44966 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets @@ -62,7 +62,6 @@ properties that determine build ordering. <_PrepareBuildApkDependsOnTargets> _SetLatestTargetFrameworkVersion; _GetLibraryImports; - _RemoveRegisterAttribute; _ResolveAssemblies; _ResolveSatellitePaths; _CreatePackageWorkspace; diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 8f883501559..f88a86453b5 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2023,6 +2023,7 @@ because xbuild doesn't support framework reference assemblies. <_CompileToDalvikDependsOnTargets> _CompileJava; + _RemoveRegisterAttribute; _CreateApplicationSharedLibraries; _GetMonoPlatformJarPath; _GetLibraryImports; From 1d9ad154b3454bdcb4e6dc29652e89bb3c21f79f Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 6 Nov 2024 13:33:26 +0100 Subject: [PATCH 47/60] Restore [Require] --- .../Tasks/GeneratePackageManagerJava.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 538e796461c..2e6b8146758 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -63,7 +63,7 @@ public override bool RunTask () public bool EnablePreloadAssembliesDefault { get; set; } // This property should be required but it will require modifying `monodroid` first - //[Required] + [Required] public string AndroidBinUtilsDirectory { get; set; } public bool EnableMarshalMethods { get; set; } From 3e5ca7d97d8eeefeb8410926174b349089fcf209 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 6 Nov 2024 16:41:18 +0100 Subject: [PATCH 48/60] Remove comment, no longer valid --- .../Tasks/GeneratePackageManagerJava.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 2e6b8146758..d91669ec0ee 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -62,7 +62,6 @@ public override bool RunTask () [Required] public bool EnablePreloadAssembliesDefault { get; set; } - // This property should be required but it will require modifying `monodroid` first [Required] public string AndroidBinUtilsDirectory { get; set; } From 5fd11d3339838e65e0e8036e86c56a65c2d92455 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 27 May 2025 14:54:33 +0200 Subject: [PATCH 49/60] Fix after rebase --- .../InstrumentationAttribute.Partial.cs | 2 +- .../PermissionAttribute.Partial.cs | 2 +- .../PermissionGroupAttribute.Partial.cs | 2 +- .../PermissionTreeAttribute.Partial.cs | 2 +- .../Tasks/CompileNativeAssembly.cs | 7 + .../Tasks/GeneratePackageManagerJava.cs | 471 +----------------- .../Tasks/PrepareAbiItems.cs | 3 + .../BuildReleaseArm64SimpleDotNet.apkdesc | 31 +- .../BuildReleaseArm64XFormsDotNet.apkdesc | 78 +-- .../Utilities/AssemblyCompression.cs | 3 +- .../Utilities/AssemblyStoreGenerator.cs | 2 + .../Utilities/MonoAndroidHelper.cs | 34 ++ .../Xamarin.Android.Common.targets | 324 ++++++------ .../mono/monodroid/embedded-assemblies-zip.cc | 15 +- .../mono/monodroid/embedded-assemblies.cc | 47 +- .../mono/monodroid/embedded-assemblies.hh | 47 +- src/native/mono/monodroid/monodroid-glue.cc | 5 +- src/native/mono/runtime-base/monodroid-dl.hh | 4 +- src/native/mono/runtime-base/util.cc | 2 +- .../mono/xamarin-app-stub/xamarin-app.hh | 4 + 20 files changed, 365 insertions(+), 720 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs index 4a272d32110..98b5a0611fc 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/InstrumentationAttribute.Partial.cs @@ -14,7 +14,7 @@ namespace Android.App { partial class InstrumentationAttribute { - ICollection specified; + ICollection? specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs index 1ca8b28ae39..2f85d446562 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionAttribute.Partial.cs @@ -17,7 +17,7 @@ namespace Android.App { partial class PermissionAttribute { - ICollection specified; + ICollection? specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs index a1e00e4b68e..51d1a9f0d95 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionGroupAttribute.Partial.cs @@ -17,7 +17,7 @@ namespace Android.App { partial class PermissionGroupAttribute { - ICollection specified; + ICollection? specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { diff --git a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs index 0d388e440d3..2c88bfdaaa7 100644 --- a/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs +++ b/src/Xamarin.Android.Build.Tasks/Mono.Android/PermissionTreeAttribute.Partial.cs @@ -17,7 +17,7 @@ namespace Android.App { partial class PermissionTreeAttribute { - ICollection specified; + ICollection? specified; public static IEnumerable FromCustomAttributeProvider (ICustomAttributeProvider provider, TypeDefinitionCache cache) { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs index 4bfc03d9d26..8fed9a084b9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs @@ -12,6 +12,13 @@ public class CompileNativeAssembly : AsyncTask { public override string TaskPrefix => "CNA"; + sealed class Config + { + public string? AssemblerPath; + public string? AssemblerOptions; + public string? InputSource; + } + [Required] public ITaskItem[] Sources { get; set; } = []; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index d91669ec0ee..a82c4c0408f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -30,242 +30,10 @@ public override bool RunTask () pkgmgr.WriteLine ("public class MonoPackageManager_Resources {"); pkgmgr.WriteLine ("\tpublic static String[] Assemblies = new String[]{"); - public ITaskItem[] NativeLibraries { get; set; } - - public ITaskItem[] MonoComponents { get; set; } - - public ITaskItem[] SatelliteAssemblies { get; set; } - - public bool UseAssemblyStore { get; set; } - - [Required] - public string OutputDirectory { get; set; } - - [Required] - public string EnvironmentOutputDirectory { get; set; } - - [Required] - public string MainAssembly { get; set; } - - [Required] - public string TargetFrameworkVersion { get; set; } - - [Required] - public string Manifest { get; set; } - - [Required] - public string [] SupportedAbis { get; set; } - - [Required] - public string AndroidPackageName { get; set; } - - [Required] - public bool EnablePreloadAssembliesDefault { get; set; } - - [Required] - public string AndroidBinUtilsDirectory { get; set; } - - public bool EnableMarshalMethods { get; set; } - public string RuntimeConfigBinFilePath { get; set; } - public string BoundExceptionType { get; set; } - - public string PackageNamingPolicy { get; set; } - public string Debug { get; set; } - public ITaskItem[] Environments { get; set; } - public string AndroidAotMode { get; set; } - public bool AndroidAotEnableLazyLoad { get; set; } - public bool EnableLLVM { get; set; } - public string HttpClientHandlerType { get; set; } - public string TlsProvider { get; set; } - public string AndroidSequencePointsMode { get; set; } - public bool EnableSGenConcurrent { get; set; } - public string? CustomBundleConfigFile { get; set; } - - bool _Debug { - get { - return string.Equals (Debug, "true", StringComparison.OrdinalIgnoreCase); - } - } - - public override bool RunTask () - { - var doc = AndroidAppManifest.Load (Manifest, MonoAndroidHelper.SupportedVersions); - int minApiVersion = doc.MinSdkVersion == null ? 4 : (int) doc.MinSdkVersion; - // We need to include any special assemblies in the Assemblies list - var mainFileName = Path.GetFileName (MainAssembly); - - using (var pkgmgr = MemoryStreamPool.Shared.CreateStreamWriter ()) { - pkgmgr.WriteLine ("package mono;"); - - // Write all the user assemblies - pkgmgr.WriteLine ("public class MonoPackageManager_Resources {"); - pkgmgr.WriteLine ("\tpublic static String[] Assemblies = new String[]{"); - - pkgmgr.WriteLine ("\t\t/* We need to ensure that \"{0}\" comes first in this list. */", mainFileName); - pkgmgr.WriteLine ("\t\t\"" + mainFileName + "\","); - foreach (var assembly in ResolvedUserAssemblies) { - if (string.Compare (Path.GetFileName (assembly.ItemSpec), mainFileName, StringComparison.OrdinalIgnoreCase) == 0) - continue; - pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly.ItemSpec) + "\","); - } - foreach (var assembly in MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies (ResolvedAssemblies)) { - if (string.Compare (Path.GetFileName (assembly.ItemSpec), mainFileName, StringComparison.OrdinalIgnoreCase) == 0) - continue; - pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly.ItemSpec) + "\","); - } - - // Write the assembly dependencies - pkgmgr.WriteLine ("\t};"); - pkgmgr.WriteLine ("\tpublic static String[] Dependencies = new String[]{"); - - //foreach (var assembly in assemblies.Except (args.Assemblies)) { - // if (args.SharedRuntime && !Toolbox.IsInSharedRuntime (assembly)) - // pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly) + "\","); - //} - - pkgmgr.WriteLine ("\t};"); - - pkgmgr.WriteLine ("}"); - pkgmgr.Flush (); - - // Only copy to the real location if the contents actually changed - var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "MonoPackageManager_Resources.java")); - - Files.CopyIfStreamChanged (pkgmgr.BaseStream, dest); - } - - AddEnvironment (); - - return !Log.HasLoggedErrors; - } - - static internal AndroidTargetArch GetAndroidTargetArchForAbi (string abi) => MonoAndroidHelper.AbiToTargetArch (abi); - - static readonly string[] defaultLogLevel = {"MONO_LOG_LEVEL", "info"}; - static readonly string[] defaultMonoDebug = {"MONO_DEBUG", "gen-compact-seq-points"}; - static readonly string[] defaultHttpMessageHandler = {"XA_HTTP_CLIENT_HANDLER_TYPE", "System.Net.Http.HttpClientHandler, System.Net.Http"}; - static readonly string[] defaultTlsProvider = {"XA_TLS_PROVIDER", "btls"}; - - void AddEnvironment () - { - bool usesMonoAOT = false; - var environmentVariables = new Dictionary (StringComparer.Ordinal); - var systemProperties = new Dictionary (StringComparer.Ordinal); - - if (!Enum.TryParse (PackageNamingPolicy, out PackageNamingPolicy pnp)) { - pnp = PackageNamingPolicyEnum.LowercaseCrc64; - } - - AotMode aotMode = AotMode.None; - if (!string.IsNullOrEmpty (AndroidAotMode) && Aot.GetAndroidAotMode (AndroidAotMode, out aotMode) && aotMode != AotMode.None) { - usesMonoAOT = true; - } - - SequencePointsMode sequencePointsMode; - if (!Aot.TryGetSequencePointsMode (AndroidSequencePointsMode, out sequencePointsMode)) - sequencePointsMode = SequencePointsMode.None; - - // Even though environment files were potentially parsed in GenerateJavaStubs, we need to do it here again because we might have additional environment - // files (generated by us) which weren't present by the time GeneratJavaStubs ran. - var environmentParser = new EnvironmentFilesParser { - BrokenExceptionTransitions = false, - UsesAssemblyPreload = EnablePreloadAssembliesDefault, - }; - environmentParser.Parse (Environments, sequencePointsMode, Log); - - foreach (string line in environmentParser.EnvironmentVariableLines) { - AddEnvironmentVariableLine (line); - } - - if (_Debug && !environmentParser.HaveLogLevel) { - AddEnvironmentVariable (defaultLogLevel[0], defaultLogLevel[1]); - } - - if (sequencePointsMode != SequencePointsMode.None && !environmentParser.HaveMonoDebug) { - AddEnvironmentVariable (defaultMonoDebug[0], defaultMonoDebug[1]); - } - - if (!environmentParser.HaveHttpMessageHandler) { - if (HttpClientHandlerType == null) - AddEnvironmentVariable (defaultHttpMessageHandler[0], defaultHttpMessageHandler[1]); - else - AddEnvironmentVariable ("XA_HTTP_CLIENT_HANDLER_TYPE", HttpClientHandlerType.Trim ()); - } - - if (!environmentParser.HaveMonoGCParams) { - if (EnableSGenConcurrent) - AddEnvironmentVariable ("MONO_GC_PARAMS", "major=marksweep-conc"); - else - AddEnvironmentVariable ("MONO_GC_PARAMS", "major=marksweep"); - } - - global::Android.Runtime.BoundExceptionType boundExceptionType; - if (String.IsNullOrEmpty (BoundExceptionType) || String.Compare (BoundExceptionType, "System", StringComparison.OrdinalIgnoreCase) == 0) { - boundExceptionType = global::Android.Runtime.BoundExceptionType.System; - } else if (String.Compare (BoundExceptionType, "Java", StringComparison.OrdinalIgnoreCase) == 0) { - boundExceptionType = global::Android.Runtime.BoundExceptionType.Java; - } else { - throw new InvalidOperationException ($"Unsupported BoundExceptionType value '{BoundExceptionType}'"); - } - - int assemblyNameWidth = 0; - Encoding assemblyNameEncoding = Encoding.UTF8; - - Action updateNameWidth = (ITaskItem assembly) => { - if (UseAssemblyStore) { - return; - } - - string assemblyName = Path.GetFileName (assembly.ItemSpec); - int nameBytes = assemblyNameEncoding.GetBytes (assemblyName).Length; - if (nameBytes > assemblyNameWidth) { - assemblyNameWidth = nameBytes; - } - }; - - int assemblyCount = 0; - bool enableMarshalMethods = EnableMarshalMethods; - HashSet archAssemblyNames = null; - HashSet uniqueAssemblyNames = new HashSet (StringComparer.OrdinalIgnoreCase); - Action updateAssemblyCount = (ITaskItem assembly) => { - string? culture = MonoAndroidHelper.GetAssemblyCulture (assembly); - string fileName = Path.GetFileName (assembly.ItemSpec); - string assemblyName; - - if (String.IsNullOrEmpty (culture)) { - assemblyName = fileName; - } else { - assemblyName = $"{culture}/{fileName}"; - } - - if (!uniqueAssemblyNames.Contains (assemblyName)) { - uniqueAssemblyNames.Add (assemblyName); - } - - string abi = MonoAndroidHelper.GetItemAbi (assembly); - archAssemblyNames ??= new HashSet (StringComparer.OrdinalIgnoreCase); - - if (!archAssemblyNames.Contains (assemblyName)) { - assemblyCount++; - archAssemblyNames.Add (assemblyName); - } - }; - - if (SatelliteAssemblies != null) { - foreach (ITaskItem assembly in SatelliteAssemblies) { - updateNameWidth (assembly); - updateAssemblyCount (assembly); - } - } - - int android_runtime_jnienv_class_token = -1; - int jnienv_initialize_method_token = -1; - int jnienv_registerjninatives_method_token = -1; - foreach (var assembly in ResolvedAssemblies) { - updateNameWidth (assembly); - updateAssemblyCount (assembly); - - if (android_runtime_jnienv_class_token != -1) { + pkgmgr.WriteLine ("\t\t/* We need to ensure that \"{0}\" comes first in this list. */", mainFileName); + pkgmgr.WriteLine ("\t\t\"" + mainFileName + "\","); + foreach (var assembly in ResolvedUserAssemblies) { + if (string.Compare (Path.GetFileName (assembly.ItemSpec), mainFileName, StringComparison.OrdinalIgnoreCase) == 0) continue; pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly.ItemSpec) + "\","); } @@ -279,238 +47,17 @@ void AddEnvironment () // pkgmgr.WriteLine ("\t\t\"" + Path.GetFileName (assembly) + "\","); //} - var uniqueNativeLibraries = new List (); - - // Number of DSOs that will be packaged, it may be different to the number of items in the above - // `uniqueNativeLibraries` list. - uint packagedNativeLibrariesCount = 0; - var seenNativeLibraryNames = new HashSet (StringComparer.OrdinalIgnoreCase); - if (NativeLibraries != null) { - foreach (ITaskItem item in NativeLibraries) { - // We don't care about different ABIs here, just the file name - string name = Path.GetFileName (item.ItemSpec); - if (seenNativeLibraryNames.Contains (name)) { - continue; - } - - if (!ELFHelper.IsEmptyAOTLibrary (Log, item.ItemSpec)) { - packagedNativeLibrariesCount++; - } - - seenNativeLibraryNames.Add (name); - uniqueNativeLibraries.Add (item); - } + pkgmgr.WriteLine ("\t};"); - // libxamarin-app.so is not in NativeLibraries, but we must count it - if (!seenNativeLibraryNames.Contains ("libxamarin-app.so")) { - uniqueNativeLibraries.Add (new TaskItem ("libxamarin-app.so")); - packagedNativeLibrariesCount++; - } - } + pkgmgr.WriteLine ("}"); + pkgmgr.Flush (); // Only copy to the real location if the contents actually changed var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "MonoPackageManager_Resources.java")); - bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); - ELFEmbeddingHelper.EmbedBinary ( - Log, - SupportedAbis, - AndroidBinUtilsDirectory, - RuntimeConfigBinFilePath, - ELFEmbeddingHelper.KnownEmbedItems.RuntimeConfig, - EnvironmentOutputDirectory, - missingContentOK: !haveRuntimeConfigBlob - ); - - var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); - var appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { - UsesMonoAOT = usesMonoAOT, - UsesMonoLLVM = EnableLLVM, - UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, - MonoAOTMode = aotMode.ToString ().ToLowerInvariant (), - AotEnableLazyLoad = AndroidAotEnableLazyLoad, - AndroidPackageName = AndroidPackageName, - BrokenExceptionTransitions = environmentParser.BrokenExceptionTransitions, - PackageNamingPolicy = pnp, - BoundExceptionType = boundExceptionType, - JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.Template != null ? NativeCodeGenState.Template.JniAddNativeMethodRegistrationAttributePresent : false, - HaveRuntimeConfigBlob = haveRuntimeConfigBlob, - NumberOfAssembliesInApk = assemblyCount, - BundledAssemblyNameWidth = assemblyNameWidth, - MonoComponents = (MonoComponent)monoComponents, - NativeLibraries = uniqueNativeLibraries, - PackagedNativeLibrariesCount = packagedNativeLibrariesCount, - HaveAssemblyStore = UseAssemblyStore, - AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, - JNIEnvInitializeToken = jnienv_initialize_method_token, - JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, - JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, - JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, - MarshalMethodsEnabled = EnableMarshalMethods, - IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), - }; - LLVMIR.LlvmIrModule appConfigModule = appConfigAsmGen.Construct (); - - foreach (string abi in SupportedAbis) { - string targetAbi = abi.ToLowerInvariant (); - string environmentBaseAsmFilePath = Path.Combine (EnvironmentOutputDirectory, $"environment.{targetAbi}"); - string marshalMethodsBaseAsmFilePath = Path.Combine (EnvironmentOutputDirectory, $"marshal_methods.{targetAbi}"); - string environmentLlFilePath = $"{environmentBaseAsmFilePath}.ll"; - string marshalMethodsLlFilePath = $"{marshalMethodsBaseAsmFilePath}.ll"; - AndroidTargetArch targetArch = GetAndroidTargetArchForAbi (abi); - - using var appConfigWriter = MemoryStreamPool.Shared.CreateStreamWriter (); - try { - appConfigAsmGen.Generate (appConfigModule, targetArch, appConfigWriter, environmentLlFilePath); - } catch { - throw; - } finally { - appConfigWriter.Flush (); - Files.CopyIfStreamChanged (appConfigWriter.BaseStream, environmentLlFilePath); - } - - MarshalMethodsNativeAssemblyGenerator marshalMethodsAsmGen; - if (enableMarshalMethods) { - marshalMethodsAsmGen = new MarshalMethodsNativeAssemblyGenerator ( - Log, - assemblyCount, - uniqueAssemblyNames, - EnsureCodeGenState (targetArch) - ); - } else { - marshalMethodsAsmGen = new MarshalMethodsNativeAssemblyGenerator ( - Log, - targetArch, - assemblyCount, - uniqueAssemblyNames - ); - } - - LLVMIR.LlvmIrModule marshalMethodsModule = marshalMethodsAsmGen.Construct (); - using var marshalMethodsWriter = MemoryStreamPool.Shared.CreateStreamWriter (); - try { - marshalMethodsAsmGen.Generate (marshalMethodsModule, targetArch, marshalMethodsWriter, marshalMethodsLlFilePath); - } catch { - throw; - } finally { - marshalMethodsWriter.Flush (); - Files.CopyIfStreamChanged (marshalMethodsWriter.BaseStream, marshalMethodsLlFilePath); - } - } - - NativeCodeGenState EnsureCodeGenState (AndroidTargetArch targetArch) - { - if (nativeCodeGenStates == null || !nativeCodeGenStates.TryGetValue (targetArch, out NativeCodeGenState? state)) { - throw new InvalidOperationException ($"Internal error: missing native code generation state for architecture '{targetArch}'"); - } - - return state; - } - - void AddEnvironmentVariable (string name, string value) - { - if (Char.IsUpper(name [0]) || !Char.IsLetter(name [0])) - environmentVariables [ValidAssemblerString (name)] = ValidAssemblerString (value); - else - systemProperties [ValidAssemblerString (name)] = ValidAssemblerString (value); - } - - void AddEnvironmentVariableLine (string l) - { - string line = l?.Trim (); - if (String.IsNullOrEmpty (line) || line [0] == '#') - return; - - string[] nv = line.Split (new char[]{'='}, 2); - AddEnvironmentVariable (nv[0].Trim (), nv.Length < 2 ? String.Empty : nv[1].Trim ()); - } - - string ValidAssemblerString (string s) - { - return s.Replace ("\"", "\\\""); - } - } - - bool ShouldIgnoreSplitConfigs () - { - if (String.IsNullOrEmpty (CustomBundleConfigFile)) { - return false; - } - - return BundleConfigSplitConfigsChecker.ShouldIgnoreSplitConfigs (Log, CustomBundleConfigFile); - } - - void GetRequiredTokens (string assemblyFilePath, out int android_runtime_jnienv_class_token, out int jnienv_initialize_method_token, out int jnienv_registerjninatives_method_token) - { - if (!File.Exists (assemblyFilePath)) { - android_runtime_jnienv_class_token = -1; - jnienv_initialize_method_token = -1; - jnienv_registerjninatives_method_token = -1; - Log.LogDebugMessage ($"Assembly '{assemblyFilePath}' does not exist, unable to read required tokens from it"); - return; - } - - using var pe = new PEReader (File.OpenRead (assemblyFilePath)); - GetRequiredTokens (pe.GetMetadataReader (), out android_runtime_jnienv_class_token, out jnienv_initialize_method_token, out jnienv_registerjninatives_method_token); - - if (android_runtime_jnienv_class_token == -1 || jnienv_initialize_method_token == -1 || jnienv_registerjninatives_method_token == -1) { - throw new InvalidOperationException ($"Unable to find the required Android.Runtime.JNIEnvInit method tokens for {assemblyFilePath}"); - } + Files.CopyIfStreamChanged (pkgmgr.BaseStream, dest); } - void GetRequiredTokens (MetadataReader reader, out int android_runtime_jnienv_class_token, out int jnienv_initialize_method_token, out int jnienv_registerjninatives_method_token) - { - android_runtime_jnienv_class_token = -1; - jnienv_initialize_method_token = -1; - jnienv_registerjninatives_method_token = -1; - - TypeDefinition? typeDefinition = null; - - foreach (TypeDefinitionHandle typeHandle in reader.TypeDefinitions) { - TypeDefinition td = reader.GetTypeDefinition (typeHandle); - if (!TypeMatches (td)) { - continue; - } - - typeDefinition = td; - android_runtime_jnienv_class_token = MetadataTokens.GetToken (reader, typeHandle); - break; - } - - if (typeDefinition == null) { - return; - } - - foreach (MethodDefinitionHandle methodHandle in typeDefinition.Value.GetMethods ()) { - MethodDefinition md = reader.GetMethodDefinition (methodHandle); - string name = reader.GetString (md.Name); - - if (jnienv_initialize_method_token == -1 && String.Compare (name, "Initialize", StringComparison.Ordinal) == 0) { - jnienv_initialize_method_token = MetadataTokens.GetToken (reader, methodHandle); - } else if (jnienv_registerjninatives_method_token == -1 && String.Compare (name, "RegisterJniNatives", StringComparison.Ordinal) == 0) { - jnienv_registerjninatives_method_token = MetadataTokens.GetToken (reader, methodHandle); - } - - if (jnienv_initialize_method_token != -1 && jnienv_registerjninatives_method_token != -1) { - break; - } - } - - - bool TypeMatches (TypeDefinition td) - { - string ns = reader.GetString (td.Namespace); - if (String.Compare (ns, "Android.Runtime", StringComparison.Ordinal) != 0) { - return false; - } - - string name = reader.GetString (td.Name); - if (String.Compare (name, "JNIEnvInit", StringComparison.Ordinal) != 0) { - return false; - } - - return true; - } - } + return !Log.HasLoggedErrors; } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs index 41328dbf299..1f9148b4f9f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs @@ -22,6 +22,9 @@ public class PrepareAbiItems : AndroidTask [Output] public ITaskItem[]? AssemblySources { get; set; } + [Output] + public ITaskItem[]? AssemblyIncludes { get; set; } + public override bool RunTask () { var sources = new List (); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index 1a3c881a8eb..0d09c5250f4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc @@ -5,46 +5,49 @@ "Size": 3036 }, "classes.dex": { - "Size": 389676 + "Size": 22484 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 18296 + "Size": 18288 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { "Size": 86688 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 116080 + "Size": 117712 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22408 + "Size": 22384 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24376 + "Size": 24392 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { "Size": 25336 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 634344 + "Size": 628216 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 20040 + "Size": 20056 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21584 + "Size": 21480 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 20024 }, + "lib/arm64-v8a/libarc.bin.so": { + "Size": 18872 + }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { "Size": 36440 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 493384 + "Size": 1524752 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3196512 + "Size": 3101112 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71976 @@ -59,16 +62,16 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 15144 + "Size": 19536 }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 3167 + "Size": 3266 }, "META-INF/MANIFEST.MF": { - "Size": 3040 + "Size": 3139 }, "res/drawable-hdpi-v4/icon.png": { "Size": 2178 @@ -95,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 2865612 + "PackageSize": 3078677 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index e4bc24bb7e3..cf5b327b70c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -35,22 +35,22 @@ "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 94648 + "Size": 96104 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 522008 + "Size": 562336 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22408 + "Size": 23224 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { - "Size": 21432 + "Size": 21456 }, "lib/arm64-v8a/lib_netstandard.dll.so": { - "Size": 23072 + "Size": 23096 }, "lib/arm64-v8a/lib_System.Collections.Concurrent.dll.so": { - "Size": 29792 + "Size": 29896 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { "Size": 36304 @@ -59,43 +59,40 @@ "Size": 25776 }, "lib/arm64-v8a/lib_System.Collections.Specialized.dll.so": { - "Size": 23840 + "Size": 23856 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { "Size": 19608 }, "lib/arm64-v8a/lib_System.ComponentModel.Primitives.dll.so": { - "Size": 21304 + "Size": 21336 }, "lib/arm64-v8a/lib_System.ComponentModel.TypeConverter.dll.so": { - "Size": 42456 + "Size": 42440 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 24440 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 19448 - }, - "lib/arm64-v8a/lib_System.Diagnostics.DiagnosticSource.dll.so": { - "Size": 28440 + "Size": 19472 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { "Size": 24704 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 19848 + "Size": 19856 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 19424 + "Size": 19456 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { - "Size": 30040 + "Size": 30064 }, "lib/arm64-v8a/lib_System.Formats.Asn1.dll.so": { - "Size": 49928 + "Size": 50312 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 29472 + "Size": 29496 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { "Size": 33800 @@ -107,31 +104,31 @@ "Size": 40696 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 185800 + "Size": 185864 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { - "Size": 89488 + "Size": 85904 }, "lib/arm64-v8a/lib_System.Net.Primitives.dll.so": { - "Size": 41112 + "Size": 42184 }, "lib/arm64-v8a/lib_System.Net.Requests.dll.so": { - "Size": 21544 + "Size": 21568 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 27064 + "Size": 27088 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 956568 + "Size": 967200 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 216720 + "Size": 216496 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { - "Size": 62184 + "Size": 62728 }, "lib/arm64-v8a/lib_System.Private.Xml.dll.so": { - "Size": 237120 + "Size": 236920 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { "Size": 35600 @@ -140,7 +137,7 @@ "Size": 20264 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21584 + "Size": 21488 }, "lib/arm64-v8a/lib_System.Runtime.Numerics.dll.so": { "Size": 55784 @@ -149,22 +146,22 @@ "Size": 19376 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 20328 + "Size": 20352 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { "Size": 21472 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { - "Size": 80496 + "Size": 81288 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 183584 + "Size": 187056 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 19248 + "Size": 19272 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 19264 + "Size": 19288 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 22096 @@ -238,14 +235,17 @@ "lib/arm64-v8a/lib_Xamarin.Google.Android.Material.dll.so": { "Size": 84912 }, + "lib/arm64-v8a/libarc.bin.so": { + "Size": 18936 + }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { "Size": 36600 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 493384 + "Size": 1516584 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3196512 + "Size": 3110944 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71952 @@ -260,7 +260,7 @@ "Size": 165000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 122144 + "Size": 353048 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -416,7 +416,7 @@ "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 98562 + "Size": 98445 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -443,7 +443,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98435 + "Size": 98318 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2483,5 +2483,5 @@ "Size": 812848 } }, - "PackageSize": 10677500 + "PackageSize": 10955937 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyCompression.cs b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyCompression.cs index af7f97cdcd5..71da2ab254a 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyCompression.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyCompression.cs @@ -171,7 +171,8 @@ static string GetCompressedAssemblyOutputDirectory (ITaskItem assembly, string c string assemblyOutputDir; string subDirectory = assembly.GetMetadata ("DestinationSubDirectory"); string abi = MonoAndroidHelper.GetItemAbi (assembly); - if (!String.IsNullOrEmpty (subDirectory) && !(subDirectory.EndsWith ($"{abi}/", StringComparison.Ordinal) || subDirectory.EndsWith ($"{abi}\\", StringComparison.Ordinal))) { + + if (!string.IsNullOrEmpty (subDirectory) && !(subDirectory.EndsWith ($"{abi}/", StringComparison.Ordinal) || subDirectory.EndsWith ($"{abi}\\", StringComparison.Ordinal))) { assemblyOutputDir = Path.Combine (compressedOutputDir, abi, subDirectory); } else { assemblyOutputDir = Path.Combine (compressedOutputDir, abi); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.cs index f061412a125..35c355a5872 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.cs @@ -106,6 +106,7 @@ string Generate (string baseOutputDirectory, AndroidTargetArch arch, List (); var descriptors = new List (); ulong namesSize = 0; @@ -120,6 +121,7 @@ string Generate (string baseOutputDirectory, AndroidTargetArch arch, List AbiToTargetArch (GetItemAbi (asmItem)); + + + public static AndroidTargetArch GetRequiredValidArchitecture (ITaskItem item) + { + AndroidTargetArch ret = GetTargetArch (item); + + if (ret == AndroidTargetArch.None) { + throw new InvalidOperationException ($"Internal error: assembly '{item}' doesn't target any architecture."); + } + + return ret; + } #endif // MSBUILD static string GetToolsRootDirectoryRelativePath (string androidBinUtilsDirectory) @@ -779,5 +791,27 @@ static string GetBinUtilsToolPath (string androidBinUtilsDirectory, string toolN { return Path.Combine (androidBinUtilsDirectory, MonoAndroidHelper.GetExecutablePath (androidBinUtilsDirectory, toolName)); } + + public static AndroidRuntime ParseAndroidRuntime (string androidRuntime) + { + if (string.Equals (androidRuntime, "CoreCLR", StringComparison.OrdinalIgnoreCase)) + return AndroidRuntime.CoreCLR; + if (string.Equals (androidRuntime, "NativeAOT", StringComparison.OrdinalIgnoreCase)) + return AndroidRuntime.NativeAOT; + + // Default runtime is MonoVM + return AndroidRuntime.MonoVM; + } + + public static JavaPeerStyle ParseCodeGenerationTarget (string codeGenerationTarget) + { + if (Enum.TryParse (codeGenerationTarget, ignoreCase: true, out JavaPeerStyle style)) + return style; + + // Default is XAJavaInterop1 + return JavaPeerStyle.XAJavaInterop1; + } + + public static object GetProjectBuildSpecificTaskObjectKey (object key, string workingDirectory, string intermediateOutputPath) => (key, workingDirectory, intermediateOutputPath); } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index f88a86453b5..26cac5ff469 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -313,6 +313,8 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidFastDeployEnvironmentFiles Condition=" '$(_AndroidFastDeployEnvironmentFiles)' == '' ">False <_AndroidCompressedAssembliesDir>$(IntermediateOutputPath)android\lz4 + <_AndroidUseCLR Condition=" '$(_AndroidRuntime)' == 'CoreCLR' ">True + <_AndroidUseCLR Condition=" '$(_AndroidRuntime)' != 'CoreCLR' ">False @@ -361,8 +363,12 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' ">False <_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' ">$(AndroidEnableMarshalMethods) + <_AndroidEmbedAssemblyStoreInRuntime Condition=" '$(AndroidUseAssemblyStore)' == 'True' And '$(EmbedAssembliesIntoApk)' == 'true' And '$(_AndroidEmbedAssemblyStoreInRuntime)' == '' ">True <_AndroidEmbedAssemblyStoreInRuntime Condition="'$(_AndroidEmbedAssemblyStoreInRuntime)' == '' ">False + + <_AndroidUseManagedMarshalMethodsLookup Condition=" '$(_AndroidUseManagedMarshalMethodsLookup)' == '' and '$(_AndroidUseMarshalMethods)' == 'True' and '$(_AndroidRuntime)' != 'MonoVM' ">True + <_AndroidUseManagedMarshalMethodsLookup Condition=" '$(_AndroidUseManagedMarshalMethodsLookup)' == '' ">False @@ -1878,35 +1884,50 @@ because xbuild doesn't support framework reference assemblies. + MainAssembly="$(TargetPath)" + OutputDirectory="$(_AndroidIntermediateJavaSourceDirectory)mono" + ResolvedUserAssemblies="@(_ResolvedUserAssemblies)"> + + + + + + + + @@ -2314,52 +2335,8 @@ because xbuild doesn't support framework reference assemblies. also need to have the args added to Xamarin.Android.Common.Debugging.targets in monodroid. --> - - - - - - + RuntimePackLibraryDirectories="@(_RuntimePackLibraryDirectory)"> + + + + + + + + + + + - - - - - - - - + <_ApkOutputPath>$(ApkFileIntermediate) + + + + <_NativeLibraries Include="@(_AndroidNativeLibraryForFastDev)" /> + <_DalvikClasses Include="@(_DexFileForFastDev)" /> + + + + <_ApkOutputPath>$(_BaseZipIntermediate) + <_BundleNativeLibraries>$(_BundleResultNativeLibraries) + + + + <_NativeLibraries Include="@(AndroidNativeLibrary)" /> + <_DalvikClasses Include="@(_DexFile)" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + const& buf, dynamic_local_string &entry_name, ZipEntryLoadState &state) noexcept { entry_name.clear (); @@ -142,7 +142,7 @@ EmbeddedAssemblies::store_individual_assembly_data (dynamic_local_string const& buf, uint32_t num_entries, [[maybe_unused]] monodroid_should_register should_register, ZipEntryLoadState &state) noexcept { // TODO: do away with all the string manipulation here. Replace it with generating xxhash for the entry name @@ -256,7 +256,7 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string verify_assembly_store_and_set_info (payload_start, entry_name.get ()); } -force_inline void +[[gnu::always_inline]] void EmbeddedAssemblies::zip_load_assembly_store_entries (std::span const& buf, uint32_t num_entries, ZipEntryLoadState &state) noexcept { if (all_required_zip_entries_found ()) { @@ -272,6 +272,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::span const& b log_debug (LOG_ASSEMBLY, "Looking for assembly store ('%s') and DSOs in APK", assembly_store_file_path.data ()); } + log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ()); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; @@ -345,12 +346,12 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus if (retval < 0) [[unlikely]] { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Failed to seek to central directory position in APK: %s. retval=%d errno=%d, File=%s", + std::format ( + "Failed to seek to central directory position in APK: {}. retval={} errno={}, File={}", std::strerror (errno), retval, errno, - apk_name + optional_string (apk_name) ) ); } @@ -653,7 +654,7 @@ EmbeddedAssemblies::zip_read_field (T const& buf, size_t index, size_t count, dy } bool -EmbeddedAssemblies::zip_read_entry_info (std::span const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state) +EmbeddedAssemblies::zip_read_entry_info (std::span const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state) noexcept { constexpr size_t CD_COMPRESSION_METHOD_OFFSET = 10uz; constexpr size_t CD_UNCOMPRESSED_SIZE_OFFSET = 24uz; diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 261ee52e230..443540226a1 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -910,6 +910,51 @@ EmbeddedAssemblies::typemap_managed_to_java (MonoReflectionType *reflection_type return ret; } +EmbeddedAssemblies::md_mmap_info +EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, const char* filename) +{ + md_mmap_info file_info; + md_mmap_info mmap_info; + + size_t pageSize = static_cast(Util::monodroid_getpagesize ()); + size_t offsetFromPage = offset % pageSize; + size_t offsetPage = offset - offsetFromPage; + size_t offsetSize = size + offsetFromPage; + + mmap_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast(offsetPage)); + + if (mmap_info.area == MAP_FAILED) { + Helpers::abort_application ( + LOG_ASSEMBLY, + std::format ( + "Could not mmap APK fd {}: {}; File={}", + fd, + strerror (errno), + optional_string (filename) + ) + ); + } + + mmap_info.size = offsetSize; + file_info.area = pointer_add (mmap_info.area, offsetFromPage); + file_info.size = size; + + log_info ( + LOG_ASSEMBLY, + " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", + mmap_info.area, + pointer_add (mmap_info.area, mmap_info.size), + mmap_info.size, + file_info.area, + pointer_add (file_info.area, file_info.size), + file_info.size, + fd, + optional_string (filename) + ); + + return file_info; +} + void EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodroid_should_register should_register) noexcept { @@ -1431,6 +1476,6 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r ); #endif - log_debug (LOG_ASSEMBLY, "Found %zu assemblies", assembly_count); + log_debug (LOG_ASSEMBLY, "Found {} assemblies on the filesystem", assembly_count); return assembly_count; } diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 9b937c35c2a..2087773b5c9 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -27,7 +27,7 @@ #include #include "cppcompat.hh" #include "shared-constants.hh" -#include "xxhash.hh" +#include #include "util.hh" #include @@ -305,12 +305,12 @@ namespace xamarin::android::internal { static void get_assembly_data (XamarinAndroidBundledAssembly const& e, uint8_t*& assembly_data, uint32_t& assembly_data_size) noexcept; static void get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, uint8_t*& assembly_data, uint32_t& assembly_data_size) noexcept; - void zip_load_entries (int fd, const char *apk_name, monodroid_should_register should_register); - void zip_load_individual_assembly_entries (std::span const& buf, uint32_t num_entries, monodroid_should_register should_register, ZipEntryLoadState &state) noexcept; - void zip_load_assembly_store_entries (std::span const& buf, uint32_t num_entries, ZipEntryLoadState &state) noexcept; - bool zip_load_entry_common (size_t entry_index, std::span const& buf, dynamic_local_string &entry_name, ZipEntryLoadState &state) noexcept; - bool zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries); - bool zip_adjust_data_offset (int fd, ZipEntryLoadState &state); + static void zip_load_entries (int fd, const char *apk_name, monodroid_should_register should_register); + static void zip_load_individual_assembly_entries (std::span const& buf, uint32_t num_entries, monodroid_should_register should_register, ZipEntryLoadState &state) noexcept; + static void zip_load_assembly_store_entries (std::span const& buf, uint32_t num_entries, ZipEntryLoadState &state) noexcept; + static bool zip_load_entry_common (size_t entry_index, std::span const& buf, dynamic_local_string &entry_name, ZipEntryLoadState &state) noexcept; + static bool zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries); + static bool zip_adjust_data_offset (int fd, ZipEntryLoadState &state); template static bool zip_extract_cd_info (std::array const& buf, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; @@ -330,7 +330,7 @@ namespace xamarin::android::internal { template static bool zip_read_field (T const& buf, size_t index, size_t count, dynamic_local_string& characters) noexcept; - bool zip_read_entry_info (std::span const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state); + static bool zip_read_entry_info (std::span const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state); [[gnu::always_inline]] static std::tuple get_wrapper_dso_payload_pointer_and_size (md_mmap_info const& map_info, const char *file_name) noexcept @@ -412,20 +412,20 @@ namespace xamarin::android::internal { static const TypeMapModuleEntry* binary_search (uint32_t key, const TypeMapModuleEntry *arr, uint32_t n) noexcept; #endif template - void set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; - void set_assembly_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; - void set_debug_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; + static void set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; + static void set_assembly_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; + static void set_debug_entry_data (XamarinAndroidBundledAssembly &entry, ZipEntryLoadState const& state, dynamic_local_string const& entry_name) noexcept; - void verify_assembly_store_and_set_info (void *data_start, const char *name) noexcept; + static void verify_assembly_store_and_set_info (void *data_start, const char *name) noexcept; - void load_embedded_assembly_store () noexcept + static void load_embedded_assembly_store () noexcept { verify_assembly_store_and_set_info (embedded_assembly_store, "embedded"); } - void map_assembly_store (dynamic_local_string const& entry_name, ZipEntryLoadState &state) noexcept; - const AssemblyStoreIndexEntry* find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept; - void store_individual_assembly_data (dynamic_local_string const& entry_name, ZipEntryLoadState const& state, monodroid_should_register should_register) noexcept; + static void map_assembly_store (dynamic_local_string const& entry_name, ZipEntryLoadState &state) noexcept; + static const AssemblyStoreIndexEntry* find_assembly_store_entry (hash_t hash, const AssemblyStoreIndexEntry *entries, size_t entry_count) noexcept; + static void store_individual_assembly_data (dynamic_local_string const& entry_name, ZipEntryLoadState const& state, monodroid_should_register should_register) noexcept; constexpr static size_t get_mangled_name_max_size_overhead () { @@ -503,14 +503,13 @@ namespace xamarin::android::internal { size_t type_map_count; #endif // DEBUG static inline const char *assemblies_prefix_override = nullptr; - - md_mmap_info runtime_config_blob_mmap{}; - void *runtime_config_data = nullptr; - size_t runtime_config_data_size = 0uz; - bool runtime_config_blob_found = embedded_runtime_config_size > 0u; - uint32_t number_of_mapped_assembly_stores = 0u; - uint32_t number_of_zip_dso_entries = 0u; - bool need_to_scan_more_apks = true; + static inline md_mmap_info runtime_config_blob_mmap{}; + static inline void *runtime_config_data = nullptr; + static inline size_t runtime_config_data_size = 0uz; + static inline bool runtime_config_blob_found = embedded_runtime_config_size > 0u; + static inline uint32_t number_of_mapped_assembly_stores = 0u; + static inline uint32_t number_of_zip_dso_entries = 0u; + static inline bool need_to_scan_more_apks = true; static inline AssemblyStoreIndexEntry *assembly_store_hashes = nullptr; static inline xamarin::android::mutex assembly_decompress_mutex {}; diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index df82db42457..954661663a2 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -729,7 +729,6 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks gather_bundled_assemblies (runtimeApks, &user_assemblies_count, have_split_apks); if (embedded_runtime_config_size > 0) { - size_t blob_time_index; if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::RuntimeConfigBlob); } @@ -737,6 +736,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks runtime_config_args.kind = 1; runtime_config_args.runtimeconfig.data.data = reinterpret_cast(embedded_runtime_config); runtime_config_args.runtimeconfig.data.data_len = static_cast(embedded_runtime_config_size); + monovm_runtimeconfig_initialize (&runtime_config_args, cleanup_runtime_config, nullptr); if (FastTiming::enabled ()) [[unlikely]] { @@ -1157,8 +1157,9 @@ MonodroidRuntime::set_profile_options () noexcept .append (OUTPUT_ARG) .append (output_path.get (), output_path.length ()); } + if (Util::create_directory (AndroidSystem::override_dirs[0], 0777, 000) < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '%s'. %s", AndroidSystem::override_dirs[0], std::strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", optional_string (AndroidSystem::override_dirs[0]), std::strerror (errno)); } log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", optional_string (value.get ())); diff --git a/src/native/mono/runtime-base/monodroid-dl.hh b/src/native/mono/runtime-base/monodroid-dl.hh index 4b5fbe1be0f..93cb8b70b48 100644 --- a/src/native/mono/runtime-base/monodroid-dl.hh +++ b/src/native/mono/runtime-base/monodroid-dl.hh @@ -48,11 +48,11 @@ namespace xamarin::android::internal size_t arr_size; if constexpr (WhichCache == CacheKind::AOT) { - log_debug (LOG_ASSEMBLY, "Looking for hash 0x%zx in AOT cache", hash); + log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in AOT cache", hash); arr = aot_dso_cache; arr_size = application_config.number_of_aot_cache_entries; } else if constexpr (WhichCache == CacheKind::DSO) { - log_debug (LOG_ASSEMBLY, "Looking for hash 0x%zx in DSO cache", hash); + log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); arr = dso_cache; arr_size = application_config.number_of_dso_cache_entries; } diff --git a/src/native/mono/runtime-base/util.cc b/src/native/mono/runtime-base/util.cc index b017af23220..a5159f1f066 100644 --- a/src/native/mono/runtime-base/util.cc +++ b/src/native/mono/runtime-base/util.cc @@ -149,7 +149,7 @@ Util::create_public_directory (const char *dir) { int ret = create_directory (dir, 0777, 0); if (ret < 0) { - log_warn (LOG_DEFAULT, "Failed to create public directory '%s'. %s", dir, std::strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); } } diff --git a/src/native/mono/xamarin-app-stub/xamarin-app.hh b/src/native/mono/xamarin-app-stub/xamarin-app.hh index 3e89c184057..860d59a263e 100644 --- a/src/native/mono/xamarin-app-stub/xamarin-app.hh +++ b/src/native/mono/xamarin-app-stub/xamarin-app.hh @@ -399,4 +399,8 @@ MONO_API MONO_API_EXPORT uint8_t embedded_runtime_config[]; MONO_API MONO_API_EXPORT size_t embedded_assembly_store_size; MONO_API MONO_API_EXPORT uint8_t embedded_assembly_store[]; + +using get_function_pointer_fn = void(*)(uint32_t mono_image_index, uint32_t class_index, uint32_t method_token, void*& target_ptr); +MONO_API MONO_API_EXPORT void xamarin_app_init (JNIEnv *env, get_function_pointer_fn fn) noexcept; + #endif // __XAMARIN_ANDROID_TYPEMAP_H From 5a344664f6a8d509e2261215d5cbf7d043c84df9 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 27 May 2025 17:09:48 +0200 Subject: [PATCH 50/60] Post-rebase fixes --- .../mono/monodroid/embedded-assemblies.cc | 45 ------------------- .../mono/monodroid/embedded-assemblies.hh | 24 ++++++---- 2 files changed, 16 insertions(+), 53 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index 443540226a1..73bb98e4751 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -910,51 +910,6 @@ EmbeddedAssemblies::typemap_managed_to_java (MonoReflectionType *reflection_type return ret; } -EmbeddedAssemblies::md_mmap_info -EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, const char* filename) -{ - md_mmap_info file_info; - md_mmap_info mmap_info; - - size_t pageSize = static_cast(Util::monodroid_getpagesize ()); - size_t offsetFromPage = offset % pageSize; - size_t offsetPage = offset - offsetFromPage; - size_t offsetSize = size + offsetFromPage; - - mmap_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast(offsetPage)); - - if (mmap_info.area == MAP_FAILED) { - Helpers::abort_application ( - LOG_ASSEMBLY, - std::format ( - "Could not mmap APK fd {}: {}; File={}", - fd, - strerror (errno), - optional_string (filename) - ) - ); - } - - mmap_info.size = offsetSize; - file_info.area = pointer_add (mmap_info.area, offsetFromPage); - file_info.size = size; - - log_info ( - LOG_ASSEMBLY, - " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", - mmap_info.area, - pointer_add (mmap_info.area, mmap_info.size), - mmap_info.size, - file_info.area, - pointer_add (file_info.area, file_info.size), - file_info.size, - fd, - optional_string (filename) - ); - - return file_info; -} - void EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodroid_should_register should_register) noexcept { diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 2087773b5c9..807437c62cb 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -194,7 +194,7 @@ namespace xamarin::android::internal { runtime_config_data_size = 0uz; } - bool keep_scanning () const noexcept + static bool keep_scanning () noexcept { return need_to_scan_more_apks; } @@ -280,9 +280,17 @@ namespace xamarin::android::internal { adjusted_info.area = (void*)((const char*)original_info.area + offsetFromPage); adjusted_info.size = size; - log_info (LOG_ASSEMBLY, "mmap_start: %08p mmap_end: %08p mmap_len: % 12u file_start: %08p file_end: %08p file_len: % 12u; apk descriptor: %d; file: %s", - original_info.area, reinterpret_cast (original_info.area) + original_info.size, original_info.size, - adjusted_info.area, reinterpret_cast (adjusted_info.area) + adjusted_info.size, adjusted_info.size, fd, filename + log_info ( + LOG_ASSEMBLY, + " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", + original_info.area, + pointer_add (original_info.area, original_info.size), + original_info.size, + adjusted_info.area, + pointer_add (adjusted_info.area, adjusted_info.size), + adjusted_info.size, + fd, + optional_string (filename) ); return adjusted_info; @@ -305,12 +313,12 @@ namespace xamarin::android::internal { static void get_assembly_data (XamarinAndroidBundledAssembly const& e, uint8_t*& assembly_data, uint32_t& assembly_data_size) noexcept; static void get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData const& e, uint8_t*& assembly_data, uint32_t& assembly_data_size) noexcept; - static void zip_load_entries (int fd, const char *apk_name, monodroid_should_register should_register); + static void zip_load_entries (int fd, const char *apk_name, monodroid_should_register should_register) noexcept; static void zip_load_individual_assembly_entries (std::span const& buf, uint32_t num_entries, monodroid_should_register should_register, ZipEntryLoadState &state) noexcept; static void zip_load_assembly_store_entries (std::span const& buf, uint32_t num_entries, ZipEntryLoadState &state) noexcept; static bool zip_load_entry_common (size_t entry_index, std::span const& buf, dynamic_local_string &entry_name, ZipEntryLoadState &state) noexcept; - static bool zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries); - static bool zip_adjust_data_offset (int fd, ZipEntryLoadState &state); + static bool zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; + static bool zip_adjust_data_offset (int fd, ZipEntryLoadState &state) noexcept; template static bool zip_extract_cd_info (std::array const& buf, uint32_t& cd_offset, uint32_t& cd_size, uint16_t& cd_entries) noexcept; @@ -330,7 +338,7 @@ namespace xamarin::android::internal { template static bool zip_read_field (T const& buf, size_t index, size_t count, dynamic_local_string& characters) noexcept; - static bool zip_read_entry_info (std::span const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state); + static bool zip_read_entry_info (std::span const& buf, dynamic_local_string& file_name, ZipEntryLoadState &state) noexcept; [[gnu::always_inline]] static std::tuple get_wrapper_dso_payload_pointer_and_size (md_mmap_info const& map_info, const char *file_name) noexcept From c73b422d4f5beaa0908cb6d90ddf177d2c2aed5d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 28 May 2025 12:38:21 +0200 Subject: [PATCH 51/60] A handful of NRT fixes + reuse shared code --- .../Tasks/CreateAssemblyStore.cs | 39 +---------- .../Tasks/CreateEmbeddedAssemblyStore.cs | 67 +++++-------------- .../Utilities/AssemblyPackagingHelper.cs | 48 ++++++++++--- .../Utilities/ELFEmbeddingHelper.cs | 8 ++- 4 files changed, 64 insertions(+), 98 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateAssemblyStore.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateAssemblyStore.cs index eb0a3724295..55ef0d7252d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CreateAssemblyStore.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateAssemblyStore.cs @@ -36,49 +36,16 @@ public class CreateAssemblyStore : AndroidTask public override bool RunTask () { // Get all the user and framework assemblies we may need to package - var assemblies = ResolvedFrameworkAssemblies.Concat (ResolvedUserAssemblies).Where (asm => !(ShouldSkipAssembly (asm))).ToArray (); + var assemblies = ResolvedFrameworkAssemblies.Concat (ResolvedUserAssemblies).Where (asm => !(AssemblyPackagingHelper.ShouldSkipAssembly (Log, asm))); if (!UseAssemblyStore) { - AssembliesToAddToArchive = assemblies; + AssembliesToAddToArchive = assemblies.ToArray (); return !Log.HasLoggedErrors; } - var store_builder = new AssemblyStoreBuilder (Log); - var per_arch_assemblies = MonoAndroidHelper.GetPerArchAssemblies (assemblies, SupportedAbis, true); - - foreach (var kvp in per_arch_assemblies) { - Log.LogDebugMessage ($"Adding assemblies for architecture '{kvp.Key}'"); - - foreach (var assembly in kvp.Value.Values) { - var sourcePath = assembly.GetMetadataOrDefault ("CompressedAssembly", assembly.ItemSpec); - store_builder.AddAssembly (sourcePath, assembly, includeDebugSymbols: IncludeDebugSymbols); - - Log.LogDebugMessage ($"Added '{sourcePath}' to assembly store."); - } - } - - var assembly_store_paths = store_builder.Generate (AppSharedLibrariesDir); - - if (assembly_store_paths.Count == 0) { - throw new InvalidOperationException ("Assembly store generator did not generate any stores"); - } - - if (assembly_store_paths.Count != SupportedAbis.Length) { - throw new InvalidOperationException ("Internal error: assembly store did not generate store for each supported ABI"); - } - + var assembly_store_paths = AssemblyPackagingHelper.CreateAssemblyStore (Log, assemblies, AppSharedLibrariesDir, SupportedAbis, IncludeDebugSymbols); AssembliesToAddToArchive = assembly_store_paths.Select (kvp => new TaskItem (kvp.Value, new Dictionary { { "Abi", MonoAndroidHelper.ArchToAbi (kvp.Key) } })).ToArray (); return !Log.HasLoggedErrors; } - - bool ShouldSkipAssembly (ITaskItem asm) - { - var should_skip = asm.GetMetadataOrDefault ("AndroidSkipAddToPackage", false); - - if (should_skip) - Log.LogDebugMessage ($"Skipping {asm.ItemSpec} due to 'AndroidSkipAddToPackage' == 'true' "); - - return should_skip; - } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs index d6eda689509..c75474ef7aa 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateEmbeddedAssemblyStore.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; @@ -14,37 +15,28 @@ public class CreateEmbeddedAssemblyStore : AndroidTask public override string TaskPrefix => "CEAS"; [Required] - public string AndroidBinUtilsDirectory { get; set; } + public string AndroidBinUtilsDirectory { get; set; } = ""; [Required] - public string AppSharedLibrariesDir { get; set; } + public string AppSharedLibrariesDir { get; set; } = ""; [Required] - public string AssemblySourcesDir { get; set; } - - [Required] - public string CompressedAssembliesDir { get; set; } + public string AssemblySourcesDir { get; set; } = ""; [Required] public bool AssemblyStoreEmbeddedInRuntime { get; set; } [Required] - public bool Debug { get; set; } - - [Required] - public bool EnableCompression { get; set; } + public bool IncludeDebugSymbols { get; set; } [Required] - public string ProjectFullPath { get; set; } + public ITaskItem[] ResolvedUserAssemblies { get; set; } = []; [Required] - public ITaskItem[] ResolvedUserAssemblies { get; set; } + public ITaskItem[] ResolvedFrameworkAssemblies { get; set; } = []; [Required] - public ITaskItem[] ResolvedFrameworkAssemblies { get; set; } - - [Required] - public string [] SupportedAbis { get; set; } + public string [] SupportedAbis { get; set; } = []; public override bool RunTask () { @@ -70,27 +62,14 @@ public override bool RunTask () bool EmbedAssemblyStore () { - bool compress = !Debug && EnableCompression; - IDictionary>? compressedAssembliesInfo = null; - - if (compress) { - string key = CompressedAssemblyInfo.GetKey (ProjectFullPath); - Log.LogDebugMessage ($"[{TaskPrefix}] Retrieving assembly compression info with key '{key}'"); - compressedAssembliesInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal>> (key, RegisteredTaskObjectLifetime.Build); - if (compressedAssembliesInfo == null) { - throw new InvalidOperationException ($"Assembly compression info not found for key '{key}'. Compression will not be performed."); - } - } - - var storeBuilder = new AssemblyStoreBuilder (Log); + var assemblies = ResolvedFrameworkAssemblies.Concat (ResolvedUserAssemblies).Where (asm => !(AssemblyPackagingHelper.ShouldSkipAssembly (Log, asm))); + var assemblyStorePaths = AssemblyPackagingHelper.CreateAssemblyStore ( + Log, assemblies, + Path.Combine (AppSharedLibrariesDir, "embedded"), + SupportedAbis, + IncludeDebugSymbols + ); - // Add user assemblies - AssemblyPackagingHelper.AddAssembliesFromCollection (Log, SupportedAbis, ResolvedUserAssemblies, DoAddAssembliesFromArchCollection); - - // Add framework assemblies - AssemblyPackagingHelper.AddAssembliesFromCollection (Log, SupportedAbis, ResolvedFrameworkAssemblies, DoAddAssembliesFromArchCollection); - - Dictionary assemblyStorePaths = storeBuilder.Generate (Path.Combine (AppSharedLibrariesDir, "embedded")); foreach (var kvp in assemblyStorePaths) { string abi = MonoAndroidHelper.ArchToAbi (kvp.Key); string inputFile = kvp.Value; @@ -107,21 +86,5 @@ bool EmbedAssemblyStore () } return !Log.HasLoggedErrors; - - void DoAddAssembliesFromArchCollection (TaskLoggingHelper log, AndroidTargetArch arch, ITaskItem assembly) - { - string sourcePath = CompressAssembly (assembly); - storeBuilder.AddAssembly (sourcePath, assembly, includeDebugSymbols: Debug); - return; - } - - string CompressAssembly (ITaskItem assembly) - { - if (!compress) { - return assembly.ItemSpec; - } - - return AssemblyCompression.Compress (Log, assembly, compressedAssembliesInfo, CompressedAssembliesDir); - } } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs index 1599a8e581e..572af36521b 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPackagingHelper.cs @@ -10,20 +10,52 @@ namespace Xamarin.Android.Tasks; static class AssemblyPackagingHelper { + public static bool ShouldSkipAssembly (TaskLoggingHelper log, ITaskItem asm) + { + var should_skip = asm.GetMetadataOrDefault ("AndroidSkipAddToPackage", false); + + if (should_skip) { + log.LogDebugMessage ($"Skipping {asm.ItemSpec} due to 'AndroidSkipAddToPackage' == 'true' "); + } + + return should_skip; + } + + public static Dictionary CreateAssemblyStore (TaskLoggingHelper log, IEnumerable assemblies, string outputDir, string[] supportedAbis, bool includeDebugSymbols) + { + var storeBuilder = new AssemblyStoreBuilder (log); + var per_arch_assemblies = MonoAndroidHelper.GetPerArchAssemblies (assemblies, supportedAbis, true); + + foreach (var kvp in per_arch_assemblies) { + log.LogDebugMessage ($"Adding assemblies for architecture '{kvp.Key}'"); + + foreach (var assembly in kvp.Value.Values) { + var sourcePath = assembly.GetMetadataOrDefault ("CompressedAssembly", assembly.ItemSpec); + storeBuilder.AddAssembly (sourcePath, assembly, includeDebugSymbols: includeDebugSymbols); + + log.LogDebugMessage ($"Added '{sourcePath}' to assembly store."); + } + } + + Dictionary assemblyStorePaths = storeBuilder.Generate (outputDir); + if (assemblyStorePaths.Count == 0) { + throw new InvalidOperationException ("Assembly store generator did not generate any stores"); + } + + if (assemblyStorePaths.Count != supportedAbis.Length) { + throw new InvalidOperationException ("Internal error: assembly store did not generate store for each supported ABI"); + } + + return assemblyStorePaths; + } + public static void AddAssembliesFromCollection (TaskLoggingHelper Log, ICollection SupportedAbis, ICollection assemblies, Action doAddAssembly) { Dictionary> perArchAssemblies = MonoAndroidHelper.GetPerArchAssemblies ( assemblies, SupportedAbis, validate: true, - shouldSkip: (ITaskItem asm) => { - if (bool.TryParse (asm.GetMetadata ("AndroidSkipAddToPackage"), out bool value) && value) { - Log.LogDebugMessage ($"Skipping {asm.ItemSpec} due to 'AndroidSkipAddToPackage' == 'true' "); - return true; - } - - return false; - } + shouldSkip: (ITaskItem asm) => ShouldSkipAssembly (Log, asm) ); foreach (var kvp in perArchAssemblies) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs index 52704354a63..7481164a829 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFEmbeddingHelper.cs @@ -108,13 +108,17 @@ static void DoEmbed ( var fi = new FileInfo (inputFile); if (fi.Exists) { inputFileSize = fi.Length; - sanitizedInputFilePath = inputFile.Replace ("\\", "\\\\"); + sanitizedInputFilePath = inputFile!.Replace ("\\", "\\\\"); } else if (!missingContentOK) { throw new InvalidOperationException ($"Internal error: input file '{inputFile}' does not exist"); } } - string asmSourceFile = NativeAssemblerItemsHelper.GetSourcePath (log, item.NativeAssemblerMode, outputDirectory, arch); + string? asmSourceFile = NativeAssemblerItemsHelper.GetSourcePath (log, item.NativeAssemblerMode, outputDirectory, arch); + if (String.IsNullOrEmpty (asmSourceFile)) { + log.LogError ("Unable to embed a binary file in native assembly, no assembly source path given."); + return; + } Directory.CreateDirectory (Path.GetDirectoryName (asmSourceFile)); using var fs = File.Open (asmSourceFile, FileMode.Create, FileAccess.Write, FileShare.Read); From 0af08487a493853b0968da94f06d6090cd9e53db Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 28 May 2025 13:00:00 +0200 Subject: [PATCH 52/60] MSBuild updates + cleanup --- .../Microsoft.Android.Sdk.AssemblyStores.targets | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets index 22fa9dca278..07360e4deec 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets @@ -21,15 +21,17 @@ DependsOnTargets="_PrepareCreateEmbeddedAssemblyStoreOutputItems" Inputs="@(_CreateEmbeddedAssemblyStoreAssembly)" Outputs="@(_EmbeddedAssemblyStoreSourceFiles)"> + + <_EmbedAssemblyStoreInRuntime Condition=" '$(_AndroidUseAssemblyStore)' And '$(_AndroidEmbedAssemblyStoreInRuntime)' ">true + <_EmbedAssemblyStoreInRuntime Condition=" '$(_EmbedAssemblyStoreInRuntime)' != 'true' ">false + + From f1b5ccc89bba9e09a75175be455c5e28fddd4162 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 28 May 2025 13:52:25 +0200 Subject: [PATCH 53/60] Embed runtime config for MonoVM --- ...crosoft.Android.Sdk.AssemblyStores.targets | 5 -- .../CollectRuntimeConfigFilesForArchive.cs | 59 ------------------- .../GenerateNativeApplicationConfigSources.cs | 15 ++++- .../Xamarin.Android.Common.targets | 25 +++----- 4 files changed, 23 insertions(+), 81 deletions(-) delete mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/CollectRuntimeConfigFilesForArchive.cs diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets index 07360e4deec..1547a850e7a 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyStores.targets @@ -21,11 +21,6 @@ DependsOnTargets="_PrepareCreateEmbeddedAssemblyStoreOutputItems" Inputs="@(_CreateEmbeddedAssemblyStoreAssembly)" Outputs="@(_EmbeddedAssemblyStoreSourceFiles)"> - - <_EmbedAssemblyStoreInRuntime Condition=" '$(_AndroidUseAssemblyStore)' And '$(_AndroidEmbedAssemblyStoreInRuntime)' ">true - <_EmbedAssemblyStoreInRuntime Condition=" '$(_EmbedAssemblyStoreInRuntime)' != 'true' ">false - - -/// Collects rc.bin to be added to the final archive. -/// -public class CollectRuntimeConfigFilesForArchive : AndroidTask -{ - const string ArchiveLibPath = "lib"; - - public override string TaskPrefix => "CRF"; - - [Required] - public string AndroidBinUtilsDirectory { get; set; } = ""; - - [Required] - public ITaskItem[] RuntimePackLibraryDirectories { get; set; } = Array.Empty (); - - [Required] - public string IntermediateOutputPath { get; set; } = ""; - - public string RuntimeConfigBinFilePath { get; set; } = ""; - - [Required] - public string [] SupportedAbis { get; set; } = []; - - [Output] - public ITaskItem [] FilesToAddToArchive { get; set; } = []; - - public override bool RunTask () - { - var files = new PackageFileListBuilder (); - var dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, RuntimePackLibraryDirectories, IntermediateOutputPath); - - // We will place rc.bin in the `lib` directory next to the blob, to make startup slightly faster, as we will find the config file right after we encounter - // our assembly store. Not only that, but also we'll be able to skip scanning the `base.apk` archive when split configs are enabled (which they are in 99% - // of cases these days, since AAB enforces that split). `base.apk` contains only ABI-agnostic file, while one of the split config files contains only - // ABI-specific data+code. - if (!string.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath)) { - foreach (var abi in SupportedAbis) { - // Prefix it with `a` because bundletool sorts entries alphabetically, and this will place it right next to `assemblies.*.blob.so`, which is what we - // like since we can finish scanning the zip central directory earlier at startup. - var inArchivePath = MakeArchiveLibPath (abi, "libarc.bin.so"); - var wrappedSourcePath = DSOWrapperGenerator.WrapIt (Log, dsoWrapperConfig, MonoAndroidHelper.AbiToTargetArch (abi), RuntimeConfigBinFilePath, Path.GetFileName (inArchivePath)); - files.AddItem (wrappedSourcePath, inArchivePath); - } - } - - FilesToAddToArchive = files.ToArray (); - - return !Log.HasLoggedErrors; - } - - static string MakeArchiveLibPath (string abi, string fileName) => MonoAndroidHelper.MakeZipArchivePath (ArchiveLibPath, abi, fileName); -} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs index c905016a9c3..09fe12b1c24 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs @@ -50,6 +50,9 @@ public class GenerateNativeApplicationConfigSources : AndroidTask [Required] public bool TargetsCLR { get; set; } + [Required] + public string AndroidBinUtilsDirectory { get; set; } = ""; + public bool EnableMarshalMethods { get; set; } public bool EnableManagedMarshalMethodsLookup { get; set; } public string? RuntimeConfigBinFilePath { get; set; } @@ -248,7 +251,6 @@ public override bool RunTask () } } - bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); LLVMIR.LlvmIrComposer appConfigAsmGen; @@ -272,6 +274,17 @@ public override bool RunTask () IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), }; } else { + bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); + ELFEmbeddingHelper.EmbedBinary ( + Log, + SupportedAbis, + AndroidBinUtilsDirectory, + RuntimeConfigBinFilePath, + ELFEmbeddingHelper.KnownEmbedItems.RuntimeConfig, + EnvironmentOutputDirectory, + missingContentOK: !haveRuntimeConfigBlob + ); + appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { UsesMonoAOT = usesMonoAOT, UsesMonoLLVM = EnableLLVM, diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 26cac5ff469..47c6ac9a62d 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -344,6 +344,9 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. false true <_AndroidUseAssemblyStore>$(AndroidUseAssemblyStore) + + <_EmbedAssemblyStoreInRuntime Condition=" '$(_AndroidUseAssemblyStore)' == 'True' And '$(_AndroidEmbedAssemblyStoreInRuntime)' == 'True' ">true + <_EmbedAssemblyStoreInRuntime Condition=" '$(_EmbedAssemblyStoreInRuntime)' != 'true' ">false + ProjectRuntimeConfigFilePath="$(ProjectRuntimeConfigFilePath)" + AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)"> - + @@ -2336,7 +2340,7 @@ because xbuild doesn't support framework reference assemblies. in monodroid. --> - - - - - Date: Wed, 28 May 2025 14:14:27 +0200 Subject: [PATCH 54/60] Fix DSO counts --- .../GenerateNativeApplicationConfigSources.cs | 17 +++++++++++++++++ ...plicationConfigNativeAssemblyGeneratorCLR.cs | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs index 09fe12b1c24..e4dda651f24 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs @@ -8,6 +8,7 @@ using System.Reflection.PortableExecutable; using System.Text; using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; using Java.Interop.Tools.TypeNameMappings; using Xamarin.Android.Tools; @@ -237,6 +238,10 @@ public override bool RunTask () } var uniqueNativeLibraries = new List (); + + // Number of DSOs that will be packaged, it may be different to the number of items in the above + // `uniqueNativeLibraries` list. + uint packagedNativeLibrariesCount = 0; var seenNativeLibraryNames = new HashSet (StringComparer.OrdinalIgnoreCase); if (NativeLibraries != null) { foreach (ITaskItem item in NativeLibraries) { @@ -246,9 +251,19 @@ public override bool RunTask () continue; } + if (!ELFHelper.IsEmptyAOTLibrary (Log, item.ItemSpec)) { + packagedNativeLibrariesCount++; + } + seenNativeLibraryNames.Add (name); uniqueNativeLibraries.Add (item); } + + // libxamarin-app.so is not in NativeLibraries, but we must count it + if (!seenNativeLibraryNames.Contains ("libxamarin-app.so")) { + uniqueNativeLibraries.Add (new TaskItem ("libxamarin-app.so")); + packagedNativeLibrariesCount++; + } } var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); @@ -264,6 +279,7 @@ public override bool RunTask () NumberOfAssembliesInApk = assemblyCount, BundledAssemblyNameWidth = assemblyNameWidth, NativeLibraries = uniqueNativeLibraries, + PackagedNativeLibrariesCount = packagedNativeLibrariesCount, AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, JNIEnvInitializeToken = jnienv_initialize_method_token, JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, @@ -301,6 +317,7 @@ public override bool RunTask () BundledAssemblyNameWidth = assemblyNameWidth, MonoComponents = (MonoComponent)monoComponents, NativeLibraries = uniqueNativeLibraries, + PackagedNativeLibrariesCount = packagedNativeLibrariesCount, HaveAssemblyStore = UseAssemblyStore, AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, JNIEnvInitializeToken = jnienv_initialize_method_token, diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs index ca8bc0d5f55..88bd177000c 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -211,6 +211,7 @@ sealed class XamarinAndroidBundledAssembly public bool MarshalMethodsEnabled { get; set; } public bool ManagedMarshalMethodsLookupEnabled { get; set; } public bool IgnoreSplitConfigs { get; set; } + public uint PackagedNativeLibrariesCount { get; set; } public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary environmentVariables, IDictionary systemProperties, IDictionary? runtimeProperties, TaskLoggingHelper log) @@ -266,7 +267,7 @@ protected override void Construct (LlvmIrModule module) environment_variable_count = (uint)(environmentVariables == null ? 0 : environmentVariables.Count * 2), system_property_count = (uint)(systemProperties == null ? 0 : systemProperties.Count * 2), number_of_assemblies_in_apk = (uint)NumberOfAssembliesInApk, - number_of_shared_libraries = (uint)NativeLibraries.Count, + number_of_shared_libraries = PackagedNativeLibrariesCount, bundled_assembly_name_width = (uint)BundledAssemblyNameWidth, number_of_dso_cache_entries = (uint)dsoCache.Count, number_of_aot_cache_entries = (uint)aotDsoCache.Count, From 642167072c0acf85541b05b3c7fd4c2cd2c42888 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 28 May 2025 15:38:11 +0200 Subject: [PATCH 55/60] Fix MonoVM diagnostic messages --- .../mono/monodroid/embedded-assemblies-zip.cc | 21 +++++++++---------- .../mono/monodroid/embedded-assemblies.hh | 1 + 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 42cf610ab3e..30e01a25fbd 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -184,9 +184,9 @@ EmbeddedAssemblies::verify_assembly_store_and_set_info (void *data_start, const if (header->magic != ASSEMBLY_STORE_MAGIC) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Assembly store '%s' is not a valid .NET for Android assembly store file", - name + std::format ( + "Assembly store '{}' is not a valid .NET for Android assembly store file", + optional_string (name) ) ); } @@ -194,9 +194,9 @@ EmbeddedAssemblies::verify_assembly_store_and_set_info (void *data_start, const if (header->version != ASSEMBLY_STORE_FORMAT_VERSION) { Helpers::abort_application ( LOG_ASSEMBLY, - Util::monodroid_strdup_printf ( - "Assembly store '%s' uses format version 0x%x, instead of the expected 0x%x", - name, + std::format ( + "Assembly store '{}' uses format version 0x{:x}, instead of the expected 0x{:x}", + optional_string (name), header->version, ASSEMBLY_STORE_FORMAT_VERSION ) @@ -269,10 +269,9 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::span const& b load_embedded_assembly_store (); log_debug (LOG_ASSEMBLY, "Looking for DSOs in APK"); } else { - log_debug (LOG_ASSEMBLY, "Looking for assembly store ('%s') and DSOs in APK", assembly_store_file_path.data ()); + log_debug (LOG_ASSEMBLY, "Looking for assembly store ('{}') and DSOs in APK", assembly_store_file_path); } - log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ()); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; @@ -338,9 +337,9 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus ); } - log_debug (LOG_ASSEMBLY, "Central directory offset: %u", cd_offset); - log_debug (LOG_ASSEMBLY, "Central directory size: %u", cd_size); - log_debug (LOG_ASSEMBLY, "Central directory entries: %u", cd_entries); + log_debug (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); + log_debug (LOG_ASSEMBLY, "Central directory size: {}", cd_size); + log_debug (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); if (retval < 0) [[unlikely]] { diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 807437c62cb..da3a86328f6 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -428,6 +428,7 @@ namespace xamarin::android::internal { static void load_embedded_assembly_store () noexcept { + log_debug (LOG_ASSEMBLY, "Loading embedded assembly store"); verify_assembly_store_and_set_info (embedded_assembly_store, "embedded"); } From 3714379916f9f13db58a4475516eb10233bb20e1 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 29 May 2025 11:42:05 +0200 Subject: [PATCH 56/60] Add support for CoreCLR --- .../Xamarin.Android.Common.targets | 7 ++- src/native/clr/host/assembly-store.cc | 56 ++++++++++--------- src/native/clr/host/host.cc | 12 ++++ src/native/clr/include/host/assembly-store.hh | 3 + src/native/clr/include/host/host.hh | 5 +- src/native/clr/include/xamarin-app.hh | 8 ++- .../xamarin-app-stub/application_dso_stub.cc | 3 + 7 files changed, 63 insertions(+), 31 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 47c6ac9a62d..35f410656c9 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -344,9 +344,6 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. false true <_AndroidUseAssemblyStore>$(AndroidUseAssemblyStore) - - <_EmbedAssemblyStoreInRuntime Condition=" '$(_AndroidUseAssemblyStore)' == 'True' And '$(_AndroidEmbedAssemblyStoreInRuntime)' == 'True' ">true - <_EmbedAssemblyStoreInRuntime Condition=" '$(_EmbedAssemblyStoreInRuntime)' != 'true' ">false - - - - Date: Thu, 29 May 2025 15:30:42 +0200 Subject: [PATCH 58/60] Remove unnecessary app config field --- .../GenerateNativeApplicationConfigSources.cs | 1 - .../Utilities/EnvironmentHelper.cs | 48 ++++++++----------- .../Utilities/ApplicationConfig.cs | 1 - ...pplicationConfigNativeAssemblyGenerator.cs | 2 - .../xamarin-app-stub/application_dso_stub.cc | 1 - .../mono/xamarin-app-stub/xamarin-app.hh | 1 - 6 files changed, 21 insertions(+), 33 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs index e4dda651f24..acb45995b70 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateNativeApplicationConfigSources.cs @@ -312,7 +312,6 @@ public override bool RunTask () PackageNamingPolicy = pnp, BoundExceptionType = boundExceptionType, JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, - HaveRuntimeConfigBlob = haveRuntimeConfigBlob, NumberOfAssembliesInApk = assemblyCount, BundledAssemblyNameWidth = assemblyNameWidth, MonoComponents = (MonoComponent)monoComponents, diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs index 7a86601ce43..7aff38ae573 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs @@ -45,7 +45,6 @@ public sealed class ApplicationConfig public bool uses_assembly_preload; public bool broken_exception_transitions; public bool jni_add_native_method_registration_attribute_present; - public bool have_runtime_config_blob; public bool have_assemblies_blob; public bool marshal_methods_enabled; public bool ignore_split_configs; @@ -68,7 +67,7 @@ public sealed class ApplicationConfig public bool managed_marshal_methods_lookup_enabled; } - const uint ApplicationConfigFieldCount = 27; + const uint ApplicationConfigFieldCount = 26; const string ApplicationConfigSymbolName = "application_config"; const string AppEnvironmentVariablesSymbolName = "app_environment_variables"; @@ -237,107 +236,102 @@ static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile) ret.jni_add_native_method_registration_attribute_present = ConvertFieldToBool ("jni_add_native_method_registration_attribute_present", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 6: // have_runtime_config_blob: bool / .byte - AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); - ret.have_runtime_config_blob = ConvertFieldToBool ("have_runtime_config_blob", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); - break; - - case 7: // have_assemblies_blob: bool / .byte + case 6: // have_assemblies_blob: bool / .byte AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); ret.have_assemblies_blob = ConvertFieldToBool ("have_assemblies_blob", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 8: // marshal_methods_enabled: bool / .byte + case 7: // marshal_methods_enabled: bool / .byte AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); ret.marshal_methods_enabled = ConvertFieldToBool ("marshal_methods_enabled", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 9: // ignore_split_configs: bool / .byte + case 8: // ignore_split_configs: bool / .byte AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); ret.ignore_split_configs = ConvertFieldToBool ("ignore_split_configs", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 10: // bound_stream_io_exception_type: byte / .byte + case 9: // bound_stream_io_exception_type: byte / .byte AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); ret.bound_stream_io_exception_type = ConvertFieldToByte ("bound_stream_io_exception_type", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 11: // package_naming_policy: uint32_t / .word | .long + case 10: // package_naming_policy: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.package_naming_policy = ConvertFieldToUInt32 ("package_naming_policy", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 12: // environment_variable_count: uint32_t / .word | .long + case 11: // environment_variable_count: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.environment_variable_count = ConvertFieldToUInt32 ("environment_variable_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 13: // system_property_count: uint32_t / .word | .long + case 12: // system_property_count: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.system_property_count = ConvertFieldToUInt32 ("system_property_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 14: // number_of_assemblies_in_apk: uint32_t / .word | .long + case 13: // number_of_assemblies_in_apk: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.number_of_assemblies_in_apk = ConvertFieldToUInt32 ("number_of_assemblies_in_apk", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 15: // bundled_assembly_name_width: uint32_t / .word | .long + case 14: // bundled_assembly_name_width: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.bundled_assembly_name_width = ConvertFieldToUInt32 ("bundled_assembly_name_width", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 16: // number_of_assembly_store_files: uint32_t / .word | .long + case 15: // number_of_assembly_store_files: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.number_of_assembly_store_files = ConvertFieldToUInt32 ("number_of_assembly_store_files", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 17: // number_of_dso_cache_entries: uint32_t / .word | .long + case 16: // number_of_dso_cache_entries: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.number_of_dso_cache_entries = ConvertFieldToUInt32 ("number_of_dso_cache_entries", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 18: // number_of_aot_cache_entries: uint32_t / .word | .long + case 17: // number_of_aot_cache_entries: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.number_of_aot_cache_entries = ConvertFieldToUInt32 ("number_of_aot_cache_entries", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 19: // android_runtime_jnienv_class_token: uint32_t / .word | .long + case 18: // android_runtime_jnienv_class_token: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.android_runtime_jnienv_class_token = ConvertFieldToUInt32 ("android_runtime_jnienv_class_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 20: // jnienv_initialize_method_token: uint32_t / .word | .long + case 19: // jnienv_initialize_method_token: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.jnienv_initialize_method_token = ConvertFieldToUInt32 ("jnienv_initialize_method_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 21: // jnienv_registerjninatives_method_token: uint32_t / .word | .long + case 20: // jnienv_registerjninatives_method_token: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.jnienv_registerjninatives_method_token = ConvertFieldToUInt32 ("jnienv_registerjninatives_method_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 22: // jni_remapping_replacement_type_count: uint32_t / .word | .long + case 21: // jni_remapping_replacement_type_count: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.jni_remapping_replacement_type_count = ConvertFieldToUInt32 ("jni_remapping_replacement_type_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 23: // jni_remapping_replacement_method_index_entry_count: uint32_t / .word | .long + case 22: // jni_remapping_replacement_method_index_entry_count: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.jni_remapping_replacement_method_index_entry_count = ConvertFieldToUInt32 ("jni_remapping_replacement_method_index_entry_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 24: // mono_components_mask: uint32_t / .word | .long + case 23: // mono_components_mask: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.mono_components_mask = ConvertFieldToUInt32 ("mono_components_mask", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 25: // android_package_name: string / [pointer type] + case 24: // android_package_name: string / [pointer type] Assert.IsTrue (expectedPointerTypes.Contains (field [0]), $"Unexpected pointer field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); pointers.Add (field [1].Trim ()); break; - case 26: // managed_marshal_methods_lookup_enabled: bool / .byte + case 25: // managed_marshal_methods_lookup_enabled: bool / .byte AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); ret.managed_marshal_methods_lookup_enabled = ConvertFieldToBool ("managed_marshal_methods_lookup_enabled", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs index 40ea29ee665..f9fcecb7e44 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs @@ -30,7 +30,6 @@ sealed class ApplicationConfig public bool uses_assembly_preload; public bool broken_exception_transitions; public bool jni_add_native_method_registration_attribute_present; - public bool have_runtime_config_blob; public bool have_assemblies_blob; public bool marshal_methods_enabled; public bool ignore_split_configs; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs index d374df67dbb..c45eb1fcaf6 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs @@ -182,7 +182,6 @@ sealed class XamarinAndroidBundledAssembly public bool BrokenExceptionTransitions { get; set; } public global::Android.Runtime.BoundExceptionType BoundExceptionType { get; set; } public bool JniAddNativeMethodRegistrationAttributePresent { get; set; } - public bool HaveRuntimeConfigBlob { get; set; } public bool HaveAssemblyStore { get; set; } public int NumberOfAssembliesInApk { get; set; } public int BundledAssemblyNameWidth { get; set; } // including the trailing NUL @@ -238,7 +237,6 @@ protected override void Construct (LlvmIrModule module) uses_assembly_preload = UsesAssemblyPreload, broken_exception_transitions = BrokenExceptionTransitions, jni_add_native_method_registration_attribute_present = JniAddNativeMethodRegistrationAttributePresent, - have_runtime_config_blob = HaveRuntimeConfigBlob, have_assemblies_blob = HaveAssemblyStore, marshal_methods_enabled = MarshalMethodsEnabled, managed_marshal_methods_lookup_enabled = ManagedMarshalMethodsLookupEnabled, diff --git a/src/native/mono/xamarin-app-stub/application_dso_stub.cc b/src/native/mono/xamarin-app-stub/application_dso_stub.cc index 49588a88e38..d60e11c82c9 100644 --- a/src/native/mono/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/mono/xamarin-app-stub/application_dso_stub.cc @@ -48,7 +48,6 @@ const ApplicationConfig application_config = { .uses_assembly_preload = false, .broken_exception_transitions = false, .jni_add_native_method_registration_attribute_present = false, - .have_runtime_config_blob = false, .have_assembly_store = false, .marshal_methods_enabled = false, .ignore_split_configs = false, diff --git a/src/native/mono/xamarin-app-stub/xamarin-app.hh b/src/native/mono/xamarin-app-stub/xamarin-app.hh index 860d59a263e..d8badede691 100644 --- a/src/native/mono/xamarin-app-stub/xamarin-app.hh +++ b/src/native/mono/xamarin-app-stub/xamarin-app.hh @@ -238,7 +238,6 @@ struct ApplicationConfig bool uses_assembly_preload; bool broken_exception_transitions; bool jni_add_native_method_registration_attribute_present; - bool have_runtime_config_blob; bool have_assembly_store; bool marshal_methods_enabled; bool ignore_split_configs; From ac649062915c28c4d2dfb617b14a76f3d3585a47 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 29 May 2025 16:43:17 +0200 Subject: [PATCH 59/60] Update apkdesc files --- .../BuildReleaseArm64SimpleDotNet.apkdesc | 43 ++++++------ .../BuildReleaseArm64XFormsDotNet.apkdesc | 69 +++++++++---------- 2 files changed, 53 insertions(+), 59 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index 0d09c5250f4..53233030a42 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc @@ -5,31 +5,31 @@ "Size": 3036 }, "classes.dex": { - "Size": 22484 + "Size": 22488 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { "Size": 18288 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 86688 + "Size": 87624 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 117712 + "Size": 120768 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 22384 + "Size": 23160 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24392 + "Size": 24408 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 25336 + "Size": 25344 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 628216 + "Size": 636760 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 20056 + "Size": 20096 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { "Size": 21480 @@ -37,41 +37,38 @@ "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 20024 }, - "lib/arm64-v8a/libarc.bin.so": { - "Size": 18872 - }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { - "Size": 36440 + "Size": 36616 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1524752 + "Size": 1525968 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3101112 + "Size": 3118632 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { - "Size": 71976 + "Size": 71952 }, "lib/arm64-v8a/libSystem.IO.Compression.Native.so": { - "Size": 758896 + "Size": 759304 }, "lib/arm64-v8a/libSystem.Native.so": { - "Size": 103520 + "Size": 104312 }, "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { - "Size": 165000 + "Size": 165240 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 19536 + "Size": 22384 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1221 + "Size": 1223 }, "META-INF/BNDLTOOL.SF": { - "Size": 3266 + "Size": 3167 }, "META-INF/MANIFEST.MF": { - "Size": 3139 + "Size": 3040 }, "res/drawable-hdpi-v4/icon.png": { "Size": 2178 @@ -98,5 +95,5 @@ "Size": 1904 } }, - "PackageSize": 3078677 + "PackageSize": 3099084 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index cf5b327b70c..c397f8e99d2 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -5,7 +5,7 @@ "Size": 6652 }, "classes.dex": { - "Size": 9179108 + "Size": 9173200 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -35,13 +35,13 @@ "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 96104 + "Size": 96320 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 562336 + "Size": 562416 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 23224 + "Size": 23200 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 21456 @@ -50,25 +50,25 @@ "Size": 23096 }, "lib/arm64-v8a/lib_System.Collections.Concurrent.dll.so": { - "Size": 29896 + "Size": 29904 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { "Size": 36304 }, "lib/arm64-v8a/lib_System.Collections.NonGeneric.dll.so": { - "Size": 25776 + "Size": 25784 }, "lib/arm64-v8a/lib_System.Collections.Specialized.dll.so": { "Size": 23856 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { - "Size": 19608 + "Size": 19600 }, "lib/arm64-v8a/lib_System.ComponentModel.Primitives.dll.so": { - "Size": 21336 + "Size": 21328 }, "lib/arm64-v8a/lib_System.ComponentModel.TypeConverter.dll.so": { - "Size": 42440 + "Size": 42432 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 24440 @@ -80,25 +80,25 @@ "Size": 24704 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 19856 + "Size": 19864 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 19456 + "Size": 19448 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { "Size": 30064 }, "lib/arm64-v8a/lib_System.Formats.Asn1.dll.so": { - "Size": 50312 + "Size": 50320 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 29496 + "Size": 29504 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { "Size": 33800 }, "lib/arm64-v8a/lib_System.IO.IsolatedStorage.dll.so": { - "Size": 28336 + "Size": 28328 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { "Size": 40696 @@ -107,7 +107,7 @@ "Size": 185864 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { - "Size": 85904 + "Size": 85856 }, "lib/arm64-v8a/lib_System.Net.Primitives.dll.so": { "Size": 42184 @@ -116,13 +116,13 @@ "Size": 21568 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 27088 + "Size": 27096 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 967200 + "Size": 968480 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 216496 + "Size": 216504 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { "Size": 62728 @@ -137,10 +137,10 @@ "Size": 20264 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21488 + "Size": 21480 }, "lib/arm64-v8a/lib_System.Runtime.Numerics.dll.so": { - "Size": 55784 + "Size": 55840 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { "Size": 19376 @@ -149,16 +149,16 @@ "Size": 20352 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 21472 + "Size": 21464 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { - "Size": 81288 + "Size": 81280 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 187056 + "Size": 187120 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 19272 + "Size": 19264 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { "Size": 19288 @@ -235,17 +235,14 @@ "lib/arm64-v8a/lib_Xamarin.Google.Android.Material.dll.so": { "Size": 84912 }, - "lib/arm64-v8a/libarc.bin.so": { - "Size": 18936 - }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { - "Size": 36600 + "Size": 36616 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1516584 + "Size": 1525968 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3110944 + "Size": 3118632 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71952 @@ -254,13 +251,13 @@ "Size": 759304 }, "lib/arm64-v8a/libSystem.Native.so": { - "Size": 103520 + "Size": 104312 }, "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { - "Size": 165000 + "Size": 165240 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 353048 + "Size": 357088 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -416,7 +413,7 @@ "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 98445 + "Size": 98346 }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 @@ -443,7 +440,7 @@ "Size": 5 }, "META-INF/MANIFEST.MF": { - "Size": 98318 + "Size": 98219 }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 @@ -2483,5 +2480,5 @@ "Size": 812848 } }, - "PackageSize": 10955937 + "PackageSize": 10959960 } \ No newline at end of file From 9b79c81ab29fee034d07cf027d4fbf14b5279675 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 30 May 2025 14:13:44 +0200 Subject: [PATCH 60/60] Add a couple of tests --- .../PackagingTest.cs | 41 +++++++++++++++++++ .../Tests/InstallAndRunTests.cs | 21 ++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs index 23cca31ecbe..5931e9843e5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs @@ -796,5 +796,46 @@ void CreateEmptyFile (string path) } } + [Test] + [TestCase (false)] + [TestCase (true)] + public void CheckEmbeddedAssemblyStorePackaging (bool useCLR) + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true + }; + + AndroidTargetArch[] supportedArches = new[] { + AndroidTargetArch.Arm64, + AndroidTargetArch.X86_64, + }; + + proj.SetRuntimeIdentifiers (supportedArches); + proj.SetProperty ("AndroidUseAssemblyStore", "true"); + proj.SetProperty ("_AndroidEmbedAssemblyStoreInRuntime", "true"); + proj.SetProperty ("UseMonoRuntime", useCLR ? "false" : "true"); + + using var b = CreateApkBuilder (); + Assert.IsTrue (b.Build (proj), "build should have succeeded."); + string apk = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath, $"{proj.PackageName}-Signed.apk"); + + var knownAssemblyStoreFiles = new HashSet (StringComparer.Ordinal); + foreach (AndroidTargetArch arch in supportedArches) { + string archName = MonoAndroidHelper.ArchToAbi (arch); + knownAssemblyStoreFiles.Add ($"lib/{archName}/libassemblies.{archName}.blob.so"); + } + + var foundAssemblyStoreFiles = new HashSet (StringComparer.Ordinal); + using var zip = ZipHelper.OpenZip (apk); + + foreach (var entry in zip) { + if (knownAssemblyStoreFiles.Contains (entry.FullName)) { + foundAssemblyStoreFiles.Add (entry.FullName); + } + } + + Assert.IsFalse (foundAssemblyStoreFiles.Count != 0, $"APK should not contain any of the files: {FoundFiles ()}"); + string FoundFiles () => String.Join (", ", foundAssemblyStoreFiles); + } } } diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index d179740e994..92593ce63c1 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -1380,5 +1380,26 @@ public void AppStartsWithManagedMarshalMethodsLookupEnabled () Path.Combine (Root, builder.ProjectDirectory, "logcat.log"), 30); Assert.IsTrue (didLaunch, "Activity should have started."); } + + [Test] + [TestCase (false)] + [TestCase (true)] + public void AppStartsWithEmbeddedAssemblyStore (bool useCLR) + { + var proj = new XamarinAndroidApplicationProject { IsRelease = true }; + proj.SetProperty ("_AndroidEmbedAssemblyStoreInRuntime", "true"); + proj.SetProperty ("UseMonoRuntime", useCLR ? "false" : "true"); + + using var builder = CreateApkBuilder (); + builder.Save (proj); + + var dotnet = new DotNetCLI (Path.Combine (Root, builder.ProjectDirectory, proj.ProjectFilePath)); + Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed"); + Assert.IsTrue (dotnet.Run (), "`dotnet run --no-build` should succeed"); + + bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity", + Path.Combine (Root, builder.ProjectDirectory, "logcat.log"), 30); + Assert.IsTrue (didLaunch, "Activity should have started."); + } } }