Fix SIGABRT on activity destroy: null view in registerFragment
Crash on device (Pixel 9 Pro, Android 17) when swiping the app away from recents: JNI DETECTED ERROR: java_object == null in call to GetObjectClass #06 libgio.so (registerFragment+104) Root cause: Gio's window.detach sends an EMPTY AndroidViewEvent (View == 0) as its detach signal (os_android.go: window.detach -> processEvent(AndroidViewEvent{})), which fires when the GioView is destroyed — i.e. the activity going away on a recents-wipe. Our handleEvent passed that null ref straight into registerFragment, whose GetObjectClass(null) aborts. Pre-existing latent bug; the emulator never delivered a detach event in testing (home keeps the view attached, force-stop kills before the event dispatches). Guard on both sides: handleEvent ignores the View == 0 detach signal (a re-attach arrives as a fresh event with a live view), and registerFragment returns early on a null view as defense in depth. Verified on the crashing device: recents swipe now closes the app cleanly, crash buffer empty.
This commit is contained in:
parent
2bdff5c8e8
commit
fdbffc9f5c
|
|
@ -41,6 +41,15 @@ func impl_start() {}
|
||||||
func handleEvent(e event.Event) {
|
func handleEvent(e event.Event) {
|
||||||
switch e := e.(type) {
|
switch e := e.(type) {
|
||||||
case app.AndroidViewEvent:
|
case app.AndroidViewEvent:
|
||||||
|
// View == 0 is Gio's DETACH signal (window.detach sends an empty
|
||||||
|
// AndroidViewEvent when the GioView is destroyed — e.g. the activity
|
||||||
|
// going away on a recents-wipe). There is nothing to register for a
|
||||||
|
// detached view; passing the null ref on would abort in JNI
|
||||||
|
// (GetObjectClass on null). A re-attach arrives as a fresh event
|
||||||
|
// with a live view.
|
||||||
|
if e.View == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
theJVM = (*C.JavaVM)(unsafe.Pointer(app.JavaVM()))
|
theJVM = (*C.JavaVM)(unsafe.Pointer(app.JavaVM()))
|
||||||
RunInJVM(func(env *JNIEnv) {
|
RunInJVM(func(env *JNIEnv) {
|
||||||
C.registerFragment(env, (C.jobject)(unsafe.Pointer(e.View)))
|
C.registerFragment(env, (C.jobject)(unsafe.Pointer(e.View)))
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,17 @@ static jobject g_view = NULL;
|
||||||
|
|
||||||
void
|
void
|
||||||
registerFragment(JNIEnv *env, jobject view) {
|
registerFragment(JNIEnv *env, jobject view) {
|
||||||
if (view != NULL) {
|
if (view == NULL) {
|
||||||
if (g_view == NULL) {
|
// Detach signal (Gio sends an empty AndroidViewEvent when the
|
||||||
g_view = (*env)->NewGlobalRef(env, view);
|
// view is destroyed). The Go side already filters these; this
|
||||||
} else if (g_view != view) {
|
// guard keeps the JNI calls safe if one ever slips through.
|
||||||
(*env)->DeleteGlobalRef(env, g_view);
|
return;
|
||||||
g_view = (*env)->NewGlobalRef(env, view);
|
}
|
||||||
}
|
if (g_view == NULL) {
|
||||||
|
g_view = (*env)->NewGlobalRef(env, view);
|
||||||
|
} else if (g_view != view) {
|
||||||
|
(*env)->DeleteGlobalRef(env, g_view);
|
||||||
|
g_view = (*env)->NewGlobalRef(env, view);
|
||||||
}
|
}
|
||||||
jclass cls = (*env)->GetObjectClass(env, view);
|
jclass cls = (*env)->GetObjectClass(env, view);
|
||||||
jmethodID mid = (*env)->GetMethodID(env, cls, "getContext", "()Landroid/content/Context;");
|
jmethodID mid = (*env)->GetMethodID(env, cls, "getContext", "()Landroid/content/Context;");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user