We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 2041 - can't get SDL_QUIT event because Android onPause cause native stopped inside SDL_PollEvent
Summary: can't get SDL_QUIT event because Android onPause cause native stopped inside ...
Status: RESOLVED FIXED
Alias: None
Product: SDL
Classification: Unclassified
Component: events (show other bugs)
Version: 2.0.0
Hardware: ARM Android (All)
: P2 normal
Assignee: Gabriel Jacobo
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-08-15 12:14 UTC by Sany Liew
Modified: 2013-11-06 14:24 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sany Liew 2013-08-15 12:14:32 UTC
I am using SDL2 to play video on Android. My android app consist of normal/java activity which will intent/launch SDLActivity (extended as ElidSDL as below logcat). On SDLActivity, there is a quit button which has onClick event to call activity finish() for ElidSDL. When this quit button is clicked, SDLActivity will be closed, but after that, my normal/java activity can't response to any touch or buttons except home button.

From what I know is that, when the finish() event is called, SDLActivity will send some events to native which will then cause the SDL stop running inside SDL_PollEvent. The later coming event onDestroy will make SDL send quit event too but this event will never reach my native SDL_PollEvent (which will sense the SDL_QUIT) unless I use SDL_SetEventFilter. After onDestroy, Java SDLActivity will wait for native thread to be joined which forever fail because native still inside SDL_PollEvent. It looks like I must return the SDL_main else some nasty errors will popup before app is closed down, so I can't use SDL_SetEventFilter because the function I put in will be called outside the SDL_main.

finish() should not be used this way? Or any trick to use SDL_SetEventFilter to make SDL_main return?

Below is portion of my log cat output.
(NOTE: V/SDL(30623) is from SDLActivity)

08-15 23:45:29.033: V/SDL(30623): onPause()
08-15 23:45:29.033: V/SDL(30623): nativePause()
08-15 23:45:29.048: I/native(30623): window event 0x6
08-15 23:45:29.111: I/native(30623): window event 0xd
08-15 23:45:29.111: I/native(30623): window lost focus
08-15 23:45:29.205: I/native(30623): window event 0x7
08-15 23:45:29.205: I/native(30623): minimize - paused trigger
08-15 23:45:29.212: V/SDL(30623): onWindowFocusChanged(): false
08-15 23:45:29.228: I/native(30623): unknown event 0x103
08-15 23:45:29.377: V/ElidSDL(30623): video 0 STOP
08-15 23:45:29.377: V/SDL(30623): surfaceDestroyed()
08-15 23:45:29.377: D/OpenGLRenderer(30623): Flushing caches (mode 0)
08-15 23:45:29.478: V/SDL(30623): onDestroy()
08-15 23:45:29.478: I/native(30623): quit event received (using SDL_SetEventFilter)
Comment 2 Gabriel Jacobo 2013-08-22 14:21:50 UTC
In SDL_androidevents.c, you'll see a line:

