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)
Sylvain Becker 2020-01-17 12:41:54 +01:00
parent d52ba78b29
commit 005e2dff21
3 changed files with 22 additions and 9 deletions

View File

@ -472,7 +472,7 @@ Android_JNI_CreateKey_once(void)
} }
static 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); jclass clazz = (*env)->FindClass(env, classname);
if (clazz == NULL || (*env)->RegisterNatives(env, clazz, methods, nb) < 0) { 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; 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/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/SDLAudioManager", SDLAudioManager_tab, SDL_arraysize(SDLAudioManager_tab));
register_methods(env, "org/libsdl/app/SDLControllerManager", SDLControllerManager_tab, SDL_arraysize(SDLControllerManager_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() */ /* Called from surfaceDestroyed() */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(JNIEnv *env, jclass jcls) JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(JNIEnv *env, jclass jcls)
{ {
int nb_attempt = 50;
retry:
SDL_LockMutex(Android_ActivityMutex); SDL_LockMutex(Android_ActivityMutex);
if (Android_Window) if (Android_Window)
@ -1001,21 +1005,27 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(JNIEnv *env,
SDL_VideoDevice *_this = SDL_GetVideoDevice(); SDL_VideoDevice *_this = SDL_GetVideoDevice();
SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata; SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata;
/* We have to clear the current context and destroy the egl surface here /* Wait for Main thread being paused and context un-activated to release 'egl_surface' */
* Otherwise there's BAD_NATIVE_WINDOW errors coming from eglCreateWindowSurface on resume if (! data->backup_done) {
* Ref: http://stackoverflow.com/questions/8762589/eglcreatewindowsurface-on-ics-and-switching-from-2d-to-3d 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) { if (data->egl_surface != EGL_NO_SURFACE) {
SDL_EGL_MakeCurrent(_this, NULL, NULL);
SDL_EGL_DestroySurface(_this, data->egl_surface); SDL_EGL_DestroySurface(_this, data->egl_surface);
data->egl_surface = EGL_NO_SURFACE; data->egl_surface = EGL_NO_SURFACE;
} }
if (data->native_window) { if (data->native_window) {
ANativeWindow_release(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 */ /* 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) { if (Android_Window) {
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeFocusChanged()"); __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeFocusChanged()");
SDL_SendWindowEvent(Android_Window, (hasFocus ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST), 0, 0); SDL_SendWindowEvent(Android_Window, (hasFocus ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST), 0, 0);
} }
SDL_UnlockMutex(Android_ActivityMutex); SDL_UnlockMutex(Android_ActivityMutex);
} }

View File

@ -68,6 +68,7 @@ android_egl_context_restore(SDL_Window *window)
event.type = SDL_RENDER_DEVICE_RESET; event.type = SDL_RENDER_DEVICE_RESET;
SDL_PushEvent(&event); SDL_PushEvent(&event);
} }
data->backup_done = 0;
} }
} }
@ -80,6 +81,7 @@ android_egl_context_backup(SDL_Window *window)
data->egl_context = SDL_GL_GetCurrentContext(); data->egl_context = SDL_GL_GetCurrentContext();
/* We need to do this so the EGLSurface can be freed */ /* We need to do this so the EGLSurface can be freed */
SDL_GL_MakeCurrent(window, NULL); SDL_GL_MakeCurrent(window, NULL);
data->backup_done = 1;
} }
} }

View File

@ -39,6 +39,7 @@ typedef struct
{ {
EGLSurface egl_surface; EGLSurface egl_surface;
EGLContext egl_context; /* We use this to preserve the context when losing focus */ EGLContext egl_context; /* We use this to preserve the context when losing focus */
SDL_bool backup_done;
ANativeWindow *native_window; ANativeWindow *native_window;
} SDL_WindowData; } SDL_WindowData;