Skip to content

Commit

Permalink
Android: prevents rare crashes when app goes to background or ends.
Browse files Browse the repository at this point in the history
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)
  #1  pc 000000000000c7f4  /vendor/lib64/egl/eglSubDriverAndroid.so (EglAndroidWindowSurface::UpdateBufferList(ANativeWindowBuffer*)+284)
  #2  pc 000000000000c390  /vendor/lib64/egl/eglSubDriverAndroid.so (EglAndroidWindowSurface::DequeueBuffer()+240)
  #3  pc 000000000000bb10  /vendor/lib64/egl/eglSubDriverAndroid.so (EglAndroidWindowSurface::GetBuffer(EglSubResource*, EglMemoryDesc*)+64)
  #4  pc 000000000032732c  /vendor/lib64/egl/libGLESv2_adreno.so (EglWindowSurface::UpdateResource(EsxContext*)+116)
  #5  pc 0000000000326dd0  /vendor/lib64/egl/libGLESv2_adreno.so (EglWindowSurface::GetResource(EsxContext*, EsxResource**, EsxResource**, int)+56)
  #6  pc 00000000002ae484  /vendor/lib64/egl/libGLESv2_adreno.so (EsxContext::AcquireBackBuffer(int)+364)
  #7  pc 0000000000249680  /vendor/lib64/egl/libGLESv2_adreno.so (EsxContext::Clear(unsigned int, unsigned int, unsigned int, EsxClearValues*)+1800)
  #8  pc 00000000002cb52c  /vendor/lib64/egl/libGLESv2_adreno.so (EsxGlApiParamValidate::GlClear(EsxDispatch*, unsigned int)+132)
  • Loading branch information
1bsyl committed Jan 17, 2020
1 parent d52ba78 commit 005e2df
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 9 deletions.
28 changes: 19 additions & 9 deletions src/core/android/SDL_android.c
Expand Up @@ -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) {
Expand All @@ -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));
Expand Down Expand Up @@ -994,28 +994,38 @@ 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)
{
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 */
}
Expand Down Expand Up @@ -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);
}
Expand Down
2 changes: 2 additions & 0 deletions src/video/android/SDL_androidevents.c
Expand Up @@ -68,6 +68,7 @@ android_egl_context_restore(SDL_Window *window)
event.type = SDL_RENDER_DEVICE_RESET;
SDL_PushEvent(&event);
}
data->backup_done = 0;
}
}

Expand All @@ -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;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/video/android/SDL_androidwindow.h
Expand Up @@ -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;
Expand Down

0 comments on commit 005e2df

Please sign in to comment.