if (SDL_HasEvent(SDL_WINDOWEVENT) || SDL_HasEvent(SDL_APP_WILLENTERBACKGROUND) || SDL_HasEvent(SDL_APP_DIDENTERBACKGROUND) ) {

If you add SDL_HasEvent(SDL_QUIT) there, does it solve the problem?
Comment 3 Sany Liew 2013-08-27 04:07:59 UTC
(In reply to Gabriel Jacobo from comment #2)
> In SDL_androidevents.c, you'll see a line:
> 
> if (SDL_HasEvent(SDL_WINDOWEVENT) ||
> SDL_HasEvent(SDL_APP_WILLENTERBACKGROUND) ||
> SDL_HasEvent(SDL_APP_DIDENTERBACKGROUND) ) {
> 
> If you add SDL_HasEvent(SDL_QUIT) there, does it solve the problem?

sorry for late reply. Actually I can't found what you mentioned. I am using SDL2.0.0 stable release version. I got it from:

http://www.libsdl.org/download-2.0.php

I downloaded again from same place after your comment but I still can't find what you mentioned. In fact inside SDL_androidevents.c only has following function:

void Android_PumpEvents(_THIS)
{
    /*
    ...
    ... inside here got SDL_SemWait, SDL_SemTryWait for
    ... Android_ResumeSem and Android_PauseSem
    ... the closest is below:
    ... */

    ...

#if SDL_ANDROID_BLOCK_ON_PAUSE
        if( isPausing || SDL_SemTryWait(Android_PauseSem) == 0 ) {
            /* We've been signaled to pause, but before we block ourselves, we need to make sure that
            SDL_WINDOWEVENT_FOCUS_LOST and SDL_WINDOWEVENT_MINIMIZED have reached the app */
            if (SDL_HasEvent(SDL_WINDOWEVENT)) {
                isPausing = 1;
            }
            else {
                isPausing = 0;
                isPaused = 1;
            }
        }
#else

    ...

}

Should I add into this and only this if (SDL_HasEvent(SDL_WINDOWEVENT)) ?
Comment 4 Gabriel Jacobo 2013-08-27 13:05:04 UTC
Yep, add it there and let me know if that solves the problem. Thanks!
Comment 5 Denis Bernard 2013-10-08 14:19:30 UTC
What actually happens is that when SDLActivity.onDestroy() is called, either because the OS kills the app or following a call to SDLActivity.finish(), the SDL_QUIT message sent by Java_org_libsdl_app_SDLActivity_nativeQuit() never makes it to the event loop in the user code.

I've tried with your suggested change, adding SDL_HasEvent(SDL_QUIT) in SDL_androidevents.c, but it doesn't help at all.

The easiest way to test this is to make a barebones app that does not handle screen orientation changes (i.e. don't put any android:configChanges in the AndroidManifest.xml). Android will try kill the app then restart it when you change the screen orientation.
Comment 6 Denis Bernard 2013-10-08 15:37:47 UTC
Found the root cause of this: When the activity is "killed" either by a call to SDLActivity.finish() or by the OS, the OS calls in order:

onPause() --> this freezes the event loop
onDestroy() --> which sends the SDL_QUIT event, never received because of the frozen event loop.
Comment 7 Denis Bernard 2013-10-08 16:59:34 UTC
More on my previous comment:

This actually happens when SDL_ANDROID_BLOCK_ON_PAUSE is enabled. After onPause(), the event loop is frozen in Android_PumpEvents(), waiting on Android_ResumeSem().

A potential fix is to change Java_org_libsdl_app_SDLActivity_nativeQuit like so:

void Java_org_libsdl_app_SDLActivity_nativeQuit(
                                    JNIEnv* env, jclass cls)
{
    /* Discard previous events. The user should have handled state storage
     * in SDL_APP_WILLENTERBACKGROUND. After nativeQuit() is called, no
     * events other than SDL_QUIT and iSDL_APP_TERMINATING should fire */
    SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
    /* Inject a SDL_QUIT event */
    SDL_SendQuit();
    SDL_SendAppEvent(SDL_APP_TERMINATING);
    /* Resume the event loop so that the app can catch SDL_QUIT which
     * should now be the top event in the event queue. */
    if (!SDL_SemValue(Android_ResumeSem)) SDL_SemPost(Android_ResumeSem);
}

Actually, the intent is to push an SDL_QUIT event on top of the event queue so that when Android_PumpEvents() resumes, the first event returned by Poll/WaitEvent is our SDL_QUIT message. This should work as long as no other thread pushes events other than the java thread calling nativeQuit().

Also, when SDL_SemWait(Android_ResumeSem) returns, android_egl_context_restore() is called. Although it doesn't seem to cause any issues, this should probably be skipped in this case.
Comment 8 Gabriel Jacobo 2013-10-08 21:07:13 UTC
Is flushing the events required? Doesn't sticking:

if (!SDL_SemValue(Android_ResumeSem)) SDL_SemPost(Android_ResumeSem);

in Java_org_libsdl_app_SDLActivity_nativeQuit solve the issue?
Comment 9 Denis Bernard 2013-10-09 12:56:43 UTC
If the event queue is a FIFO, we have to make sure that when Android_PumpEvents() returns, SDL_QUIT will be the first event returned by the caller (SDL_WaitForEventTimeout()).

Otherwise, if any events came in between onPause() and onDestroy(), the app may try to paint stuff on an invalid GL surface (which should have been invalidated at this point) before getting to the SDL_QUIT event.

Given the way the Android/SDL apps are designed, I'm not sure if this can happen though (a user thread posting events? some input/audio thread?).
Comment 10 Gabriel Jacobo 2013-11-06 14:24:09 UTC
Fixed, thanks guys!http://hg.libsdl.org/SDL/rev/261addaa47d0