From dc263450ff4b3c8814e54e84d74865bdf84dee83 Mon Sep 17 00:00:00 2001 From: Sylvain Becker Date: Mon, 14 Jan 2019 23:33:48 +0100 Subject: [PATCH] Android: create Pause/ResumeSem semaphore at higher level than CreateWindow() - If you call onPause() before CreateWindow(), SDLThread will run in infinite loop in background. - If you call onPause() between a DestroyWindow() and a new CreateWindow(), semaphores are invalids. SDLActivity.java: the first resume() starts the SDLThread, don't call nativeResume() as it would post ResumeSem. And the first pause would automatically be resumed. --- .../main/java/org/libsdl/app/SDLActivity.java | 8 +++- src/core/android/SDL_android.c | 44 ++++++++++++++----- src/video/android/SDL_androidwindow.c | 7 --- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 28060296e721f..7e4f363d80200 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -505,10 +505,14 @@ public static void handleNativeState() { mSDLThread = new Thread(new SDLMain(), "SDLThread"); mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true); mSDLThread.start(); + + // No nativeResume(), don't signal Android_ResumeSem + mSurface.handleResume(); + } else { + nativeResume(); + mSurface.handleResume(); } - nativeResume(); - mSurface.handleResume(); mCurrentNativeState = mNextNativeState; } } diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index b7e1947180bec..c6795f03ffc8c 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -439,6 +439,17 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl __android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_ActivityMutex mutex"); } + + Android_PauseSem = SDL_CreateSemaphore(0); + if (Android_PauseSem == NULL) { + __android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_PauseSem semaphore"); + } + + Android_ResumeSem = SDL_CreateSemaphore(0); + if (Android_ResumeSem == NULL) { + __android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_ResumeSem semaphore"); + } + mActivityClass = (jclass)((*env)->NewGlobalRef(env, cls)); midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass, @@ -961,6 +972,16 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeQuit)( Android_ActivityMutex = NULL; } + if (Android_PauseSem) { + SDL_DestroySemaphore(Android_PauseSem); + Android_PauseSem = NULL; + } + + if (Android_ResumeSem) { + SDL_DestroySemaphore(Android_ResumeSem); + Android_ResumeSem = NULL; + } + str = SDL_GetError(); if (str && str[0]) { __android_log_print(ANDROID_LOG_ERROR, "SDL", "SDLActivity thread ends (error=%s)", str); @@ -982,14 +1003,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePause)( SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0); SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND); SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND); - - /* *After* sending the relevant events, signal the pause semaphore - * so the event loop knows to pause and (optionally) block itself. - * Sometimes 2 pauses can be queued (eg pause/resume/pause), so it's - * always increased. */ - SDL_SemPost(Android_PauseSem); } + /* *After* sending the relevant events, signal the pause semaphore + * so the event loop knows to pause and (optionally) block itself. + * Sometimes 2 pauses can be queued (eg pause/resume/pause), so it's + * always increased. */ + SDL_SemPost(Android_PauseSem); + SDL_UnlockMutex(Android_ActivityMutex); } @@ -1006,13 +1027,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeResume)( SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND); SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0); SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0); - /* Signal the resume semaphore so the event loop knows to resume and restore the GL Context - * We can't restore the GL Context here because it needs to be done on the SDL main thread - * and this function will be called from the Java thread instead. - */ - SDL_SemPost(Android_ResumeSem); } + /* Signal the resume semaphore so the event loop knows to resume and restore the GL Context + * We can't restore the GL Context here because it needs to be done on the SDL main thread + * and this function will be called from the Java thread instead. + */ + SDL_SemPost(Android_ResumeSem); + SDL_UnlockMutex(Android_ActivityMutex); } diff --git a/src/video/android/SDL_androidwindow.c b/src/video/android/SDL_androidwindow.c index 638eef3c84404..5e34c284a97e4 100644 --- a/src/video/android/SDL_androidwindow.c +++ b/src/video/android/SDL_androidwindow.c @@ -49,9 +49,6 @@ Android_CreateWindow(_THIS, SDL_Window * window) goto endfunction; } - Android_PauseSem = SDL_CreateSemaphore(0); - Android_ResumeSem = SDL_CreateSemaphore(0); - /* Set orientation */ Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS)); @@ -171,10 +168,6 @@ Android_DestroyWindow(_THIS, SDL_Window *window) if (window == Android_Window) { Android_Window = NULL; - if (Android_PauseSem) SDL_DestroySemaphore(Android_PauseSem); - if (Android_ResumeSem) SDL_DestroySemaphore(Android_ResumeSem); - Android_PauseSem = NULL; - Android_ResumeSem = NULL; if (window->driverdata) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata;