Skip to content

Commit 39576f2

Browse files
authored
[Mono.Android] Don't use __Internal in our P/Invoke calls (#4757)
Context: #4914 Context: d583b7c Context: mono/mono#20295 (comment) Context? mono/mono#17369 Context? mono/mono@d5b6cf3 As a runtime extension, Mono long supported `[DllImport("__Internal")]` as a synonym for [`dlopen(NULL, 0)`][0]. Unfortunately, this [did not work on Android][1] -- Bionic would SIGSEGV when the filename parameter was `NULL` -- and as "fallout" of this change the `loader_func` that Xamarin.Android registers with mono via `mono_dl_fallback_register()` would be invoked *instead of* `dlopen(NULL)` when loading `__Internal`…but *only* on Android. Use of this feature remains widely used in Xamarin.Android, e.g. [`java-interop` is mapped to `__Internal`][2], avoiding the need to build and ship a separate `libjava-interop.so` library. Unfortunately, as part of .NET 5, MonoVM will be overhauling the semantics of `[DllImport("__Internal")]`, preventing `loader_func` from being invoked on Android to resolve `__Internal`. Consequently, we need to begin moving away from use of `__Internal`. Begin this process, and remove all P/Invokes to `__Internal` within `Mono.Android.dll` with P/Invokes to `xa-internal-api` (d583b7c). [0]: https://linux.die.net/man/3/dlopen [1]: mono/mono@9b73cd9 [2]: https://github.com/xamarin/xamarin-android/blob/faf1d16692ead1115d34fdf7b84c256c94a321da/src/monodroid/config.xml#L2
1 parent eadd3bd commit 39576f2

File tree

9 files changed

+109
-39
lines changed

9 files changed

+109
-39
lines changed

src/Mono.Android/Android.Runtime/AndroidEnvironment.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ static string GetDefaultTimeZone ()
280280
}
281281
}
282282

283-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
283+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
284284
static extern IntPtr _monodroid_timezone_get_default_id ();
285285

286286
// This is invoked by
@@ -301,7 +301,7 @@ static string GetDefaultTimeZone ()
301301
// These are invoked by
302302
// System.dll!System.AndroidPlatform.getifaddrs
303303
// DO NOT REMOVE
304-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
304+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
305305
static extern int _monodroid_getifaddrs (out IntPtr ifap);
306306

307307
static int GetInterfaceAddresses (out IntPtr ifap)
@@ -312,15 +312,15 @@ static int GetInterfaceAddresses (out IntPtr ifap)
312312
// These are invoked by
313313
// System.dll!System.AndroidPlatform.freeifaddrs
314314
// DO NOT REMOVE
315-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
315+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
316316
static extern void _monodroid_freeifaddrs (IntPtr ifap);
317317

318318
static void FreeInterfaceAddresses (IntPtr ifap)
319319
{
320320
_monodroid_freeifaddrs (ifap);
321321
}
322322

323-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
323+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
324324
static extern void _monodroid_detect_cpu_and_architecture (ref ushort built_for_cpu, ref ushort running_on_cpu, ref byte is64bit);
325325

326326
static void DetectCPUAndArchitecture (out ushort builtForCPU, out ushort runningOnCPU, out bool is64bit)

