Skip to content

Commit 4b16be1

Browse files
committed
Lots of code, Android doesn't cooperate...
No matter what I try, the call posted to the main thread still doesn't use the right class loader and, thus, `System.loadLibrary` cannot find the shared lib: ``` 08-13 12:16:10.657 12472 12507 D monodroid-assembly: Trying to load loading shared JNI library /data/user/0/Mono.Android.NET_Tests/files/.__override__/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so with System.loadLibrary 08-13 12:16:10.657 12472 12507 D monodroid-assembly: Running DSO loader on thread 12507, dispatching to main thread 08-13 12:16:10.657 12472 12472 D monodroid-assembly: Looper CB called on thread 12472. Will attempt to load DSO 'System.Security.Cryptography.Native.Android' 08-13 12:16:10.657 12472 12472 D monodroid-assembly: Undecorated library name: System.Security.Cryptography.Native.Android 08-13 12:16:10.659 12472 12472 D nativeloader: Load libSystem.Security.Cryptography.Native.Android.so using system ns (caller=/system/framework/framework.jar!classes3.dex): dlopen failed: library "libSystem.Security.Cryptography.Native.Android.so" not found 08-13 12:16:10.659 12472 12472 D monodroid-assembly: System.loadLibrary threw a Java exception. Will attempt to log it. 08-13 12:16:10.661 12472 12472 W System.err: java.lang.UnsatisfiedLinkError: dlopen failed: library "libSystem.Security.Cryptography.Native.Android.so" not found ``` Time to think about something else :( Thank you Android for 3 days wasted
1 parent 29463c7 commit 4b16be1

File tree

10 files changed

+105
-33
lines changed

10 files changed

+105
-33
lines changed

src/native/clr/host/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ set(XAMARIN_NET_ANDROID_STATIC_LIB "${XAMARIN_NET_ANDROID_LIB}-static")
2828
set(XAMARIN_MONODROID_SOURCES
2929
assembly-store.cc
3030
bridge-processing.cc
31-
dso-loader.cc
3231
gc-bridge.cc
3332
host.cc
3433
host-jni.cc
3534
host-util.cc
3635
internal-pinvokes.cc
3736
os-bridge.cc
37+
runtime-environment.cc
3838
runtime-util.cc
3939
typemap.cc
4040
xamarin_getifaddrs.cc

src/native/clr/host/dso-loader.cc

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <runtime-base/runtime-environment.hh>
2+
#include <host/os-bridge.hh>
3+
4+
using namespace xamarin::android;
5+
6+
auto RuntimeEnvironment::get_jnienv () noexcept -> JNIEnv*
7+
{
8+
return OSBridge::ensure_jnienv ();
9+
}

src/native/common/include/runtime-base/dso-loader.hh

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <runtime-base/android-system.hh>
1313
#include <runtime-base/mainthread-dso-loader.hh>
14+
#include <runtime-base/runtime-environment.hh>
1415
#include <runtime-base/system-loadlibrary-wrapper.hh>
1516
#include <runtime-base/util.hh>
1617
#include <shared/helpers.hh>
@@ -27,7 +28,7 @@ namespace xamarin::android {
2728
static void init (JNIEnv *env, jclass systemClass, ALooper *main_looper, pid_t _main_thread_id) noexcept
2829
{
2930
SystemLoadLibraryWrapper::init (env, systemClass);
30-
MainThreadDsoLoader::init (main_looper);
31+
MainThreadDsoLoader::init (env, main_looper);
3132
main_thread_id = _main_thread_id;
3233
}
3334

@@ -70,7 +71,6 @@ namespace xamarin::android {
7071
}
7172

7273
private:
73-
static auto get_jnienv () noexcept -> JNIEnv*;
7474
static auto load_jni_on_main_thread (std::string_view const& full_name, std::string const& undecorated_name) noexcept -> void*;
7575

7676
[[gnu::always_inline]]
@@ -99,10 +99,6 @@ namespace xamarin::android {
9999
{
100100
log_debug (LOG_ASSEMBLY, "Trying to load loading shared JNI library {} with System.loadLibrary", name);
101101

102-
if (systemKlass == nullptr) [[unlikely]] {
103-
Helpers::abort_application ("DSO loader class not initialized properly."sv);
104-
}
105-
106102
auto get_file_name = [](std::string_view const& full_name, bool is_path) -> std::string_view {
107103
if (!is_path) {
108104
return full_name;
@@ -163,15 +159,18 @@ namespace xamarin::android {
163159

164160
// TODO: implement the above
165161
if (gettid () == main_thread_id) {
166-
if (!SystemLoadLibraryWrapper::load (get_jnienv (), get_undecorated_name (name, name_is_path))) {
162+
if (!SystemLoadLibraryWrapper::load (RuntimeEnvironment::get_jnienv (), get_undecorated_name (name, name_is_path))) {
167163
// We could abort, but let's let the managed land react to this library missing. We cannot continue
168164
// with `dlopen` below, because without `JNI_OnLoad` etc invoked, we might have nasty crashes in the
169165
// library code if e.g. it assumes that `JNI_OnLoad` initialized all the Java class, method etc
170166
// pointers.
171167
return nullptr;
172168
}
173169
} else {
174-
Helpers::abort_application ("Loading DSO on the main thread not implemented yet"sv);
170+
MainThreadDsoLoader loader;
171+
if (!loader.load (name, get_undecorated_name (name, name_is_path))) {
172+
return nullptr;
173+
}
175174
}
176175

177176
// This is unfortunate, but since `System.loadLibrary` doesn't return the class handle, we must get it this
@@ -183,8 +182,6 @@ namespace xamarin::android {
183182
}
184183

185184
private:
186-
static inline jmethodID System_loadLibrary = nullptr;
187-
static inline jclass systemKlass = nullptr;
188185
static inline pid_t main_thread_id = 0;
189186
};
190187
}

src/native/common/include/runtime-base/mainthread-dso-loader.hh

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@
44
#include <cstring>
55
#include <unistd.h>
66

7+
#include <array>
8+
#include <chrono>
79
#include <format>
810
#include <semaphore>
911
#include <string_view>
1012

1113
#include <android/looper.h>
1214

15+
#include <runtime-base/logger.hh>
16+
#include <runtime-base/runtime-environment.hh>
17+
#include <runtime-base/system-loadlibrary-wrapper.hh>
1318
#include <shared/helpers.hh>
1419

1520
namespace xamarin::android {
@@ -24,7 +29,7 @@ namespace xamarin::android {
2429
Helpers::abort_application (
2530
LOG_ASSEMBLY,
2631
std::format (
27-
"Failed to create a pipe for main thread DSO loader. {}",
32+
"Failed to create a pipe for main thread DSO loader. {}"sv,
2833
strerror (errno)
2934
)
3035
);
@@ -64,35 +69,89 @@ namespace xamarin::android {
6469
MainThreadDsoLoader& operator=(const MainThreadDsoLoader&) = delete;
6570
MainThreadDsoLoader& operator=(MainThreadDsoLoader&&) = delete;
6671

67-
void load (std::string_view const& full_name, std::string const& undecorated_name) noexcept
72+
bool load (std::string_view const& full_name, std::string_view const& undecorated_name) noexcept
6873
{
69-
// TODO: init load here by writing to pipe_fds[1]
74+
if (!undecorated_library_name.empty ()) [[unlikely]] {
75+
Helpers::abort_application ("Main thread DSO loader object reused! DO NOT DO THAT!"sv);
76+
}
77+
log_debug (LOG_ASSEMBLY, "Running DSO loader on thread {}, dispatching to main thread"sv, gettid ());
78+
79+
undecorated_library_name = undecorated_name;
80+
load_success = false;
81+
constexpr std::array<uint8_t, 1> payload { 0xFF };
82+
ssize_t nbytes = write (pipe_fds[1], payload.data (), payload.size ());
83+
if (nbytes == -1) {
84+
log_warn (
85+
LOG_ASSEMBLY,
86+
"Write failure when posting a DSO load event to main thread. {}"sv,
87+
strerror (errno)
88+
);
89+
return false;
90+
}
7091

7192
// Wait for the callback to complete
72-
load_complete_sem.acquire ();
93+
using namespace std::literals;
94+
95+
// We'll wait for up to 3s, it should be more than enough time for the library to load
96+
bool success = load_complete_sem.try_acquire_for (3s);
97+
if (!success) {
98+
log_warn (LOG_ASSEMBLY, "Timeout while waiting for shared library '{}' to load."sv, full_name);
99+
return false;
100+
}
101+
102+
return load_success;
73103
}
74104

75-
static void init (ALooper *main_looper)
105+
static void init (JNIEnv *main_jni_env, ALooper *main_looper)
76106
{
77-
main_thread_looper = main_looper;
107+
if (main_thread_looper != nullptr) {
108+
return;
109+
}
78110

111+
main_thread_looper = main_looper;
112+
main_thread_jni_env = main_jni_env;
79113
// This will keep the looper around for the lifetime of the application.
80114
ALooper_acquire (main_looper);
81115
}
82116

83117
private:
84-
static auto load_cb (int fd, int events, void *data) noexcept -> int
118+
119+
static auto load_cb ([[maybe_unused]] int fd, [[maybe_unused]] int events, void *data) noexcept -> int
85120
{
86121
auto self = reinterpret_cast<MainThreadDsoLoader*> (data);
122+
if (self == nullptr) [[unlikely]] {
123+
Helpers::abort_application ("MainThreadDsoLoader instance not passed to the looper callback."sv);
124+
}
125+
126+
auto over_and_out = [&self]() -> int {
127+
// We're one-shot, 0 means just that
128+
self->load_complete_sem.release ();
129+
return 0;
130+
};
131+
132+
if (self->undecorated_library_name.empty ()) {
133+
log_warn (LOG_ASSEMBLY, "Library name not specified in main thread looper callback."sv);
134+
return over_and_out ();
135+
}
136+
137+
log_debug (
138+
LOG_ASSEMBLY,
139+
"Looper CB called on thread {}. Will attempt to load DSO '{}'"sv,
140+
gettid (),
141+
self->undecorated_library_name
142+
);
87143

88-
self->load_complete_sem.release ();
89-
return 0; // We're one-shot, 0 means just that
144+
self->load_success = SystemLoadLibraryWrapper::load (main_thread_jni_env /* RuntimeEnvironment::get_jnienv () */, self->undecorated_library_name);
145+
return over_and_out ();
90146
}
91147

92148
private:
93149
int pipe_fds[2] = {-1, -1};
94150
std::binary_semaphore load_complete_sem {0};
151+
std::string_view undecorated_library_name {};
152+
bool load_success = false;
95153

96154
static inline ALooper *main_thread_looper = nullptr;
155+
static inline JNIEnv *main_thread_jni_env = nullptr;
97156
};
98157
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
3+
#include <jni.h>
4+
5+
namespace xamarin::android {
6+
class RuntimeEnvironment
7+
{
8+
public:
9+
static auto get_jnienv () noexcept -> JNIEnv*;
10+
};
11+
}

src/native/common/include/runtime-base/system-loadlibrary-wrapper.hh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ namespace xamarin::android {
2525
[[gnu::flatten]]
2626
static auto load (JNIEnv *jni_env, std::string_view const& undecorated_lib_name) noexcept -> bool
2727
{
28+
if (systemKlass == nullptr) [[unlikely]] {
29+
Helpers::abort_application ("System.loadeLibrary wrapper class not initialized properly."sv);
30+
}
31+
2832
// std::string is needed because we must pass a NUL-terminated string to Java, otherwise
2933
// strange things happen (and std::string_view is not necessarily such a string)
3034
const std::string lib_name { undecorated_lib_name };

src/native/mono/monodroid/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ set(XAMARIN_MONO_ANDROID_STATIC_LIB "${XAMARIN_MONO_ANDROID_LIB}-static")
9393
set(XAMARIN_MONODROID_SOURCES
9494
debug-constants.cc
9595
debug.cc
96-
dso-loader.cc
9796
embedded-assemblies-zip.cc
9897
embedded-assemblies.cc
9998
globals.cc
@@ -104,6 +103,7 @@ set(XAMARIN_MONODROID_SOURCES
104103
monodroid-tracing.cc
105104
monovm-properties.cc
106105
osbridge.cc
106+
runtime-environment.cc
107107
runtime-util.cc
108108
timezones.cc
109109
xamarin_getifaddrs.cc
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
#include <runtime-base/dso-loader.hh>
1+
#include <runtime-base/runtime-environment.hh>
22

33
#include "osbridge.hh"
44

55
using namespace xamarin::android;
66
using namespace xamarin::android::internal;
77

8-
auto DsoLoader::get_jnienv () noexcept -> JNIEnv*
8+
auto RuntimeEnvironment::get_jnienv () noexcept -> JNIEnv*
99
{
1010
return OSBridge::ensure_jnienv ();
1111
}

src/native/mono/xamarin-debug-app-helper/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ set(LIB_NAME xamarin-debug-app-helper)
22
set(LIB_ALIAS xa::debug-app-helper)
33

44
set(XAMARIN_DEBUG_HELPER_SOURCES
5-
../monodroid/dso-loader.cc
5+
../monodroid/runtime-environment.cc
66
debug-app-helper.cc
77
)
88
add_clang_check_sources("${XAMARIN_DEBUG_HELPER_SOURCES}")
@@ -55,6 +55,7 @@ target_link_libraries(
5555
xa::runtime-base
5656
xa::java-interop
5757
-ldl
58+
-landroid
5859
-llog
5960
-lmonosgen-2.0
6061
)

0 commit comments

Comments
 (0)