From d2ade6990bb06548cf8c723c34b0691f313d46d7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 23 Mar 2023 21:53:45 +0100 Subject: [PATCH] [Xamarin.Android.Build.Tasks] Fix native code generation when marshal methods are disabled (#7899) Disabling marshal method generation via `$(AndroidEnableMarshalMethods)`=False turns off a lot of native code generation in the `MarshalMethodsNativeAssemblyGenerator` class, but the class is also responsible for outputting a correctly sized cache area (an array of *X* pointers) to be used by the native runtime to cache pointers to `MonoImage` instances. `libmonodroid.so` trusts that `Xamarin.Android.Build.Tasks.dll` et al will 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 created an 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 | 5 +++++ .../Utilities/MarshalMethodsNativeAssemblyGenerator.cs | 3 ++- tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | 3 ++- 5 files changed, 11 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..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 @@ -166,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; } 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 23f74fb46bf..1f0d4000992 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");