Description
Java code
import android.os.Handler;
import android.os.Looper;
public class Deadlock {
public interface Delegate {
void perform();
}
public static void deadlock(Delegate delegate) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(delegate::perform);
}
}
Dart code
final delegate = Deadlock$Delegate.implement($Deadlock$Delegate(perform: () {
print('Hello');
}));
Deadlock.deadlock(delegate);
Java Stack trace
_invoke:-1, PortProxyBuilder (com.github.dart_lang.jni), PortProxyBuilder.java
invoke:143, PortProxyBuilder (com.github.dart_lang.jni), PortProxyBuilder.java
2 hidden frames
run:0, Deadlock$$ExternalSyntheticLambda0 (com.superlist.super_native_dialogs), D8$$SyntheticClass
8 hidden frames
Native Stack trace
[libc.so] syscall 0x000000710b8d63cc
[libdartjni.so] wait_for dartjni.h:119
[libdartjni.so] Java_com_github_dart_1lang_jni_PortProxyBuilder__1invoke dartjni.c:459
The problem that Java_com_github_dart_1lang_jni_PortProxyBuilder__1invoke
checks Dart_CurrentIsolate_DL
to determine whether the call is coming from another thread, and if that returns null
it sends message on port and wait. However in case of Flutter on Android, the platform thread is the isolate thread, which means it is essentially blocking the main thread. Note that Dart_CurrentIsolate_DL
returns null
, because after posting the callback to main looper the isolate has been exited.
The solution that would work in the context of Flutter is to remember the thread Id alongside isolate, and if the thread Id matches, calling Dart_EnterIsolate_DL
and Dart_ExitIsolate_DL
around the trampoline.
Now while this works for Flutter, I'm not sure the solution is generic enough since it makes assumption about the isolate being "pinned" to a specific thread.
Metadata
Metadata
Assignees
Type
Projects
Status