Commit d583b7c
authored
[monodroid] Work around an Android 9 dlopen bug on x86 (#4914)
Fixes: #4893
The setup:
1. App with `AndroidManifest.xml` which sets
`/application/@android:extractNativeLibs` to `false`, e.g.:
[assembly:Application (ExtractNativeLibs=false)]
2. Build (1) as a *Release* app
3. Run (2) on an Android 9.0 (API-28) *x86* emulator (32-bit!)
The result: app crash during process startup!
E/mono(14126): Unhandled Exception:
E/mono(14126): System.ArgumentNullException: Value cannot be null.
E/mono(14126): Parameter name: key
E/mono(14126): at System.Collections.Generic.Dictionary`2[TKey,TValue].FindEntry (TKey key)
E/mono(14126): at System.Collections.Generic.Dictionary`2[TKey,TValue].TryGetValue (TKey key, TValue& value)
E/mono(14126): at Java.Interop.TypeManager.RegisterType (System.String java_class, System.Type t)
E/mono(14126): at Android.Runtime.JNIEnv.RegisterJniNatives (System.IntPtr typeName_ptr, System.Int32 typeName_len, System.IntPtr jniClass, System.IntPtr methods_ptr, System.Int32 methods_len)
The cause of the crash is an apparent Android bionic bug, a'la:
void* h1 = dlopen ("…path/to/libmonodroid.so", RTLD_LAZY);
// time passses
void* h2 = dlopen ("…path/to/libmonodroid.so", RTLD_LAZY);
"Normal"/expected semantics are that `h1` is the same as `h2`, with
the second `dlopen()` invocation effectively being a no-op, as the
library has already been loaded.
On 32-bit Android 9 -- but *only* when `extractNativeLibs`=false! --
what *instead* happens is that that native library is *re-loaded* such
that `h1` != `h2` (potentially?!), *and* the global state of `h1` is
cleared; the library is reinitialized.
Where this comes in is with P/Invokes to `__Internal`, which we
"redirect" to `libmonodroid.so`. However, since `dlopen(NULL)`
has a history on Android of generating a SIGSEGV, we avoid the crash
by explicitly loading `libmonodroid.so` every time we need to satisfy
a request for `__Internal` (in `MonodroidRuntime::monodroid_dlopen()`
when `name` is `nullptr`). As we re-load `libmonodroid.so` and
`dlopen()` potentially *clears* global data, what happens is that
certain class members initialized in `Runtime.initInternal()` become
`nullptr`. In this particular case, `MonodroidRuntime::Class_getName`
became null, which meant that we couldn't lookup Java class names,
which caused the subsequent crash.
The fix is to introduce a new `libxa-internal-api.so` which contains
only three things of consequence:
1. Explicit "init" and "shutdown" exports:
MONO_API bool _monodroid_init_internal_api (MonoAndroidInternalCalls *api);
MONO_API bool _monodroid_shutdown_internal_api (void);
2. A pointer to a new `MonoAndroidInternalCalls` "interface",
implemented in `libmonodroid.so`, and
3. Other "C" exports that `__Internal` needs to invoke, which are
implemented by delegating through `MonoAndroidInternalCalls`.
`libxa-internal-api.so` thus becomes the *only* library that we ever
`dlopen()` more than once, and as we control when it's loaded, we can
call `_monodroid_init_internal_api()` and
`_monodroid_shutdown_internal_api()` as appropriate, ensuring that
when we run on Android 9+x86+`extractNativeLibs`=false, the "damage"
from subsequent `dlopen()` invocations is minimized.1 parent d447aa6 commit d583b7c
File tree
20 files changed
+1001
-391
lines changed- build-tools
- create-packs
- installers
- samples/HelloWorld/Properties
- src
- Xamarin.Android.Build.Tasks
- monodroid
- jni
20 files changed
+1001
-391
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
41 | 42 | | |
42 | 43 | | |
43 | 44 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
159 | 159 | | |
160 | 160 | | |
161 | 161 | | |
| 162 | + | |
162 | 163 | | |
163 | 164 | | |
164 | 165 | | |
| |||
294 | 295 | | |
295 | 296 | | |
296 | 297 | | |
| 298 | + | |
297 | 299 | | |
298 | 300 | | |
299 | 301 | | |
| |||
333 | 335 | | |
334 | 336 | | |
335 | 337 | | |
| 338 | + | |
336 | 339 | | |
337 | 340 | | |
338 | 341 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1890 | 1890 | | |
1891 | 1891 | | |
1892 | 1892 | | |
| 1893 | + | |
1893 | 1894 | | |
1894 | 1895 | | |
1895 | 1896 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
228 | 228 | | |
229 | 229 | | |
230 | 230 | | |
| 231 | + | |
| 232 | + | |
231 | 233 | | |
232 | 234 | | |
233 | 235 | | |
| |||
285 | 287 | | |
286 | 288 | | |
287 | 289 | | |
288 | | - | |
289 | 290 | | |
290 | | - | |
291 | 291 | | |
292 | 292 | | |
| 293 | + | |
293 | 294 | | |
294 | 295 | | |
295 | 296 | | |
| |||
299 | 300 | | |
300 | 301 | | |
301 | 302 | | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
302 | 309 | | |
303 | 310 | | |
304 | 311 | | |
| |||
314 | 321 | | |
315 | 322 | | |
316 | 323 | | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
317 | 333 | | |
318 | 334 | | |
319 | 335 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
225 | 225 | | |
226 | 226 | | |
227 | 227 | | |
228 | | - | |
| 228 | + | |
229 | 229 | | |
230 | 230 | | |
231 | 231 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
597 | 597 | | |
598 | 598 | | |
599 | 599 | | |
600 | | - | |
| 600 | + | |
601 | 601 | | |
602 | 602 | | |
603 | 603 | | |
| |||
0 commit comments