Skip to content

Conversation

@dependabot
Copy link

@dependabot dependabot bot commented on behalf of github Dec 9, 2022

Bumps external/Java.Interop from 3a9f770 to 149d70f.

Commits
  • 149d70f [generator] Refactor enum writing to use SourceWriters (#1063)
  • c2daa9f [Java.Interop.Tools.Cecil] DirectoryAssemblyResolver & File.Exists() (#1065)
  • 8ab9d33 [Java.Interop.Tools.TypeNameMappings] improve `ToJniNameFromAttributesForAndr...
  • 09f8da2 [JavaCallableWrappers] avoid string.Format() (#1061)
  • See full diff in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [external/Java.Interop](https://github.com/xamarin/java.interop) from `3a9f770` to `149d70f`.
- [Release notes](https://github.com/xamarin/java.interop/releases)
- [Commits](dotnet/java-interop@3a9f770...149d70f)

---
updated-dependencies:
- dependency-name: external/Java.Interop
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
@dependabot dependabot bot added dependencies Pull requests that update a dependency file submodules Pull requests that update Submodules code labels Dec 9, 2022
@dependabot @github
Copy link
Author

dependabot bot commented on behalf of github Dec 15, 2022

Superseded by #12.

@dependabot dependabot bot closed this Dec 15, 2022
@dependabot dependabot bot deleted the dependabot/submodules/external/Java.Interop-149d70f branch December 15, 2022 08:12
jonpryor pushed a commit that referenced this pull request Jul 25, 2024
Context: dotnet/maui#23694 (review)
Context: https://github.com/dotnet/maui/blob/d38ca872f68326ab623c050b0efd93c7d212e000/src/Essentials/test/DeviceTests/Tests/Preferences_Tests.cs#L305-L310
Context: dotnet/android@06bb1dc...45855b8

A .NET MAUI on-device test is crashing on API 23 emulators:

    07-23 11:35:45.837  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115] JNI ERROR (app bug): local reference table overflow (max=512)
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115] local reference table dump:
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]   Last 10 entries (of 512):
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       511: 0x6ff7e140 java.lang.Class<android.app.SharedPreferencesImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       510: 0x6ff7db18 java.lang.Class<android.app.SharedPreferencesImpl$EditorImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       509: 0x6fed5750 java.lang.Class<android.content.SharedPreferences$Editor>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       508: 0x6ff7e140 java.lang.Class<android.app.SharedPreferencesImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       507: 0x6fed57d8 java.lang.Class<android.content.SharedPreferences>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       506: 0x6ff7e140 java.lang.Class<android.app.SharedPreferencesImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       505: 0x6fed57d8 java.lang.Class<android.content.SharedPreferences>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       504: 0x6ff7db18 java.lang.Class<android.app.SharedPreferencesImpl$EditorImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       503: 0x6fed5750 java.lang.Class<android.content.SharedPreferences$Editor>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       502: 0x6ff7e140 java.lang.Class<android.app.SharedPreferencesImpl>
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]   Summary:
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]       511 of java.lang.Class (7 unique instances)
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]         1 of android.app.SharedPreferencesImpl
    07-23 11:35:45.839  4252  4277 F art     : art/runtime/indirect_reference_table.cc:115]
    07-23 11:35:45.930  4252  4277 F art     : art/runtime/barrier.cc:90] Check failed: count_ == 0 (count_=-1, 0=0) Attempted to destroy barrier with non zero count
    07-23 11:35:45.930  4252  4277 F art     : art/runtime/runtime.cc:366] Runtime aborting --- recursively, so no thread-specific detail!
    07-23 11:35:45.930  4252  4277 F art     : art/runtime/runtime.cc:366]
    --------- beginning of crash
    07-23 11:35:45.930  4252  4277 F libc    : Fatal signal 6 (SIGABRT), code -6 in tid 4277 (.NET TP Worker)
    07-23 11:35:46.003  1640  1640 I SELinux : SELinux: Loaded file_contexts contexts from /file_contexts.
    07-23 11:35:46.006  1640  1640 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    07-23 11:35:46.006  1640  1640 F DEBUG   : Build fingerprint: 'Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/6695544:userdebug/test-keys'
    07-23 11:35:46.006  1640  1640 F DEBUG   : Revision: '0'
    07-23 11:35:46.006  1640  1640 F DEBUG   : ABI: 'x86_64'
    07-23 11:35:46.006  1640  1640 F DEBUG   : pid: 4252, tid: 4277, name: .NET TP Worker  >>> com.microsoft.maui.essentials.devicetests <<<
    07-23 11:35:46.006  1640  1640 F DEBUG   : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    07-23 11:35:46.014  1640  1640 F DEBUG   : Abort message: 'art/runtime/indirect_reference_table.cc:115] JNI ERROR (app bug): local reference table overflow (max=512)'
    07-23 11:35:46.014  1640  1640 F DEBUG   :     rax 0000000000000000  rbx 00007f7dadfbf500  rcx ffffffffffffffff  rdx 0000000000000006
    07-23 11:35:46.014  1640  1640 F DEBUG   :     rsi 00000000000010b5  rdi 000000000000109c
    07-23 11:35:46.014  1640  1640 F DEBUG   :     r8  0000000000000001  r9  0000000000000003  r10 0000000000000008  r11 0000000000000206
    07-23 11:35:46.014  1640  1640 F DEBUG   :     r12 00000000000010b5  r13 0000000000000006  r14 00007f7dc7305a40  r15 00007f7dabd70cc0
    07-23 11:35:46.014  1640  1640 F DEBUG   :     cs  0000000000000033  ss  000000000000002b
    07-23 11:35:46.014  1640  1640 F DEBUG   :     rip 00007f7dcaa49a67  rbp 0000000000000002  rsp 00007f7dadfbc048  eflags 0000000000000206
    07-23 11:35:46.018  1640  1640 F DEBUG   :
    07-23 11:35:46.018  1640  1640 F DEBUG   : backtrace:
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #00 pc 0000000000087a67  /system/lib64/libc.so (tgkill+7)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #1 pc 0000000000085b11  /system/lib64/libc.so (pthread_kill+65)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #2 pc 000000000002e841  /system/lib64/libc.so (raise+17)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #3 pc 00000000000288fd  /system/lib64/libc.so (abort+61)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #4 pc 00000000004ffd65  /system/lib64/libart.so (art::Runtime::Abort()+341)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #5 pc 0000000000178d71  /system/lib64/libart.so (art::LogMessage::~LogMessage()+2865)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #6 pc 0000000000172dad  /system/lib64/libart.so (art::Barrier::~Barrier()+813)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #7 pc 000000000053de1a  /system/lib64/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+394)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #8 pc 00000000004ffea4  /system/lib64/libart.so (art::Runtime::Abort()+660)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #9 pc 0000000000178d71  /system/lib64/libart.so (art::LogMessage::~LogMessage()+2865)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #10 pc 00000000002f00fd  /system/lib64/libart.so (art::IndirectReferenceTable::Add(unsigned int, art::mirror::Object*)+1005)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #11 pc 00000000003ee19a  /system/lib64/libart.so (art::JNI::CallObjectMethodV(_JNIEnv*, _jobject*, _jmethodID*, __va_list_tag*)+586)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #12 pc 00000000001abdf8  /system/lib64/libart.so (art::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, __va_list_tag*, art::Primitive::Type, art::InvokeType)+1736)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #13 pc 00000000001ae031  /system/lib64/libart.so (art::CheckJNI::CallObjectMethodV(_JNIEnv*, _jobject*, _jmethodID*, __va_list_tag*)+33)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #14 pc 000000000004555d  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonodroid.so (_JNIEnv::CallObjectMethod(_jobject*, _jmethodID*, ...)+157)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #15 pc 000000000003beb5  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonodroid.so (xamarin::android::internal::MonodroidRuntime::get_java_class_name_for_TypeManager(_jclass*)+69)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #16 pc 00000000001e8585  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #17 pc 00000000001e7020  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #18 pc 00000000001d8fb5  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #19 pc 00000000001d6961  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #20 pc 00000000000e5f19  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #21 pc 00000000002a96c6  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so (mono_runtime_invoke_checked+86)
    07-23 11:35:46.019  1640  1640 F DEBUG   :     #22 pc 00000000002b202e  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #23 pc 000000000026cb84  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #24 pc 000000000027615a  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #25 pc 00000000001e8618  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #26 pc 00000000001e7066  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #27 pc 00000000001d8fb5  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #28 pc 00000000001d6961  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #29 pc 00000000000e5f19  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     #30 pc 00000000002a96c6  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so (mono_runtime_invoke_checked+86)
    07-23 11:35:46.020  1640  1640 F DEBUG   :     dotnet#31 pc 00000000002c0713  /data/app/com.microsoft.maui.essentials.devicetests-1/lib/x86_64/libmonosgen-2.0.so
    07-23 11:35:46.020  1640  1640 F DEBUG   :     dotnet#32 pc 0000000000084eee  /system/lib64/libc.so (__pthread_start(void*)+46)
    07-23 11:35:46.020  1640  1640 F DEBUG   :     dotnet#33 pc 00000000000296eb  /system/lib64/libc.so (__start_thread+11)
    07-23 11:35:46.020  1640  1640 F DEBUG   :     dotnet#34 pc 000000000001ce55  /system/lib64/libc.so (__bionic_clone+53)
    07-23 11:35:46.179  1640  1640 F DEBUG   :
    07-23 11:35:46.179  1640  1640 F DEBUG   : Tombstone written to: /data/tombstones/tombstone_00

After some investigation, we think this was introduced in 35f41dc.

I could reproduce the issue in a simple test case:

    [Test]
    public void PutAndGetManyValues ()
    {
        for (int i = 0; i < Count; i++) {
            using var prefs = GetPreferences ();
            using var editor = prefs.Edit ();
            editor.PutString ("key" + i, "value" + i);
            editor.Apply ();
        }

        for (int i = 0; i < Count; i++) {
            using var prefs = GetPreferences ();
            Assert.AreEqual ("value" + i, prefs.GetString ("key" + i, null));
        }
    }

Which also crashed with:

    07-24 09:39:02.615  4623  4638 I NUnit   : SharedPreferencesTest
    07-24 09:39:02.615  4623  4638 I NUnit   : PutAndGetManyValues
    07-24 09:39:02.719  4623  4638 F art     : art/runtime/indirect_reference_table.cc:115] JNI ERROR (app bug): local reference table overflow (max=512)

I updated `TypeManager` to use a `try-finally` block, such as:

    JniObjectReference typeClass = default;
    JniObjectReference handleClass = default;
    try {
        //...
    } finally {
        JniObjectReference.Dispose (ref handleClass);
        JniObjectReference.Dispose (ref typeClass);
    }

And it appears the test case now passes on API 23 emulators. Hoping
this will also fix .NET MAUI.
simonrozsival pushed a commit that referenced this pull request Sep 19, 2025
TL;DR

dotnet/android already runs majority of its threads as cooperate
suspend aware threads (GC safe when return from thread attach) and
hybrid suspend will pre-emptive suspend threads that are currently in
GC safe mode, indicates that changing the remaining calls from
`mono_thread_attach` into `mono_jit_thread_attach` should be a
low-risk change.

The full story:

Mono runtime can run in different suspend models, pre-emptive, hybrid
or coop suspend. In the past, Xamarin Android (mono/mono), used
pre-emptive suspend model, but starting with .net6, dotnet Android
switched to hybrid suspend model.

The major difference between these two is how threads are
suspend/resumed when triggering a GC, pre-emptive suspend relies on
signals, meaning that any thread attached to the runtime, can be
suspended at any location in code, including in bad areas that could
cause side effects (like holding low level locks). The Mono embedding
API's was original designed with this suspend model in mind.

The hybrid suspend model on the other hand is a combination between
pre-emptive and cooperate suspend model, but for this discussion, the
interesting part is the fact that threads running GC unsafe under
hybrid suspend need to hit safe points to be suspended, if not hitting
a safe point, the runtime will (by default), wait for that thread
forever, hanging the GC in its stw "stop the world" phase. A safe
point is a location in code where thread will yield execution and wait
for GC to complete and resume it. A safe point is just a location
where a thread tells the runtime that it's in a GC safe region
promising not to touch any managed memory or call any runtime
functions as described here,
https://www.mono-project.com/docs/advanced/runtime/docs/coop-suspend/#gc-safe-mode.

The switching back and forth between GC unsafe and safe is mainly
taken care of by the runtime, for example, calling a p/invoke will
mark the thread as being in GC safe mode while running the p/invoke,
internal runtime waits, hitting safe points in C# code etc. A thread
running in GC unsafe mode means that its executing managed or runtime
code and needs to hit a safe point before it can be suspended by GC.

A thread could start out either as in GC unsafe or safe mode. The
following lists a couple of scenarios:

* `mono_thread_attach` due to backward compability with Mono embedding
  API and embedders, thread attached to the runtime in GC unsafe mode,
  meaning that it needs to reach a safe point to be suspended.
* `mono_jit_thread_attach` thread gets attached to the runtime in GC
  safe mode.
* `mono_jit_init`/`mono_jit_init_version`, thread calling these
  functions to initialize the runtime will be put in GC safe mode.
* Native to managed wrappers, like unmanaged callers only methods,
  reverse p/invoke function pointers, `GetFunctionPointerForDelegate`
  etc, will attach unattached threads so they will be in GC safe mode
  on return.

A thread that is running in GC safe mode must be switched to  GC
unsafe mode when re-entering managed or runtime code. When calling
through the native to managed wrappers, this will be taken care of by
the wrapper. When calling through the Mono embedding API's, each
individual API needs to take a decision (based on what it does) to
switch to GC unsafe and then back to the state thread had when
entering the API (could actually be GC unsafe if it was called in GC
unsafe mode).

Threads GC mode is critical when running a GC, since GC would need to
do a stw in order to proceed with GC work. The hybrid suspend models
stw is a little more complex in how it operates compared to both
pre-emptive and coop suspend, but it mainly boils down to two steps.
The first, all threads attached to the runtime will be checked. If
thread is currently in GC safe mode, it will be ignored in first step,
all threads in GC unsafe mode will be waited upon until they reach a
safe point. This is normally where we see deadlocks in ANR's due to
threads not reaching safe points in timely manners. Once the first
phase is done (all threads in GC unsafe mode reached safe points),
second phase will consider all threads still in GC safe mode and
pre-emptive suspended them (using signals).

We have identified several ANR's (Application Not Responding) on
Android where we seen threads attached to runtime with callstacks like
this:

```
"queue-1-2" tid=8105 Native
  #00  pc 0x000000000006a0c0  /system/lib64/libc.so (__rt_sigsuspend+4)
  #1  pc 0x0000000000029684  /system/lib64/libc.so (sigsuspend+44)
  #2  pc 0x00000000001ff994  /data/app/<app.bundle.id>-_I4CSOAWam382fA8t14IEg==/lib/arm64/libmonosgen-2.0.so (suspend_signal_handler+200)
  #3  pc 0x00000000000005dc  [vdso:000000737837f000]
  #4  pc 0x000000000001dae8  /system/lib64/libc.so (syscall+24)
  #5  pc 0x00000000000e1ee4  /system/lib64/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+152)
  #6  pc 0x0000000000392794  /system/lib64/libart.so (art::Monitor::Wait(art::Thread*, long, int, bool, art::ThreadState)+632)
  #7  pc 0x0000000000394288  /system/lib64/libart.so (art::Monitor::Wait(art::Thread*, art::mirror::Object*, long, int, bool, art::ThreadState)+252)
  #8  pc 0x00000000001dcadc  /system/framework/arm64/boot.oat (java.lang.Object.wait [DEDUPED]+140)
  #9  pc 0x00000000001fcebc  /system/framework/arm64/boot.oat (java.lang.Thread.parkFor$+428)
  #10  pc 0x0000000000608cd8  /system/framework/arm64/boot.oat (java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await+808)
  #11  pc 0x00000000005de8ec  /system/framework/arm64/boot.oat (java.util.concurrent.LinkedBlockingQueue.take+156)
  #12  pc 0x00000000005e9e1c  /system/framework/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor.getTask+492)
  #13  pc 0x00000000005ec2b0  /system/framework/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+240)
  #14  pc 0x00000000005fb114  /system/framework/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+68)
  #15  pc 0x00000000001fd13c  /system/framework/arm64/boot.oat (java.lang.Thread.run+76)
  #16  pc 0x0000000000509384  /system/lib64/libart.so (art_quick_invoke_stub+580)
  #17  pc 0x00000000000d8078  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
  #18  pc 0x0000000000431120  /system/lib64/libart.so (art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*)+104)
  #19  pc 0x00000000004322ac  /system/lib64/libart.so (art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, jvalue*)+432)
  #20  pc 0x0000000000458e8c  /system/lib64/libart.so (art::Thread::CreateCallback(void*)+1140)
  #21  pc 0x00000000000678b4  /system/lib64/libc.so (__pthread_start(void*)+36)
  #22  pc 0x000000000001ef24  /system/lib64/libc.so (__start_thread+68)
```

This thread is attached to runtime since its running our suspend
signal handler, but it also seems to be waiting inside some Java
thread pool. This works under pre-emptive suspend, but if the same
thread has been attached to runtime under hybrid and ends up waiting
like this outside of managed and runtime code, then the thread must be
in GC safe mode or it will violate the runtime hybrid suspend model,
since if a thread is in GC unsafe mode, then it needs to reach a safe
point in timely manner, something above callstack will probably never
do, blocking the completion of stw.

It turns out that dotnet/android codebase still have two locations
that could attach threads using `mono_thread_attach`, while the
majority of threads are attached either as runtime init thread,
marshalled methods using `mono_jit_thread_attach` or native to managed
wrappers. Thread attached using one of the above will be in GC safe
mode, meaning they should either reach safe points or being
pre-emptive suspended under hybrid suspend model. After analyzing the
code paths in dotnet/android ending up in calls to
`mono_thread_attach` it is however still not clear if they are
reachable in real world scenarios, but since we have ANR's that points
to issues suspending threads, we seen threads with callstack waiting
outside runtime and majority of threads attached to runtime running
dotnet Android seems to attach as cooperate suspend aware (GC safe
mode on return), it would make sense to standardize and attach all
threads as cooperate suspend aware in dotnet/android repro.

As part of this analysis, I also looked over all Mono API's used by
dotnet/runtime, analyzed if they are correctly switching to GC unsafe
when called, if the API's are cooperate aware and if they are safe to
only be called during init or before running managed code. The fact
that hybrid suspend will do a pre-emptive suspend on threads that are
running in GC safe mode reduce issues using API's that currently won't
enter GC unsafe (but probably should) or are not cooperate suspend
aware, passing raw GC objects as parameter or return values.

Since we already run majority of threads as cooperate suspend aware
threads (GC safe when return from thread attach) in dotnet/android and
that hybrid suspend will pre-emptive suspend threads that are
currently in GC safe mode, indicates that changing the remaining calls
from `mono_thread_attach` into `mono_jit_thread_attach` should be a
low risk change.

For completion, this is the list of Mono embedding API's used by
dotnet/android and their state regarding switching to GC unsafe, being
cooperate suspend aware and potential implications. API's without
comments should be safe to call under any suspend model. API's marked
as "init-only" should be called before runtime or before running
managed code. They are either not thread safe changing runtime state
or used during runtime initialization or needs to be in place before
running managed code. API's marked with "Can't be called under coop
suspend model." normally means that the API uses raw GC objects as
parameters or return values. These API's can't be called under
cooperate suspend model, but since hybrid suspend model will
pre-emptive suspend threads in GC safe mode, it can still scan threads
active stack and registers, so should be able to handle direct GC
references on stack or in register for all attached runtime threads.
The last category "Should transition to GC unsafe.", is mainly API's
that should do a GC unsafe transition internally but currently don't.
This is something that should probably be fixed in runtime and until
done, these API's can't be safely called under coop suspend model.
They should however still be safe under hybrid suspend, since threads
in GC safe mode will be pre-empted.

| Mono API                                      | GC Unsafe | Cooperate | Comment                                      |
|-----------------------------------------------|-----------|-----------|----------------------------------------------|
| mono_add_internal_call                        | No        | Yes       | init-only                                    |
| mono_alc_get_default_gchandle                 | No        | Yes       |                                              |
| mono_array_new                                | Yes       | No        | Can't be called under coop suspend model.    |
| mono_assembly_get_image                       | Yes       | Yes       |                                              |
| mono_assembly_load_from_full                  | Yes       | Yes       |                                              |
| mono_assembly_load_full                       | Yes       | Yes       |                                              |
| mono_assembly_load_full_alc                   | Yes       | Yes       |                                              |
| mono_assembly_loaded                          | Yes       | Yes       |                                              |
| mono_assembly_name_free                       | Yes       | Yes       |                                              |
| mono_assembly_name_get_culture                | Yes       | Yes       |                                              |
| mono_assembly_name_get_name                   | Yes       | Yes       |                                              |
| mono_assembly_name_new                        | Yes       | Yes       |                                              |
| mono_assembly_open_full                       | Yes       | Yes       |                                              |
| mono_check_corlib_version                     | Yes       | Yes       |                                              |
| mono_class_from_mono_type                     | Yes       | Yes       |                                              |
| mono_class_from_name                          | Yes       | Yes       |                                              |
| mono_class_get                                | Yes       | Yes       |                                              |
| mono_class_get_field_from_name                | Yes       | Yes       |                                              |
| mono_class_get_image                          | No        | Yes       |                                              |
| mono_class_get_method_from_name               | Yes       | Yes       |                                              |
| mono_class_get_name                           | Yes       | Yes       |                                              |
| mono_class_get_namespace                      | Yes       | Yes       |                                              |
| mono_class_get_type                           | No        | Yes       |                                              |
| mono_class_get_type_token                     | No        | Yes       |                                              |
| mono_class_is_subclass_of                     | Yes       | Yes       |                                              |
| mono_class_vtable                             | Yes       | Yes       |                                              |
| mono_config_is_server_mode                    | No        | Yes       |                                              |
| mono_debug_init                               | No        | Yes       | init-only                                    |
| mono_debug_open_image_from_memory             | Yes       | Yes       |                                              |
| mono_debugger_agent_unhandled_exception       | Yes       | No        | Can't be called under coop suspend model.    |
| mono_dl_fallback_register                     | No        | Yes       | init-only                                    |
| mono_domain_foreach                           | Yes       | Yes       |                                              |
| mono_domain_get                               | No        | Yes       |                                              |
| mono_domain_get_id                            | No        | Yes       |                                              |
| mono_domain_set                               | Yes       | Yes       |                                              |
| mono_error_get_message                        | No        | Yes       | Should transition to GC unsafe.              |
| mono_field_get_value                          | Yes       | No        | Can't be called under coop suspend model.    |
| mono_field_set_value                          | Yes       | No        | Can't be called under coop suspend model.    |
| mono_field_static_set_value                   | Yes       | Yes       |                                              |
| mono_gc_register_bridge_callbacks             | No        | Yes       | init-only                                    |
| mono_gc_wait_for_bridge_processing            | Yes       | Yes       |                                              |
| mono_get_byte_class                           | No        | Yes       |                                              |
| mono_get_method                               | No        | Yes       | Should transition to GC unsafe.              |
| mono_get_root_domain                          | No        | Yes       |                                              |
| mono_get_runtime_build_info                   | No        | Yes       |                                              |
| mono_guid_to_string                           | No        | Yes       |                                              |
| mono_image_get_name                           | No        | Yes       |                                              |
| mono_image_loaded                             | Yes       | Yes       |                                              |
| mono_image_open_from_data_alc                 | Yes       | Yes       |                                              |
| mono_image_open_from_data_with_name           | Yes       | Yes       |                                              |
| mono_image_strerror                           | No        | Yes       |                                              |
| mono_install_assembly_preload_hook            | No        | Yes       | init-only                                    |
| mono_install_assembly_preload_hook_v3         | No        | Yes       | init-only                                    |
| mono_jit_init_version                         | No        | Yes       |                                              |
| mono_jit_parse_options                        | No        | Yes       | init-only                                    |
| mono_jit_set_aot_mode                         | No        | Yes       | init-only                                    |
| mono_jit_set_trace_options                    | No        | Yes       | init-only                                    |
| mono_jit_thread_attach                        | No        | Yes       |                                              |
| mono_method_full_name                         | Yes       | Yes       |                                              |
| mono_method_get_unmanaged_callers_only_ftnptr | Yes       | Yes       |                                              |
| mono_object_get_class                         | Yes       | No        | Can't be called under coop suspend model.    |
| mono_profiler_create                          | No        | Yes       | init-only                                    |
| mono_reflection_assembly_get_assembly         | No        | No        | Can't be called under coop suspend model.    |
| mono_reflection_type_from_name                | Yes       | Yes       |                                              |
| mono_reflection_type_get_type                 | Yes       | No        | Can't be called under coop suspend model.    |
| mono_runtime_init                             | No        | Yes       |                                              |
| mono_runtime_invoke                           | Yes       | No        | Can't be called under coop suspend model.    |
| mono_runtime_set_main_args                    | No        | Yes       | init-only                                    |
| mono_set_crash_chaining                       | No        | Yes       | init-only                                    |
| mono_set_signal_chaining                      | No        | Yes       | init-only                                    |
| mono_set_use_llvm                             | No        | Yes       | init-only                                    |
| mono_string_chars                             | No        | No        | Can't be called under coop suspend model.    |
| mono_string_length                            | No        | No        | Can't be called under coop suspend model.    |
| mono_string_new                               | Yes       | No        | Can't be called under coop suspend model.    |
| mono_string_to_utf8                           | Yes       | No        | Can't be called under coop suspend model.    |
| mono_thread_attach                            | No        | No        | Can't be called under coop suspend model.    |
| mono_thread_create                            | Yes       | Yes       |                                              |
| mono_trace_set_level_string                   | No        | Yes       | init-only                                    |
| mono_trace_set_log_handler                    | No        | Yes       | init-only                                    |
| mono_trace_set_mask_string                    | No        | Yes       | init-only                                    |
| mono_trace_set_print_handler                  | No        | Yes       | init-only                                    |
| mono_trace_set_printerr_handler               | No        | Yes       | init-only                                    |
| mono_type_get_name_full                       | No        | Yes       | Should transition to GC unsafe.              |
| mono_type_get_object                          | Yes       | No        | Can't be called under coop suspend model.    |
| mono_unhandled_exception                      | Yes       | No        | Can't be called under coop suspend model.    |
| mono_value_copy_array                         | No        | No        | Can't be called under coop suspend model.    |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file submodules Pull requests that update Submodules code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant