From c7f716e2ea8fa1facdbccb4d34dd648c4dd06721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etcheverry?= Date: Sat, 29 Jan 2022 21:58:55 +0100 Subject: [PATCH] Mono/C#: Fix Android AAB export failing to load native libs By default, when installing from Android App Bundles the native libraries are not extracted. They are loaded directly from the APK. See: https://stackoverflow.com/a/56551499 Passing only the file name to dlopen, without the location, makes it search the native library in all locations, including inside the apk. --- .../mono/mono_gd/support/android_support.cpp | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp index 35a9ffcb4f0..8bb33e2a310 100644 --- a/modules/mono/mono_gd/support/android_support.cpp +++ b/modules/mono/mono_gd/support/android_support.cpp @@ -164,11 +164,12 @@ const char *godot_so_name = "libgodot_android.so"; void *mono_dl_handle = NULL; void *godot_dl_handle = NULL; -void *try_dlopen(const String &p_so_path, int p_flags) { +void *_try_dlopen_file_path(const String &p_so_path, int p_flags) { if (!FileAccess::exists(p_so_path)) { - if (OS::get_singleton()->is_stdout_verbose()) + if (OS::get_singleton()->is_stdout_verbose()) { OS::get_singleton()->print("Cannot find shared library: '%s'\n", p_so_path.utf8().get_data()); - return NULL; + } + return nullptr; } int lflags = gd_mono_convert_dl_flags(p_flags); @@ -176,13 +177,48 @@ void *try_dlopen(const String &p_so_path, int p_flags) { void *handle = dlopen(p_so_path.utf8().get_data(), lflags); if (!handle) { - if (OS::get_singleton()->is_stdout_verbose()) + if (OS::get_singleton()->is_stdout_verbose()) { OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", p_so_path.utf8().get_data(), dlerror()); - return NULL; + } + return nullptr; } - if (OS::get_singleton()->is_stdout_verbose()) + if (OS::get_singleton()->is_stdout_verbose()) { OS::get_singleton()->print("Successfully loaded shared library: '%s'\n", p_so_path.utf8().get_data()); + } + + return handle; +} + +void *try_dlopen(const String &p_so_path, int p_flags) { + void *handle = _try_dlopen_file_path(p_so_path, p_flags); + + if (handle) { + return handle; + } + + // Try only with the file name, without specifying the location. + // This is needed when installing from Android App Bundles, as the native + // libraries are not extracted. They are loaded directly from the APK. + // See: https://stackoverflow.com/a/56551499 + // If we pass only the file name to dlopen without the location, it should + // search the native libraries in all locations, including inside the apk. + + String so_name = p_so_path.get_file(); + + int lflags = gd_mono_convert_dl_flags(p_flags); + + handle = dlopen(so_name.utf8().get_data(), lflags); + if (!handle) { + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", so_name.utf8().get_data(), dlerror()); + } + return nullptr; + } + + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print("Successfully loaded shared library: '%s'\n", so_name.utf8().get_data()); + } return handle; } @@ -196,6 +232,7 @@ void *gd_mono_android_dlopen(const char *p_name, int p_flags, char **r_err, void String so_path = path::join(app_native_lib_dir, mono_so_name); mono_dl_handle = try_dlopen(so_path, p_flags); + ERR_FAIL_COND_V_MSG(!mono_dl_handle, nullptr, "Failed to load Mono native library from path"); } return mono_dl_handle; @@ -371,7 +408,7 @@ void initialize() { String so_path = path::join(app_native_lib_dir, godot_so_name); godot_dl_handle = try_dlopen(so_path, gd_mono_convert_dl_flags(MONO_DL_LAZY)); - ERR_FAIL_COND(!godot_dl_handle); + ERR_FAIL_COND_MSG(!godot_dl_handle, "Failed to load Godot native library"); } void cleanup() {