src/Mono.Android/Android.Runtime/AndroidRuntime.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ namespace Android.Runtime {
1616

1717
class AndroidRuntime : JniRuntime {
1818

19+
public const string InternalDllName = "xa-internal-api";
20+
1921
internal AndroidRuntime (IntPtr jnienv,
2022
IntPtr vm,
2123
bool allocNewObjectSupported,
@@ -100,7 +102,7 @@ public AndroidRuntimeOptions (IntPtr jnienv,
100102

101103
class AndroidObjectReferenceManager : JniRuntime.JniObjectReferenceManager {
102104

103-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
105+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
104106
static extern int _monodroid_gref_get ();
105107

106108
public override int GlobalReferenceCount {

src/Mono.Android/Android.Runtime/JNIEnv.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,16 @@ public static partial class JNIEnv {
6666

6767
internal static AndroidValueManager? AndroidValueManager;
6868

69-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
69+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
7070
extern static void monodroid_log (LogLevel level, LogCategories category, string message);
7171

72-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
72+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
7373
internal extern static IntPtr monodroid_timing_start (string? message);
7474

75-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
75+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
7676
internal extern static void monodroid_timing_stop (IntPtr sequence, string? message);
7777

78-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
78+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
7979
internal extern static void monodroid_free (IntPtr ptr);
8080

8181
public static IntPtr Handle {
@@ -296,7 +296,7 @@ internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPt
296296
}
297297
}
298298

299-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
299+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
300300
extern static void _monodroid_gc_wait_for_bridge_processing ();
301301

302302
#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 ()
310310
_monodroid_gc_wait_for_bridge_processing ();
311311
}
312312

313-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
313+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
314314
extern static IntPtr _monodroid_get_identity_hash_code (IntPtr env, IntPtr value);
315315

316316
internal static Func<IntPtr, IntPtr>? IdentityHash;
@@ -597,25 +597,25 @@ internal static void DeleteRef (IntPtr handle, JniHandleOwnership transfer)
597597
}
598598
}
599599

600-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
600+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
601601
internal static extern int _monodroid_gref_log (string message);
602602

603-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
603+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
604604
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);
605605

606-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
606+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
607607
internal static extern void _monodroid_gref_log_delete (IntPtr handle, byte type, string? threadName, int threadId, [In] StringBuilder? from, int from_writable);
608608

609-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
609+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
610610
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);
611611

612-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
612+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
613613
internal static extern void _monodroid_weak_gref_delete (IntPtr handle, byte type, string? threadName, int threadId, [In] StringBuilder? from, int from_writable);
614614

615-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
615+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
616616
internal static extern int _monodroid_lref_log_new (int lrefc, IntPtr handle, byte type, string? threadName, int threadId, [In] StringBuilder from, int from_writable);
617617

618-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
618+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
619619
internal static extern void _monodroid_lref_log_delete (int lrefc, IntPtr handle, byte type, string? threadName, int threadId, [In] StringBuilder from, int from_writable);
620620

621621
public static IntPtr NewGlobalRef (IntPtr jobject)

src/Mono.Android/Android.Runtime/Logger.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static void Log (LogLevel level, string appname, string? log) {
6060
}
6161
}
6262

63-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
63+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
6464
extern static uint monodroid_get_log_categories ();
6565

6666
static Logger ()

src/Mono.Android/Java.Interop/Runtime.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ public static List<WeakReference> GetSurfacedObjects ()
2020
return r;
2121
}
2222

23-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
23+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
2424
static extern int _monodroid_max_gref_get ();
2525

2626
public static int MaxGlobalReferenceCount {
2727
get {return _monodroid_max_gref_get ();}
2828
}
2929

30-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
30+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
3131
static extern int _monodroid_gref_get ();
3232

