From 005e2dff21dde479177cd48c9b38c18c1f213c9d Mon Sep 17 00:00:00 2001 From: Sylvain Becker Date: Fri, 17 Jan 2020 12:41:54 +0100 Subject: [PATCH] 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) --- src/core/android/SDL_android.c | 28 ++++++++++++++++++--------- src/video/android/SDL_androidevents.c | 2 ++ src/video/android/SDL_androidwindow.h | 1 + 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 3c15bb0e7..7f1955fbf 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 91c84b694..51d2a57a5 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 235a3a89a..c26a072ee 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;