From 7e050a670b3b7ebc150c093677102d7783ba165a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 3 Jun 2020 10:18:49 +0200 Subject: [PATCH] Stop using `__Internal` in our p/invoke calls Context: https://github.com/xamarin/xamarin-android/pull/4914 Context: https://github.com/xamarin/xamarin-android/commit/d583b7c215fe9be2f732b4a52423be0aea7f0809 The .NET5 version of the Mono runtime "hijacked" `__Internal` for its own purposes and the change causes us trouble when trying to resolve p/invokes from our managed code to our runtime. Instead we now use `xa-internal-api` (added in d583b7c2) to specify the p/invoke library name. --- .../Android.Runtime/AndroidEnvironment.cs | 8 +- .../Android.Runtime/AndroidRuntime.cs | 4 +- src/Mono.Android/Android.Runtime/JNIEnv.cs | 26 ++--- src/Mono.Android/Android.Runtime/Logger.cs | 2 +- src/Mono.Android/Java.Interop/Runtime.cs | 4 +- src/Mono.Android/Java.Interop/TypeManager.cs | 2 +- src/monodroid/jni/monodroid-glue-internal.hh | 2 +- src/monodroid/jni/monodroid-glue.cc | 94 ++++++++++++++++--- .../Tests/XASdkDeployTests.cs | 6 +- 9 files changed, 109 insertions(+), 39 deletions(-) diff --git a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs index 86bedf422f9..57db3c44ee1 100644 --- a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs +++ b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs @@ -280,7 +280,7 @@ static string GetDefaultTimeZone () } } - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] static extern IntPtr _monodroid_timezone_get_default_id (); // This is invoked by @@ -301,7 +301,7 @@ static string GetDefaultTimeZone () // These are invoked by // System.dll!System.AndroidPlatform.getifaddrs // DO NOT REMOVE - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] static extern int _monodroid_getifaddrs (out IntPtr ifap); static int GetInterfaceAddresses (out IntPtr ifap) @@ -312,7 +312,7 @@ static int GetInterfaceAddresses (out IntPtr ifap) // These are invoked by // System.dll!System.AndroidPlatform.freeifaddrs // DO NOT REMOVE - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] static extern void _monodroid_freeifaddrs (IntPtr ifap); static void FreeInterfaceAddresses (IntPtr ifap) @@ -320,7 +320,7 @@ static void FreeInterfaceAddresses (IntPtr ifap) _monodroid_freeifaddrs (ifap); } - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] static extern void _monodroid_detect_cpu_and_architecture (ref ushort built_for_cpu, ref ushort running_on_cpu, ref byte is64bit); static void DetectCPUAndArchitecture (out ushort builtForCPU, out ushort runningOnCPU, out bool is64bit) diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs index d989036b95e..8e12cec67e3 100644 --- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs +++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs @@ -16,6 +16,8 @@ namespace Android.Runtime { class AndroidRuntime : JniRuntime { + public const string InternalDllName = "xa-internal-api"; + internal AndroidRuntime (IntPtr jnienv, IntPtr vm, bool allocNewObjectSupported, @@ -100,7 +102,7 @@ public AndroidRuntimeOptions (IntPtr jnienv, class AndroidObjectReferenceManager : JniRuntime.JniObjectReferenceManager { - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] static extern int _monodroid_gref_get (); public override int GlobalReferenceCount { diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 660d6bb3686..a1ad9c67ee5 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -66,16 +66,16 @@ public static partial class JNIEnv { internal static AndroidValueManager? AndroidValueManager; - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] extern static void monodroid_log (LogLevel level, LogCategories category, string message); - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal extern static IntPtr monodroid_timing_start (string? message); - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal extern static void monodroid_timing_stop (IntPtr sequence, string? message); - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal extern static void monodroid_free (IntPtr ptr); public static IntPtr Handle { @@ -296,7 +296,7 @@ internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPt } } - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] extern static void _monodroid_gc_wait_for_bridge_processing (); #pragma warning disable CS0649 // Field is never assigned to. This field is assigned from monodroid-glue.cc. @@ -310,7 +310,7 @@ public static void WaitForBridgeProcessing () _monodroid_gc_wait_for_bridge_processing (); } - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] extern static IntPtr _monodroid_get_identity_hash_code (IntPtr env, IntPtr value); internal static Func? IdentityHash; @@ -597,25 +597,25 @@ internal static void DeleteRef (IntPtr handle, JniHandleOwnership transfer) } } - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern int _monodroid_gref_log (string message); - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern int _monodroid_gref_log_new (IntPtr curHandle, byte curType, IntPtr newHandle, byte newType, string? threadName, int threadId, [In] StringBuilder? from, int from_writable); - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern void _monodroid_gref_log_delete (IntPtr handle, byte type, string? threadName, int threadId, [In] StringBuilder? from, int from_writable); - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern void _monodroid_weak_gref_new (IntPtr curHandle, byte curType, IntPtr newHandle, byte newType, string? threadName, int threadId, [In] StringBuilder? from, int from_writable); - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern void _monodroid_weak_gref_delete (IntPtr handle, byte type, string? threadName, int threadId, [In] StringBuilder? from, int from_writable); - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern int _monodroid_lref_log_new (int lrefc, IntPtr handle, byte type, string? threadName, int threadId, [In] StringBuilder from, int from_writable); - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] internal static extern void _monodroid_lref_log_delete (int lrefc, IntPtr handle, byte type, string? threadName, int threadId, [In] StringBuilder from, int from_writable); public static IntPtr NewGlobalRef (IntPtr jobject) diff --git a/src/Mono.Android/Android.Runtime/Logger.cs b/src/Mono.Android/Android.Runtime/Logger.cs index fe3fb4c91dc..b75ab7ab782 100644 --- a/src/Mono.Android/Android.Runtime/Logger.cs +++ b/src/Mono.Android/Android.Runtime/Logger.cs @@ -60,7 +60,7 @@ public static void Log (LogLevel level, string appname, string? log) { } } - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] extern static uint monodroid_get_log_categories (); static Logger () diff --git a/src/Mono.Android/Java.Interop/Runtime.cs b/src/Mono.Android/Java.Interop/Runtime.cs index 96fc0b65358..4ebf234200e 100644 --- a/src/Mono.Android/Java.Interop/Runtime.cs +++ b/src/Mono.Android/Java.Interop/Runtime.cs @@ -20,14 +20,14 @@ public static List GetSurfacedObjects () return r; } - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] static extern int _monodroid_max_gref_get (); public static int MaxGlobalReferenceCount { get {return _monodroid_max_gref_get ();} } - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] static extern int _monodroid_gref_get (); public static int GlobalReferenceCount { diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index 8f3d4bef114..4f9750f1c35 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -38,7 +38,7 @@ public static Dictionary ManagedToJni { } public static partial class TypeManager { - [DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)] + [DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)] extern static IntPtr monodroid_TypeManager_get_java_class_name (IntPtr klass); internal static string GetClassName (IntPtr class_ptr) diff --git a/src/monodroid/jni/monodroid-glue-internal.hh b/src/monodroid/jni/monodroid-glue-internal.hh index 028b3278c13..2c98378df4b 100644 --- a/src/monodroid/jni/monodroid-glue-internal.hh +++ b/src/monodroid/jni/monodroid-glue-internal.hh @@ -139,7 +139,7 @@ namespace xamarin::android::internal private: unsigned int convert_dl_flags (int flags); #if defined (WINDOWS) || defined (APPLE_OS_X) - static const char* get_my_location (); + static const char* get_my_location (bool remove_file_name = true); #endif // defined(WINDOWS) || defined(APPLE_OS_X) static void* monodroid_dlopen (const char *name, int flags, char **err, void *user_data); static void* monodroid_dlsym (void *handle, const char *name, char **err, void *user_data); diff --git a/src/monodroid/jni/monodroid-glue.cc b/src/monodroid/jni/monodroid-glue.cc index d37175e41de..07a20d17932 100644 --- a/src/monodroid/jni/monodroid-glue.cc +++ b/src/monodroid/jni/monodroid-glue.cc @@ -1151,27 +1151,92 @@ MonodroidRuntime::monodroid_dlopen (const char *name, int flags, char **err, [[m { unsigned int dl_flags = monodroidRuntime.convert_dl_flags (flags); bool libmonodroid_fallback = false; - + bool name_is_full_path = false; + bool name_needs_free = false; /* name is nullptr when we're P/Invoking __Internal, so remap to libxa-internal-api */ - if (name == nullptr) { + if (name == nullptr || strstr (name, "xa-internal-api") != nullptr) { +#if defined (WINDOWS) + char *tmp_name = nullptr; + + auto probe_dll_at = [&](const char *the_path) -> bool { + if (the_path == nullptr) { + return false; + } + + const char *last_sep = strrchr (the_path, MONODROID_PATH_SEPARATOR_CHAR); + if (last_sep != nullptr) { + char *dir = utils.strdup_new (the_path, last_sep - the_path); + tmp_name = utils.string_concat (dir, MONODROID_PATH_SEPARATOR, API_DSO_NAME); + delete[] dir; + if (!utils.file_exists (tmp_name)) { + delete[] tmp_name; + tmp_name = nullptr; + return false; + } + + return true; + } + + return false; + }; + + // + // First try to see if it exist at the path pointed to by `name`. With p/invokes, currently (Sep 2020), we can't + // really trust the path since it consists of *some* directory path + p/invoke library name and it does not + // point to the location where the native library is. However, we still need to check the location first, should + // it point to the right place in the future. + // + // Context: https://github.com/mono/mono/issues/20295#issuecomment-679271621 + // + bool found = probe_dll_at (name); + if (!found) { + // Next lets try the location of the XA runtime DLL, libxa-internal-api.dll should be next to it. + const char *path = get_my_location (false); + found = probe_dll_at (path); + if (path != nullptr) { + free (reinterpret_cast(const_cast(path))); + } + + if (!found) { + log_warn (LOG_DEFAULT, "Failed to locate %s, using file name without the path", API_DSO_NAME); + name = API_DSO_NAME; + } else { + name = tmp_name; + name_is_full_path = true; + name_needs_free = true; + } + } +#else // ndef WINDOWS name = API_DSO_NAME; +#endif // WINDOWS libmonodroid_fallback = true; } - void *h = androidSystem.load_dso_from_any_directories (name, dl_flags); + void *h = nullptr; + if (!name_is_full_path) + h = androidSystem.load_dso_from_any_directories (name, dl_flags); if (h != nullptr) { - return monodroid_dlopen_log_and_return (h, err, name, false, libmonodroid_fallback); + return monodroid_dlopen_log_and_return (h, err, name, name_needs_free, libmonodroid_fallback); } if (libmonodroid_fallback) { - char *full_name = utils.path_combine (AndroidSystem::SYSTEM_LIB_PATH, API_DSO_NAME); + const char *full_name; + if (name_is_full_path) { + full_name = name; + } else { + if (name_needs_free) { + delete[] name; + } + full_name = utils.path_combine (AndroidSystem::SYSTEM_LIB_PATH, API_DSO_NAME); + name_needs_free = true; + } h = androidSystem.load_dso (full_name, dl_flags, false); - return monodroid_dlopen_log_and_return (h, err, full_name, true, true); + return monodroid_dlopen_log_and_return (h, err, full_name, name_needs_free, true); } if (!utils.ends_with (name, ".dll.so") && !utils.ends_with (name, ".exe.so")) { - return monodroid_dlopen_log_and_return (h, err, name, false); + return monodroid_dlopen_log_and_return (h, err, name, name_needs_free); } char *basename_part = const_cast (strrchr (name, '/')); @@ -1186,6 +1251,10 @@ MonodroidRuntime::monodroid_dlopen (const char *name, int flags, char **err, [[m if (h != nullptr && XA_UNLIKELY (utils.should_log (LOG_ASSEMBLY))) log_info_nocheck (LOG_ASSEMBLY, "Loaded AOT image '%s'", static_cast(basename)); + if (name_needs_free) { + delete[] name; + } + return h; } @@ -1489,7 +1558,7 @@ MonodroidRuntime::typemap_managed_to_java (MonoReflectionType *type, const uint8 #if defined (WINDOWS) const char* -MonodroidRuntime::get_my_location () +MonodroidRuntime::get_my_location (bool remove_file_name) { HMODULE hm = NULL; @@ -1507,13 +1576,14 @@ MonodroidRuntime::get_my_location () return nullptr; } - PathRemoveFileSpecW (path); + if (remove_file_name) + PathRemoveFileSpecW (path); return utils.utf16_to_utf8 (path); } #elif defined (APPLE_OS_X) const char* -MonodroidRuntime::get_my_location () +MonodroidRuntime::get_my_location (bool remove_file_name) { Dl_info info; if (dladdr (reinterpret_cast(&MonodroidRuntime::get_my_location), &info) == 0) { @@ -1521,7 +1591,9 @@ MonodroidRuntime::get_my_location () return nullptr; } - return utils.strdup_new (dirname (const_cast(info.dli_fname))); + if (remove_file_name) + return utils.strdup_new (dirname (const_cast(info.dli_fname))); + return utils.strdup_new (info.dli_fname); } #endif // defined(WINDOWS) diff --git a/tests/MSBuildDeviceIntegration/Tests/XASdkDeployTests.cs b/tests/MSBuildDeviceIntegration/Tests/XASdkDeployTests.cs index b2fdaa3c766..9d2a999aba8 100644 --- a/tests/MSBuildDeviceIntegration/Tests/XASdkDeployTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/XASdkDeployTests.cs @@ -55,11 +55,7 @@ public void DotNetDebug () AssertHasDevices (); XASdkProject proj; - proj = new XASdkProject { - //TODO: targetSdkVersion="30" causes a crash on startup in .NET 5 - MinSdkVersion = null, - TargetSdkVersion = null, - }; + proj = new XASdkProject (); proj.SetRuntimeIdentifier (DeviceAbi); var relativeProjDir = Path.Combine ("temp", TestName);