3333
public static int GlobalReferenceCount {

src/Mono.Android/Java.Interop/TypeManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public static Dictionary<Type, string> ManagedToJni {
3838
}
3939

4040
public static partial class TypeManager {
41-
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
41+
[DllImport (AndroidRuntime.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
4242
extern static IntPtr monodroid_TypeManager_get_java_class_name (IntPtr klass);
4343

4444
internal static string GetClassName (IntPtr class_ptr)

src/monodroid/jni/monodroid-glue-internal.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ namespace xamarin::android::internal
139139
private:
140140
unsigned int convert_dl_flags (int flags);
141141
#if defined (WINDOWS) || defined (APPLE_OS_X)
142-
static const char* get_my_location ();
142+
static const char* get_my_location (bool remove_file_name = true);
143143
#endif // defined(WINDOWS) || defined(APPLE_OS_X)
144144
static void* monodroid_dlopen (const char *name, int flags, char **err, void *user_data);
145145
static void* monodroid_dlsym (void *handle, const char *name, char **err, void *user_data);

src/monodroid/jni/monodroid-glue.cc

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,27 +1151,92 @@ MonodroidRuntime::monodroid_dlopen (const char *name, int flags, char **err, [[m
11511151
{
11521152
unsigned int dl_flags = monodroidRuntime.convert_dl_flags (flags);
11531153
bool libmonodroid_fallback = false;
1154-
1154+
bool name_is_full_path = false;
1155+
bool name_needs_free = false;
11551156
/* name is nullptr when we're P/Invoking __Internal, so remap to libxa-internal-api */
1156-
if (name == nullptr) {
1157+
if (name == nullptr || strstr (name, "xa-internal-api") != nullptr) {
1158+
#if defined (WINDOWS)
1159+
char *tmp_name = nullptr;
1160+
1161+
auto probe_dll_at = [&](const char *the_path) -> bool {
1162+
if (the_path == nullptr) {
1163+
return false;
1164+
}
1165+
1166+
const char *last_sep = strrchr (the_path, MONODROID_PATH_SEPARATOR_CHAR);
1167+
if (last_sep != nullptr) {
1168+
char *dir = utils.strdup_new (the_path, last_sep - the_path);
1169+
tmp_name = utils.string_concat (dir, MONODROID_PATH_SEPARATOR, API_DSO_NAME);
1170+
delete[] dir;
1171+
if (!utils.file_exists (tmp_name)) {
1172+
delete[] tmp_name;
1173+
tmp_name = nullptr;
1174+
return false;
1175+
}
1176+
1177+
return true;
1178+
}
1179+
1180+
return false;
1181+
};
1182+
1183+
//
1184+
// First try to see if it exist at the path pointed to by `name`. With p/invokes, currently (Sep 2020), we can't
1185+
// really trust the path since it consists of *some* directory path + p/invoke library name and it does not
1186+
// point to the location where the native library is. However, we still need to check the location first, should
1187+
// it point to the right place in the future.
1188+
//
1189+
// Context: https://github.com/mono/mono/issues/20295#issuecomment-679271621
1190+
//
1191+
bool found = probe_dll_at (name);
1192+
if (!found) {
1193+
// Next lets try the location of the XA runtime DLL, libxa-internal-api.dll should be next to it.
1194+
const char *path = get_my_location (false);
1195+
found = probe_dll_at (path);
1196+
if (path != nullptr) {
1197+
free (reinterpret_cast<void*>(const_cast<char*>(path)));
1198+
}
1199+
1200+
if (!found) {
1201+
log_warn (LOG_DEFAULT, "Failed to locate %s, using file name without the path", API_DSO_NAME);
1202+
name = API_DSO_NAME;
1203+
} else {
1204+
name = tmp_name;
1205+
name_is_full_path = true;
1206+
name_needs_free = true;
1207+
}
1208+
}
1209+
#else // ndef WINDOWS
11571210
name = API_DSO_NAME;
1211+
#endif // WINDOWS
11581212
libmonodroid_fallback = true;
11591213
}
11601214

1161-
void *h = androidSystem.load_dso_from_any_directories (name, dl_flags);
1215+
void *h = nullptr;
1216+
if (!name_is_full_path)
1217+
h = androidSystem.load_dso_from_any_directories (name, dl_flags);
11621218

11631219
if (h != nullptr) {
1164-
return monodroid_dlopen_log_and_return (h, err, name, false, libmonodroid_fallback);
1220+
return monodroid_dlopen_log_and_return (h, err, name, name_needs_free, libmonodroid_fallback);
11651221
}
11661222

11671223
if (libmonodroid_fallback) {
1168-
char *full_name = utils.path_combine (AndroidSystem::SYSTEM_LIB_PATH, API_DSO_NAME);
1224+
const char *full_name;
1225+
if (name_is_full_path) {
1226+
full_name = name;
1227+
} else {
1228+
if (name_needs_free) {
1229+
delete[] name;
1230+
}
1231+
full_name = utils.path_combine (AndroidSystem::SYSTEM_LIB_PATH, API_DSO_NAME);
1232+
name_needs_free = true;
1233+
}
11691234
h = androidSystem.load_dso (full_name, dl_flags, false);
1170-
return monodroid_dlopen_log_and_return (h, err, full_name, true, true);
1235+
return monodroid_dlopen_log_and_return (h, err, full_name, name_needs_free, true);
11711236
}
11721237

11731238
if (!utils.ends_with (name, ".dll.so") && !utils.ends_with (name, ".exe.so")) {
1174-
return monodroid_dlopen_log_and_return (h, err, name, false);
1239+
return monodroid_dlopen_log_and_return (h, err, name, name_needs_free);
11751240
}
11761241

11771242
char *basename_part = const_cast<char*> (strrchr (name, '/'));
@@ -1186,6 +1251,10 @@ MonodroidRuntime::monodroid_dlopen (const char *name, int flags, char **err, [[m
11861251
if (h != nullptr && XA_UNLIKELY (utils.should_log (LOG_ASSEMBLY)))
11871252
log_info_nocheck (LOG_ASSEMBLY, "Loaded AOT image '%s'", static_cast<const char*>(basename));
11881253

1254+
if (name_needs_free) {
1255+
delete[] name;
1256+
}
1257+
11891258
return h;
11901259
}
11911260

@@ -1489,7 +1558,7 @@ MonodroidRuntime::typemap_managed_to_java (MonoReflectionType *type, const uint8
14891558

14901559
#if defined (WINDOWS)
14911560
const char*
1492-
MonodroidRuntime::get_my_location ()
1561+
MonodroidRuntime::get_my_location (bool remove_file_name)
14931562
{
14941563
HMODULE hm = NULL;
14951564

@@ -1507,21 +1576,24 @@ MonodroidRuntime::get_my_location ()
15071576
return nullptr;
15081577
}
15091578

1510-
PathRemoveFileSpecW (path);
1579+
if (remove_file_name)
1580+
PathRemoveFileSpecW (path);
15111581

15121582
return utils.utf16_to_utf8 (path);
15131583
}
15141584
#elif defined (APPLE_OS_X)
15151585
const char*
1516-
MonodroidRuntime::get_my_location ()
1586+
MonodroidRuntime::get_my_location (bool remove_file_name)
15171587
{
15181588
Dl_info info;
15191589
if (dladdr (reinterpret_cast<const void*>(&MonodroidRuntime::get_my_location), &info) == 0) {
15201590
log_warn (LOG_DEFAULT, "Could not lookup library containing `MonodroidRuntime::get_my_location()`; dladdr failed: %s", dlerror ());
15211591
return nullptr;
15221592
}
15231593

1524-
return utils.strdup_new (dirname (const_cast<char*>(info.dli_fname)));
1594+
if (remove_file_name)
1595+
return utils.strdup_new (dirname (const_cast<char*>(info.dli_fname)));
1596+
return utils.strdup_new (info.dli_fname);
15251597
}
15261598
#endif // defined(WINDOWS)
15271599

tests/MSBuildDeviceIntegration/Tests/XASdkDeployTests.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,7 @@ public void DotNetDebug ()
5555
AssertHasDevices ();
5656

5757
XASdkProject proj;
58-
proj = new XASdkProject {
59-
//TODO: targetSdkVersion="30" causes a crash on startup in .NET 5
60-
MinSdkVersion = null,
61-
TargetSdkVersion = null,
62-
};
58+
proj = new XASdkProject ();
6359
proj.SetRuntimeIdentifier (DeviceAbi);
6460

6561
var relativeProjDir = Path.Combine ("temp", TestName);

0 commit comments

Comments
 (0)