From 06ea40b567ac10b17cb4d024f08854c9cc31587f Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 20 Mar 2023 14:36:37 +0100 Subject: [PATCH 1/2] Fix native code generation when marshal methods are disabled Disabling marshal method generation turns off a lot of native code generation in the `MarshalMethodsNativeAssemblyGenerator` class, but the class is also responsible for outputting correctly sized cache area (an array of X pointers) to be used by the native runtime to cache pointers to `MonoImage` instances. Native runtime trusts the managed runtime to generate correct code and, thus, does not verify the size of generated array. This trust, unfortunately, was broken because with marshal methods disabled, the native code generator output cache array that was 0 entries in size, thus leading to segfault when attempting to run the application. Fix the issue and also parametrize one of the on-device tests to be built twice, with marshal methods explicitly disabled and explicitly enabled. --- .../Tasks/GeneratePackageManagerJava.cs | 2 +- .../Tests/Xamarin.ProjectTools/Android/KnownProperties.cs | 1 + .../Android/XamarinAndroidApplicationProject.cs | 6 ++++++ .../Utilities/MarshalMethodsNativeAssemblyGenerator.cs | 3 ++- tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | 3 ++- 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index ee869ddad32..623b20976de 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -413,7 +413,7 @@ void AddEnvironment () Log ); } else { - marshalMethodsAsmGen = new MarshalMethodsNativeAssemblyGenerator (uniqueAssemblyNames); + marshalMethodsAsmGen = new MarshalMethodsNativeAssemblyGenerator (assemblyCount, uniqueAssemblyNames); } marshalMethodsAsmGen.Init (); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownProperties.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownProperties.cs index d8b7b63fa51..7b846201c9a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownProperties.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownProperties.cs @@ -12,6 +12,7 @@ public static class KnownProperties public const string AndroidUseLatestPlatformSdk = "AndroidUseLatestPlatformSdk"; public const string AndroidUseAapt2 = "AndroidUseAapt2"; public const string AndroidCreatePackagePerAbi = "AndroidCreatePackagePerAbi"; + public const string AndroidEnableMarshalMethods = "AndroidEnableMarshalMethods"; public const string AndroidSupportedAbis = "AndroidSupportedAbis"; public const string RuntimeIdentifier = "RuntimeIdentifier"; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs index fde6e298fa1..552f8286300 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs @@ -23,6 +23,8 @@ public class XamarinAndroidApplicationProject : XamarinAndroidCommonProject static readonly string default_main_activity_cs, default_main_activity_fs; static readonly string default_android_manifest; + public bool? EnableMarshalMethods { get; set; } = null; + static XamarinAndroidApplicationProject () { var folder = Builder.UseDotNet ? "DotNet" : "Base"; @@ -41,6 +43,10 @@ public XamarinAndroidApplicationProject (string debugConfigurationName = "Debug" : base (debugConfigurationName, releaseConfigurationName) { if (Builder.UseDotNet) { + if (EnableMarshalMethods.HasValue) { + SetProperty (KnownProperties.AndroidEnableMarshalMethods, EnableMarshalMethods.Value ? "True" : "False"); + } + SetProperty (KnownProperties.OutputType, "Exe"); SetProperty (KnownProperties.Nullable, "enable"); SetProperty (KnownProperties.ImplicitUsings, "enable"); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsNativeAssemblyGenerator.cs index 50aec79c9ed..229ba0397d7 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsNativeAssemblyGenerator.cs @@ -204,8 +204,9 @@ sealed class MarshalMethodName /// /// Constructor to be used ONLY when marshal methods are DISABLED /// - public MarshalMethodsNativeAssemblyGenerator (ICollection uniqueAssemblyNames) + public MarshalMethodsNativeAssemblyGenerator (int numberOfAssembliesInApk, ICollection uniqueAssemblyNames) { + this.numberOfAssembliesInApk = numberOfAssembliesInApk; this.uniqueAssemblyNames = uniqueAssemblyNames ?? throw new ArgumentNullException (nameof (uniqueAssemblyNames)); generateEmptyCode = true; } diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index d1a3cd61d2a..fb0ec53e1ec 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -26,7 +26,7 @@ public void Teardown () } [Test] - public void NativeAssemblyCacheWithSatelliteAssemblies () + public void NativeAssemblyCacheWithSatelliteAssemblies ([Values (true, false)] bool enableMarshalMethods) { var path = Path.Combine ("temp", TestName); var lib = new XamarinAndroidLibraryProject { @@ -49,6 +49,7 @@ public void NativeAssemblyCacheWithSatelliteAssemblies () proj = new XamarinAndroidApplicationProject { IsRelease = true, + EnableMarshalMethods = enableMarshalMethods, }; proj.References.Add (new BuildItem.ProjectReference ($"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj", lib.ProjectName, lib.ProjectGuid)); proj.SetAndroidSupportedAbis ("armeabi-v7a", "arm64-v8a", "x86", "x86_64"); From 54a3f6e0bedc9f9b204a535aaf0f664e22285119 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 20 Mar 2023 15:40:12 +0100 Subject: [PATCH 2/2] Fix a snafu --- .../Android/XamarinAndroidApplicationProject.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs index 552f8286300..1feaf5e2d8e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs @@ -23,8 +23,6 @@ public class XamarinAndroidApplicationProject : XamarinAndroidCommonProject static readonly string default_main_activity_cs, default_main_activity_fs; static readonly string default_android_manifest; - public bool? EnableMarshalMethods { get; set; } = null; - static XamarinAndroidApplicationProject () { var folder = Builder.UseDotNet ? "DotNet" : "Base"; @@ -43,10 +41,6 @@ public XamarinAndroidApplicationProject (string debugConfigurationName = "Debug" : base (debugConfigurationName, releaseConfigurationName) { if (Builder.UseDotNet) { - if (EnableMarshalMethods.HasValue) { - SetProperty (KnownProperties.AndroidEnableMarshalMethods, EnableMarshalMethods.Value ? "True" : "False"); - } - SetProperty (KnownProperties.OutputType, "Exe"); SetProperty (KnownProperties.Nullable, "enable"); SetProperty (KnownProperties.ImplicitUsings, "enable"); @@ -172,6 +166,11 @@ public AndroidLinkMode AndroidLinkModeRelease { set { SetProperty (ReleaseProperties, KnownProperties.AndroidLinkMode, value.ToString ()); } } + public bool EnableMarshalMethods { + get { return string.Equals (GetProperty (KnownProperties.AndroidEnableMarshalMethods), "True", StringComparison.OrdinalIgnoreCase); } + set { SetProperty (KnownProperties.AndroidEnableMarshalMethods, value.ToString ()); } + } + public string AndroidManifest { get; set; } public string LayoutMain { get; set; } public string MainActivity { get; set; }