Android: prevents rare crashes when app goes to background or ends. Make sure the thread is actually paused, and context backep-up, before SurfaceView is destroyed (eg surfaceDestroyed() actually returns). Add a timeout when surfaceDestroyed() is called, and check 'backup_done' variable. It prevents crashes like: #00 pc 000000000000c0d0 /system/lib64/libutils.so (android::RefBase::incStrong(void const*) const+8) #01 pc 000000000000c7f4 /vendor/lib64/egl/eglSubDriverAndroid.so (EglAndroidWindowSurface::UpdateBufferList(ANativeWindowBuffer*)+284) #02 pc 000000000000c390 /vendor/lib64/egl/eglSubDriverAndroid.so (EglAndroidWindowSurface::DequeueBuffer()+240) #03 pc 000000000000bb10 /vendor/lib64/egl/eglSubDriverAndroid.so (EglAndroidWindowSurface::GetBuffer(EglSubResource*, EglMemoryDesc*)+64) #04 pc 000000000032732c /vendor/lib64/egl/libGLESv2_adreno.so (EglWindowSurface::UpdateResource(EsxContext*)+116) #05 pc 0000000000326dd0 /vendor/lib64/egl/libGLESv2_adreno.so (EglWindowSurface::GetResource(EsxContext*, EsxResource**, EsxResource**, int)+56) #06 pc 00000000002ae484 /vendor/lib64/egl/libGLESv2_adreno.so (EsxContext::AcquireBackBuffer(int)+364) #07 pc 0000000000249680 /vendor/lib64/egl/libGLESv2_adreno.so (EsxContext::Clear(unsigned int, unsigned int, unsigned int, EsxClearValues*)+1800) #08 pc 00000000002cb52c /vendor/lib64/egl/libGLESv2_adreno.so (EsxGlApiParamValidate::GlClear(EsxDispatch*, unsigned int)+132)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index 3c15bb0..7f1955f 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -472,7 +472,7 @@ Android_JNI_CreateKey_once(void)
}
static void
-register_methods(JNIEnv *env, const char *classname, JNINativeMethod *methods, int nb)
+register_methods(JNIEnv *env, const char *classname, JNINativeMethod *methods, int nb)
{
jclass clazz = (*env)->FindClass(env, classname);
if (clazz == NULL || (*env)->RegisterNatives(env, clazz, methods, nb) < 0) {
@@ -492,7 +492,7 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
return JNI_VERSION_1_4;
}
- register_methods(env, "org/libsdl/app/SDLActivity", SDLActivity_tab, SDL_arraysize(SDLActivity_tab));
+ register_methods(env, "org/libsdl/app/SDLActivity", SDLActivity_tab, SDL_arraysize(SDLActivity_tab));
register_methods(env, "org/libsdl/app/SDLInputConnection", SDLInputConnection_tab, SDL_arraysize(SDLInputConnection_tab));
register_methods(env, "org/libsdl/app/SDLAudioManager", SDLAudioManager_tab, SDL_arraysize(SDLAudioManager_tab));
register_methods(env, "org/libsdl/app/SDLControllerManager", SDLControllerManager_tab, SDL_arraysize(SDLControllerManager_tab));
@@ -994,6 +994,10 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv *env, j
/* Called from surfaceDestroyed() */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(JNIEnv *env, jclass jcls)
{
+ int nb_attempt = 50;
+
+retry:
+
SDL_LockMutex(Android_ActivityMutex);
if (Android_Window)
@@ -1001,21 +1005,27 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(JNIEnv *env,
SDL_VideoDevice *_this = SDL_GetVideoDevice();
SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata;
- /* We have to clear the current context and destroy the egl surface here
- * Otherwise there's BAD_NATIVE_WINDOW errors coming from eglCreateWindowSurface on resume
- * Ref: http://stackoverflow.com/questions/8762589/eglcreatewindowsurface-on-ics-and-switching-from-2d-to-3d
- */
+ /* Wait for Main thread being paused and context un-activated to release 'egl_surface' */
+ if (! data->backup_done) {
+ nb_attempt -= 1;
+ if (nb_attempt == 0) {
+ SDL_SetError("Try to release egl_surface with context probably still active");
+ } else {
+ SDL_UnlockMutex(Android_ActivityMutex);
+ SDL_Delay(10);
+ goto retry;
+ }
+ }
if (data->egl_surface != EGL_NO_SURFACE) {
- SDL_EGL_MakeCurrent(_this, NULL, NULL);
SDL_EGL_DestroySurface(_this, data->egl_surface);
data->egl_surface = EGL_NO_SURFACE;
}
if (data->native_window) {
ANativeWindow_release(data->native_window);
+ data->native_window = NULL;
}
- data->native_window = NULL;
/* GL Context handling is done in the event loop because this function is run from the Java thread */
}
@@ -1190,7 +1200,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)(
if (Android_Window) {
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeFocusChanged()");
SDL_SendWindowEvent(Android_Window, (hasFocus ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST), 0, 0);
- }
+ }
SDL_UnlockMutex(Android_ActivityMutex);
}
diff --git a/src/video/android/SDL_androidevents.c b/src/video/android/SDL_androidevents.c
index 91c84b6..51d2a57 100644
--- a/src/video/android/SDL_androidevents.c
+++ b/src/video/android/SDL_androidevents.c
@@ -68,6 +68,7 @@ android_egl_context_restore(SDL_Window *window)
event.type = SDL_RENDER_DEVICE_RESET;
SDL_PushEvent(&event);
}
+ data->backup_done = 0;
}
}
@@ -80,6 +81,7 @@ android_egl_context_backup(SDL_Window *window)
data->egl_context = SDL_GL_GetCurrentContext();
/* We need to do this so the EGLSurface can be freed */
SDL_GL_MakeCurrent(window, NULL);
+ data->backup_done = 1;
}
}
diff --git a/src/video/android/SDL_androidwindow.h b/src/video/android/SDL_androidwindow.h
index 235a3a8..c26a072 100644
--- a/src/video/android/SDL_androidwindow.h
+++ b/src/video/android/SDL_androidwindow.h
@@ -39,6 +39,7 @@ typedef struct
{
EGLSurface egl_surface;
EGLContext egl_context; /* We use this to preserve the context when losing focus */
+ SDL_bool backup_done;
ANativeWindow *native_window;
} SDL_WindowData;