From 67bf7d8a52f489185e18f8e7a5ad5703a7b0ed63 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 20 Jul 2022 15:43:46 -0500 Subject: [PATCH] [Mono.Android] fix crash on startup with EnableLLVM `dotnet new android` apps would crash on startup when built with `-c Release -p:EnableLLVM=true`: 07-20 08:55:44.642 2983 2983 F monodroid-assembly: Internal p/invoke symbol 'java-interop @ java_interop_jvm_list' (hash: 0x58c48fc8b89cb484) not found in compile-time map. ... 07-20 08:55:44.834 3004 3004 F DEBUG : signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr -------- 07-20 08:55:44.834 3004 3004 F DEBUG : Abort message: 'Internal p/invoke symbol 'java-interop @ java_interop_jvm_list' (hash: 0x58c48fc8b89cb484) not found in compile-time map.' `java_interop_jvm_list` should *never* be called on Android, it is the result of `new AndroidRuntime()` having not been called yet? The problem being that the static `Android.App.Application.cctor` was somehow running *before* `JNIEnv.Initialize()` was complete? And this only happens with LLVM? Reviewing the code: [UnmanagedCallersOnly] internal static unsafe void Initialize (JnienvInitializeArgs* args) { //... SynchronizationContext.SetSynchronizationContext (Android.App.Application.SynchronizationContext); } We do indeed access `Android.App.Application`... To fix this, we can move this to a new method decorated with `MethodImplOptions.NoInlining`. Apps built with LLVM now launch for me. We can also enable the LLVM `Mono.Android-Tests` again. --- build-tools/automation/azure-pipelines.yaml | 4 +--- src/Mono.Android/Android.Runtime/JNIEnv.cs | 9 ++++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index c5d397bd7ad..8240ee9146d 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -691,13 +691,11 @@ stages: - template: yaml-templates/apk-instrumentation.yaml parameters: - # TODO: disable LLVM test, see: https://github.com/dotnet/runtime/issues/68914 - condition: false configuration: $(XA.Build.Configuration) testName: Mono.Android.NET_Tests-AotLlvm project: tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)AotLlvm.xml - extraBuildArgs: -p:TestsFlavor=AotLlvm -p:EnableLlvm=true + extraBuildArgs: -p:TestsFlavor=AotLlvm -p:EnableLlvm=true -p:AndroidEnableProfiledAot=false artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab artifactFolder: $(DotNetTargetFramework)-AotLlvm useDotNet: true diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 26485b9462a..d9ef52d1255 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -196,10 +196,17 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args) } #if !MONOANDROID1_0 - SynchronizationContext.SetSynchronizationContext (Android.App.Application.SynchronizationContext); + SetSynchronizationContext (); #endif } +#if !MONOANDROID1_0 + // NOTE: prevents Android.App.Application static ctor from running + [MethodImpl (MethodImplOptions.NoInlining)] + static void SetSynchronizationContext () => + SynchronizationContext.SetSynchronizationContext (Android.App.Application.SynchronizationContext); +#endif + internal static void Exit () { /* Manually dispose surfaced objects and close the current JniEnvironment to