Commit 005e2dff21dde479177cd48c9b38c18c1f213c9d

Sylvain Becker 2020-01-17T12:41:54

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)

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;