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 3831 - Android terminates SDL2 application when using the power button while it's active and related power management problems?
Summary: Android terminates SDL2 application when using the power button while it's ac...
Status: RESOLVED INVALID
Alias: None
Product: SDL
Classification: Unclassified
Component: events (show other bugs)
Version: 2.0.5
Hardware: x86 Windows 10
: P1 normal
Assignee: Sam Lantinga
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-09-15 14:15 UTC by superfury
Modified: 2017-09-19 10:07 UTC (History)
1 user (show)

See Also:


Attachments
Input of my emulator, which crashes when it's turned to standby(or during resume after standby). (146.92 KB, text/plain)
2017-09-15 14:15 UTC, superfury
Details

Note You need to log in before you can comment on or make changes to this bug.
Description superfury 2017-09-15 14:15:52 UTC
Created attachment 2946 [details]
Input of my emulator, which crashes when it's turned to standby(or during resume after standby).

When I use the power button on my Samsung Galaxy S7 while my SDL2 app is running(which turns off the screen) and click it again(entering the screen lock protection, if required), then my SDL2 application is terminated? Is some required processing missing(it's an emulator that's running), or is there a bug in SDL2?

An event filter is set up that redirects all specific events to my main thread(locking it temporarily):

*** START OF CODE ***
int SDLCALL myEventFilter(void *userdata, SDL_Event * event)
{
	//Emergency calls! Immediately update!
	switch (event->type) //Emergency event?
	{
		case SDL_APP_TERMINATING: //Terminating the application by the OS?
	
		case SDL_APP_LOWMEMORY: //Low on memory?
		case SDL_APP_DIDENTERBACKGROUND: //Are we pushed to the background?
		case SDL_APP_WILLENTERBACKGROUND: //Are we pushing to the background?
		case SDL_APP_WILLENTERFOREGROUND: //Are we pushing to the foreground?
		case SDL_APP_DIDENTERFOREGROUND: //Are we pushed to the foreground?
			updateInput(event); //Handle this immediately!
		return 1; //Drop the event, as this is handled already!
	}
	// etc
	return 0; //Handle normally, as a normal event!
}
*** END OF CODE ***

The main input code(which runs from the main thread, as well as from the event handler directly(the updateInput function call)) handles the event, when it's received(ignoring the SDL_APP_LOWMEMORY event, as nothing can be cleaned up on emulated objects(which would screw up the emulator)):

*** START OF CODE ***
	//Misc system events
	case SDL_QUIT: //Quit?
	#ifdef SDL2
	#ifdef ANDROID
	case SDL_APP_TERMINATING: //Terminating the application by the OS?
	
	//case SDL_APP_LOWMEMORY: //Low on memory?
		#ifdef NDK_PROFILE
			monpendingcleanup(); //Process any pending cleanup when needed!
		#endif
	#endif
	#endif
		quitting:
		lock(LOCK_INPUT);
		if (joystick) //Gotten a joystick connected?
		{
			SDL_JoystickClose(joystick); //Finish our joystick: we're not using it anymore!
			joystick = NULL; //No joystick connected anymore!
		}
		EMU_Shutdown(1); //Request a shutdown!
		unlock(LOCK_INPUT);
		break;
	#ifndef SDL2
	case SDL_ACTIVEEVENT: //Window event?
		lock(LOCK_INPUT);
		if (event->active.state&SDL_APPMOUSEFOCUS)
		{
			hasmousefocus = event->active.gain; //Do we have mouse focus?
		}
		if (event->active.state&SDL_APPINPUTFOCUS) //Gain/lose keyboard focus?
		{
			hasinputfocus = event->active.gain; //Do we have input focus?
		}
		if (event->active.state&SDL_APPACTIVE) //Iconified/Restored?
		{
			haswindowactive = (haswindowactive&~1)|(event->active.gain?1:0); //0=Iconified, 1=Restored.
		}
		unlock(LOCK_INPUT);
		break;
	#else
	case SDL_WINDOWEVENT: //SDL2 window event!
		switch (event->window.event) //What event?
		{
			case SDL_WINDOWEVENT_MINIMIZED:
				lock(LOCK_INPUT);
				haswindowactive &= ~1; //Iconified!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_RESTORED:
				lock(LOCK_INPUT);
				haswindowactive |= 1; //Restored!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_FOCUS_GAINED:
				lock(LOCK_INPUT);
				hasinputfocus = 1; //Input focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_FOCUS_LOST:
				lock(LOCK_INPUT);
				hasinputfocus = 0; //Lost input focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_ENTER:
				lock(LOCK_INPUT);
				hasmousefocus = 1; //Mouse focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_LEAVE:
				lock(LOCK_INPUT);
				hasmousefocus = 0; //Lost mouse focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_CLOSE:
				goto quitting; //We're redirecting to the SDL_QUIT event!
				break;
			default: //Unknown event?
				break;
		}
		break;
	case SDL_APP_DIDENTERBACKGROUND: //Are we pushed to the background?
	case SDL_APP_WILLENTERBACKGROUND: //Are we pushing to the background?
		lock(LOCK_INPUT);
		haswindowactive &= ~6; //We're iconified! This also prevents drawing and audio output! This is critical!
		haswindowactive |= 0x8; //Discard any future time!
		unlock(LOCK_INPUT);
		break;
	case SDL_APP_WILLENTERFOREGROUND: //Are we pushing to the foreground?
		break; //Unhandled!
	case SDL_APP_DIDENTERFOREGROUND: //Are we pushed to the foreground?
		lock(LOCK_INPUT);
		haswindowactive |= 6; //We're not iconified! This also enables drawing and audio output!
		lock(LOCK_GPU);
		request_render = 1; //Requesting for rendering once!
		unlock(LOCK_GPU);
		unlock(LOCK_INPUT);
		break;
	#ifdef ANDROID
	case SDL_WINDOWEVENT_SIZE_CHANGED: //Orientation changed?
		lock(LOCK_GPU); //Lock the GPU!
		lock(LOCK_VIDEO); //Lock the video output!
		window_xres = window_yres = 0; //We're autodetecting the new resolution!
		GPU.forceRedraw = 1; //We're forcing a full redraw next frame to make sure the screen is always updated nicely!
		needvideoupdate = 1; //We need a video update!
		unlock(LOCK_VIDEO); //We're done with video!
		unlock(LOCK_GPU); //We're finshed with the GPU!
		break;
	#endif
*** END OF CODE ***

The haswindowactive has different flags, which prevent the app itself from doing various kinds of updates:
- Basic emulation is paused when minimized/iconified(or put on pause when put on background on Android event).
- Bits 0&1 need to be set to update video(prevents invalid video updates when not allowed).
- Bit 2 mutes audio output(although the buffer is filled with silent samples(zeroes).
- Bits 2/3/4(being pending resume/pause state) combined pauses emulation.
- Recording being paused/resumed is handled through bit 4 only.

Even with all this implemented, when I press the power button on my Android device(only when the app is active, but not when it's in the background) and click it again later(to turn the device on again and to resume emulation(after entering the screen lock, if required)), the application is terminated by the Android OS? Clicking it again restarts the app entirely?
Comment 1 Sylvain 2017-09-15 19:18:42 UTC
your app stop ? does it crash ? or is destroyed normally ? 

you could add to you AndroidManifest.xml, for your activity : 
 android:alwaysRetainTaskState="true"
 and also android:launchMode="singleInstance"
Comment 2 superfury 2017-09-16 11:32:59 UTC
(In reply to Sylvain from comment #1)
> your app stop ? does it crash ? or is destroyed normally ? 
> 
> you could add to you AndroidManifest.xml, for your activity : 
>  android:alwaysRetainTaskState="true"
>  and also android:launchMode="singleInstance"

Just added those to the activity in the androidmanifest.xml, but it still stops the application when the device is put in standby while the application is running.

I now notice that, even when the device is put to turn off the screen while locked using the power button, the application continues to produce sound, so it's still running the emulation, instead of silencing it(because it's put to the background that disables all those and pauses emulation(the SDL_APP_WILLENTERBACKGROUND event))?
Comment 3 superfury 2017-09-16 11:54:22 UTC
(In reply to superfury from comment #2)
> (In reply to Sylvain from comment #1)
> > your app stop ? does it crash ? or is destroyed normally ? 
> > 
> > you could add to you AndroidManifest.xml, for your activity : 
> >  android:alwaysRetainTaskState="true"
> >  and also android:launchMode="singleInstance"
> 
> Just added those to the activity in the androidmanifest.xml, but it still
> stops the application when the device is put in standby while the
> application is running.
> 
> I now notice that, even when the device is put to turn off the screen while
> locked using the power button, the application continues to produce sound,
> so it's still running the emulation, instead of silencing it(because it's
> put to the background that disables all those and pauses emulation(the
> SDL_APP_WILLENTERBACKGROUND event))?

Those don't help. The old behaviour is still there:
- When the application is paused by returning to the main Android screen(by pressing the Home button) will pause the application and mute audio output. It can then be put in standby by using the Power button and turned on and clicking the application makes it resume the emulation where it left off.
- When the application isn't paused by returning to the main Android screen(not pressing the Home button) and using the Power button to put it in standby, the application keeps running and doesn't mute audio(thus the WILLENTERBACKGROUND event never fires). The application keeps running and generate sound while it's in Standby. When the application is resumed by clicking the Power button again, it seems to crash?

I'll add some logging of the background states to my those events to see what's happening...
Comment 4 Sylvain 2017-09-16 12:35:49 UTC
Seems strange, do you have the latest SDL2 version, and also the latest SDLActivity.java ?

I also have a S7 and when I press the power button, while the application is running, I get: 

onPause()
nativePause()
SDL_APP_WILLENTERBACKGROUND
SDL_APP_DIDENTERBACKGROUND

I get those events by using SDL_PollEvent

( but you can also get them via SDL_AddEventWatch())
Comment 5 superfury 2017-09-16 12:37:21 UTC
These are the state changes (foreground/background/close states) that happen during my various testcases:

Standby,Poweron(returns to main Android screen):
*** START ***
00:00:04:34.06077: willenterbackground
00:00:04:34.06502: willenterbackground
00:00:04:34.06786: didenterbackground
00:00:04:34.07144: willenterbackground
00:00:04:34.07274: didenterbackground
00:00:04:34.07435: willenterbackground
00:00:04:36.04639: quitting
00:00:04:36.04906: quitting
00:00:04:36.05040: quitting
*** END ***

Background, Standby, Poweron, Foreground, Background, Close
*** START ***
00:00:08:74.07397: willenterbackground
00:00:08:74.08608: didenterbackground
00:00:08:74.09104: willenterbackground
00:00:08:74.09654: willenterbackground
00:00:08:74.09880: didenterbackground
00:00:08:74.09989: willenterbackground
00:00:21:07.02784: willenterforeground
00:00:21:07.03552: didenterforeground
00:00:21:07.05816: willenterforeground
00:00:21:07.06040: didenterforeground
00:00:28:06.01736: willenterbackground
00:00:28:06.01996: didenterbackground
00:00:28:06.02256: willenterbackground
00:00:28:06.07744: willenterbackground
00:00:28:06.07936: didenterbackground
00:00:28:06.08060: willenterbackground
*** END ***

Background, Foreground, Background, Close
*** START ***
00:00:08:37.09773: willenterbackground
00:00:08:38.00234: didenterbackground
00:00:08:38.00348: willenterbackground
00:00:08:38.00995: willenterbackground
00:00:08:38.01170: didenterbackground
00:00:08:38.01295: willenterbackground
00:00:11:55.02128: willenterforeground
00:00:11:55.02741: didenterforeground
00:00:11:55.04264: willenterforeground
00:00:11:55.04453: didenterforeground
00:00:14:89.09511: willenterbackground
00:00:14:89.09700: didenterbackground
00:00:14:89.09815: willenterbackground
00:00:14:89.09986: willenterbackground
00:00:14:90.00132: didenterbackground
00:00:14:90.00233: willenterbackground
*** END ***

Background/Foreground is done by Minimizing/Restoring, Close is closing the App from Android main menu(task manager), Standby is pressing the power button to turn screen off, Poweron is the reverse of Standby(pressing the power button to restore Android to poweron mode).
Comment 6 Sylvain 2017-09-16 12:57:49 UTC
So which portion of log represents the state "foreground" + transition  "pressing the power button" ? 

You seemed to say that you did not have the SDL_APP_WILLENTERBACKGROUND ? Can  you put a SDL_Log in your "myEventFilter" ?

Maybe your app is multi threaded and blocked by your lock() / unlock() ?
Comment 7 superfury 2017-09-16 13:23:13 UTC
All those logs start out with the application being started normally(thus on the foreground). The big time gaps of at least 0.5 second are the seperators for each action. The only locking on the logging itself is the logging of a single entry(or timed entry). So the locks that are shown in the code given are the locks that are used, while the logging happens right at the start of the case statement(e.g. directly below "case SDL_APP_DIDENTERBACKGROUND: //Are we pushed to the background?" ). Otherwise, the statements are unmodified. The logging function that's called(dolog) has it's own lock to prevent the same logging file from being used by multiple threads at once, which will be corrupting the logging file if not locked.

Yes, the application is multi-threaded, but SDL events are only handled in the main thread(and the event filter's thread for those specific Android cases).
Comment 8 superfury 2017-09-16 13:25:43 UTC
Also, the version I'm using is the SDL 2.0.5 version from libsdl.org (https://libsdl.org/release/SDL2-2.0.5.zip ).
Comment 9 Sylvain 2017-09-16 13:42:40 UTC
So according to your log, you correctly receive the event WILL_ENTERBACKGROUND
but immediately after, you are also receiving SDL_APP_TERMINATING (state=quitting).
On android, this event only happens when onDestroy() is called.

in addition to 
        android:alwaysRetainTaskState="true"
        android:launchMode="singleInstance"

I use in AndroidManifest.xml, something like this:
        android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale|uiMode|screenSize|smallestScreenSize">


If that does not solve your issue, I would: 
- update to latest version of SDL2
- try one of the SDL test app
Comment 10 superfury 2017-09-16 14:00:19 UTC
I've replaced the configchanges with the line you've provided. It now properly resumes after going to standby and returning from it. But for some unknown reason, it still continues to produce sound and run the emulation when it's put in standby(as it did with those two task state/launch mode settings)?
Comment 11 superfury 2017-09-16 14:14:57 UTC
I've removed those two settings, while leaving your version of the configChanges intact. It now won't crash anymore with any of those situations, but it won't mute the sound or pause the application(through haswindowactive) when it's put in standby while the application is still activated(so essentially, it's stuck in the foreground unless the user minimizes it using the home button)?
Comment 12 Sylvain 2017-09-16 14:28:32 UTC
You should mute and stop using the renderer as soon as you have the ENTERBACKGROUND event. So, this is within your app now.

can you identify which of the "configChange" parameter is mandatory ?
Comment 13 superfury 2017-09-16 14:33:20 UTC
I originally only had two of them in my config: "keyboardHidden|orientation", which are required for the on-screen keyboard and orientation(which is always landscape(will crash on portrait due to unused handling(though I'll never use that, since the screen would be much too small and problems with reallocating many emulation structures). One or more of those configuration changes you've given fixes the problem with the standby mode, but I don't know which one.
Comment 14 superfury 2017-09-16 14:57:13 UTC
I've reduced the config to at least(while keeping it running without crashing): "touchscreen|keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize". I don't know how many more I can safely remove without making the application crash. Although orientation changes isn't supported(it's locked to landscape(portrait would make it unusable, due to the very small width, which is required for readability of on-screen text(both the application itself and the emulated system's display))).
Comment 15 Sylvain 2017-09-16 19:21:10 UTC
and if only put :
android:configChanges="keyboardHidden|orientation|screenSize"
like in the repository ?
Comment 16 superfury 2017-09-17 19:28:01 UTC
Just changed the config. Everything still works without crashing. It continues to run in standby still(not backgrounded at all; using vanilla SDL2.0.5 from libsdl.org)?
Comment 17 Sylvain 2017-09-18 07:37:56 UTC
And you still got events : 
SDL_APP_WILLENTERBACKGROUND / SDL_APP_DIDENTERBACKGROUND ?

Put logs into your code to check that you mute the audio ?
Comment 18 superfury 2017-09-18 09:04:24 UTC
Receiving either of those two events WILL cause the application to mute audio that's rendering and pause the processing within the app(because of the resulting bits in the haswindowactive). So it's clearly either receiving those and receiving an foreground message right after that(which will resume the application and audio output) or not receiving it at all.
Comment 19 superfury 2017-09-18 09:15:10 UTC
This is the log it's producing:

00:00:10:44.01183: willenterbackground(or didenterbackground ^ passthrough)
00:00:10:44.02597: didenterbackground
00:00:10:44.02732: willenterbackground(or didenterbackground ^ passthrough)
00:00:10:44.02874: willenterbackground(or didenterbackground ^ passthrough)
00:00:10:44.03026: didenterbackground
00:00:10:44.03154: willenterbackground(or didenterbackground ^ passthrough)
00:00:10:89.01034: willenterforeground
00:00:10:89.01518: didenterforeground
00:00:10:89.02244: willenterforeground
00:00:10:89.02466: didenterforeground
00:00:22:88.09172: willenterbackground(or didenterbackground ^ passthrough)
00:00:22:89.00360: didenterbackground
00:00:22:89.00824: willenterbackground(or didenterbackground ^ passthrough)
00:00:22:89.01182: willenterbackground(or didenterbackground ^ passthrough)
00:00:22:89.01372: didenterbackground
00:00:22:89.01500: willenterbackground(or didenterbackground ^ passthrough)
00:00:25:58.00428: quitting


I've just opened the application, waited for the main execution loop to start, then put it in standby, wait a little bit of time, turn it on, minimized and closed.
Comment 20 superfury 2017-09-18 09:24:39 UTC
It handles pausing properly when it's minimized(deactivated) normally using the home button etc. Only during the standby it keeps running for some unknown reason?

The pause is handled at various points in execution:

- Main execution loop:
*** START CODE ***
	lock(LOCK_INPUT);
	if (unlikely((haswindowactive&0x1C)==0xC)) {getnspassed(&CPU_timing); haswindowactive|=0x10;} //Pending to finish Soundblaster!
	currenttiming += likely(haswindowactive&2)?getnspassed(&CPU_timing):0; //Check for any time that has passed to emulate! Don't emulate when not allowed to run, keeping emulation paused!
	unlock(LOCK_INPUT);
*** END CODE ***

Video resolution update check:
*** START CODE ***
	if (needvideoupdate && ((haswindowactive&3)==3)) //We need to update the screen resolution and we're not hidden (We can't update the Window resolution correctly when we're hidden)?
*** END CODE ***

Frame rendering:
*** START CODE ***
		if ((haswindowactive&3)==3) //Are we even visible and allowed to update?
		{
			safeFlip(rendersurface); //Set the new resized screen to use, if possible!
		}
*** END CODE ***

Sound sample rendering:
*** START CODE ***
		if ((haswindowactive&4)==0) //Not to sound audio?
		{
			result_l = result_r = 0; //Mute audio!
		}
*** END CODE ***

Handling at the end of the main loop to continue properly:
*** START CODE ***
		if (unlikely((haswindowactive&0x38)==0x38)) {haswindowactive &= ~0x38;} //Fully active again?
*** END CODE ***

Sound Blaster sample recording(recording ):
*** START CODE ***
	soundblaster_recordedpassed = getnspassed(&SOUNDBLASTER.recordingtimer); //Tick the recording timer real-time!
	if (unlikely(haswindowactive&0x10)) {soundblaster_recordedpassed = 0.0; haswindowactive |= ~0x20;} //Fully active again?
*** END CODE ***

That's all the code that has anything directly to do with the minimized/maximized/pause/mute status.
Comment 21 Sylvain 2017-09-18 09:27:56 UTC
According to your log  you have multiple time the "willenterbackground" event and this is strange.

I suggest you to update to the latest SDL2 code and try again.
Comment 22 superfury 2017-09-18 12:24:26 UTC
I've updated SDL2 to the latest code from hg.libsdl.org/SDL, but the problem is still there?

*** START OF LOG ***
00:00:07:62.01398: willenterbackground
00:00:07:62.01806: didenterbackground
00:00:07:62.02168: willenterbackground
00:00:07:62.02330: didenterbackground
00:00:16:28.04180: willenterforeground
00:00:16:28.04823: didenterforeground
00:00:16:28.06510: willenterforeground
00:00:16:28.06901: didenterforeground
00:00:17:76.01956: willenterbackground
00:00:17:76.02138: didenterbackground
00:00:17:76.02364: willenterbackground
00:00:17:76.02524: didenterbackground
00:00:19:66.01476: quitting
*** END OF LOG ***

This is opening the app, at 7.62 seconds standby, wait some seconds, turn the device on again, minimizing the app, close the app.

I've modified the logging a bit to skip the duplicate willenterbackground after the didenterbackground by jumping around it in the case above it.

*** START CODE ***
	//Misc system events
	case SDL_QUIT: //Quit?
	#ifdef SDL2
	#ifdef ANDROID
	case SDL_APP_TERMINATING: //Terminating the application by the OS?
	
	//case SDL_APP_LOWMEMORY: //Low on memory?
		#ifdef NDK_PROFILE
			monpendingcleanup(); //Process any pending cleanup when needed!
		#endif
	#endif
	#endif
		quitting:
		dolog("Android","quitting");
		lock(LOCK_INPUT);
		if (joystick) //Gotten a joystick connected?
		{
			SDL_JoystickClose(joystick); //Finish our joystick: we're not using it anymore!
			joystick = NULL; //No joystick connected anymore!
		}
		EMU_Shutdown(1); //Request a shutdown!
		unlock(LOCK_INPUT);
		break;
	#ifndef SDL2
	case SDL_ACTIVEEVENT: //Window event?
		lock(LOCK_INPUT);
		if (event->active.state&SDL_APPMOUSEFOCUS)
		{
			hasmousefocus = event->active.gain; //Do we have mouse focus?
		}
		if (event->active.state&SDL_APPINPUTFOCUS) //Gain/lose keyboard focus?
		{
			hasinputfocus = event->active.gain; //Do we have input focus?
		}
		if (event->active.state&SDL_APPACTIVE) //Iconified/Restored?
		{
			haswindowactive = (haswindowactive&~1)|(event->active.gain?1:0); //0=Iconified, 1=Restored.
		}
		unlock(LOCK_INPUT);
		break;
	#else
	case SDL_WINDOWEVENT: //SDL2 window event!
		switch (event->window.event) //What event?
		{
			case SDL_WINDOWEVENT_MINIMIZED:
				lock(LOCK_INPUT);
				haswindowactive &= ~1; //Iconified!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_RESTORED:
				lock(LOCK_INPUT);
				haswindowactive |= 1; //Restored!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_FOCUS_GAINED:
				lock(LOCK_INPUT);
				hasinputfocus = 1; //Input focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_FOCUS_LOST:
				lock(LOCK_INPUT);
				hasinputfocus = 0; //Lost input focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_ENTER:
				lock(LOCK_INPUT);
				hasmousefocus = 1; //Mouse focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_LEAVE:
				lock(LOCK_INPUT);
				hasmousefocus = 0; //Lost mouse focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_CLOSE:
				goto quitting; //We're redirecting to the SDL_QUIT event!
				break;
			default: //Unknown event?
				break;
		}
		break;
	case SDL_APP_DIDENTERBACKGROUND: //Are we pushed to the background?
		dolog("Android","didenterbackground");
		goto willenterbackground;
	case SDL_APP_WILLENTERBACKGROUND: //Are we pushing to the background?
		dolog("Android","willenterbackground");
		willenterbackground:
		lock(LOCK_INPUT);
		haswindowactive &= ~6; //We're iconified! This also prevents drawing and audio output! This is critical!
		haswindowactive |= 0x8; //Discard any future time!
		unlock(LOCK_INPUT);
		break;
	case SDL_APP_WILLENTERFOREGROUND: //Are we pushing to the foreground?
		dolog("Android","willenterforeground");
		break; //Unhandled!
	case SDL_APP_DIDENTERFOREGROUND: //Are we pushed to the foreground?
		dolog("Android","didenterforeground");
		lock(LOCK_INPUT);
		haswindowactive |= 6; //We're not iconified! This also enables drawing and audio output!
		lock(LOCK_GPU);
		request_render = 1; //Requesting for rendering once!
		unlock(LOCK_GPU);
		unlock(LOCK_INPUT);
		break;
	#ifdef ANDROID
	case SDL_WINDOWEVENT_SIZE_CHANGED: //Orientation changed?
		lock(LOCK_GPU); //Lock the GPU!
		lock(LOCK_VIDEO); //Lock the video output!
		window_xres = window_yres = 0; //We're autodetecting the new resolution!
		GPU.forceRedraw = 1; //We're forcing a full redraw next frame to make sure the screen is always updated nicely!
		needvideoupdate = 1; //We need a video update!
		unlock(LOCK_VIDEO); //We're done with video!
		unlock(LOCK_GPU); //We're finshed with the GPU!
		break;
	#endif
*** END CODE ***
Comment 23 Sylvain 2017-09-18 12:55:22 UTC
Ok! So there first 4 lines :

00:00:07:62.01398: willenterbackground
00:00:07:62.01806: didenterbackground
00:00:07:62.02168: willenterbackground
00:00:07:62.02330: didenterbackground

do you think you receive the event twice ? this is still strange.
Maybe because you have an EventWatch + you are polling the events ?

Anyway, you don't receive any put to foreground. 
So nothing re-activate the audio !

Could it be that, when you receive an enter_background event, you forward it to another thread, which is not fast enough to process it ? so the audio remains activated ?

Also, there is a android compilation flag in SDL2 "BLOCK_ON_PAUSE". Do  you have the compilation by default or do you modify this flag ?
Comment 24 superfury 2017-09-19 09:16:53 UTC
I haven't added any other flags, except some runtime flags:

*** START CODE ***
	#ifdef SDL2
	SDL_AddEventWatch(myEventFilter, NULL); //For applying critical updates!
	#ifdef SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4
		SDL_SetHintWithPriority(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4,"1",SDL_HINT_OVERRIDE); //We're forcing the window not to quit on ALT-F4!
	#endif
	#ifdef SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH
		SDL_SetHintWithPriority(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH,"1",SDL_HINT_OVERRIDE); //We're forcing us to use seperate mouse and touch events!
	#endif
	#endif
*** END CODE ***

So those hints aren't set up at all in my code.

The events are supposed to be handled by updateInput, which (in the case of those specific Android inputs) should be handled in the myEventFilter function(which redirects to the updateInput function in the same thread). It also returns 1, which should prevent the event from bubbling up to the main thread's updateInput handling(thus be handled twice)?

Wait a sec.... *looks at the filter and SDL documentation again* ... Whoops. The filter has it's filtering backwards indeed: it returns 1 for the Android filters(which means it adds it to the queue for the main thread to process again). Othersise, it returns 0(which will drop the event).

https://wiki.libsdl.org/SDL_SetEventFilter

That literally says:
If filter returns 1, then the event will be added to the internal queue. If it returns 0, then the event will be dropped from the queue, but the internal state will still be updated. This allows selective filtering of dynamically arriving events.

So the filter result was backwards(it needs to return 0 for the Android events, while 1 for all other events).

Updated filter function:
*** START CODE ***
int SDLCALL myEventFilter(void *userdata, SDL_Event * event)
{
	//Emergency calls! Immediately update!
	switch (event->type) //Emergency event?
	{
		#ifdef ANDROID
		case SDL_APP_TERMINATING: //Terminating the application by the OS?
		case SDL_APP_LOWMEMORY: //Low on memory?
		case SDL_APP_DIDENTERBACKGROUND: //Are we pushed to the background?
		case SDL_APP_WILLENTERBACKGROUND: //Are we pushing to the background?
		case SDL_APP_WILLENTERFOREGROUND: //Are we pushing to the foreground?
		case SDL_APP_DIDENTERFOREGROUND: //Are we pushed to the foreground?
			updateInput(event); //Handle this immediately!
			return 0; //Drop the event, as this is handled already!
		#endif
		default:
			break; //Handle normally!
	}
	// etc
	return 1; //Handle normally, as a normal event!
}
*** END CODE ***
Comment 25 superfury 2017-09-19 09:26:21 UTC
I've improved the SDL to support window events better (for standby) on Android as well(redirecting focus gain/lost to foreground/background):

*** START CODE ***
	//Misc system events
	case SDL_QUIT: //Quit?
	#ifdef SDL2
	#ifdef ANDROID
	case SDL_APP_TERMINATING: //Terminating the application by the OS?
	
	//case SDL_APP_LOWMEMORY: //Low on memory?
		#ifdef NDK_PROFILE
			monpendingcleanup(); //Process any pending cleanup when needed!
		#endif
	#endif
	#endif
		quitting:
		lock(LOCK_INPUT);
		if (joystick) //Gotten a joystick connected?
		{
			SDL_JoystickClose(joystick); //Finish our joystick: we're not using it anymore!
			joystick = NULL; //No joystick connected anymore!
		}
		EMU_Shutdown(1); //Request a shutdown!
		unlock(LOCK_INPUT);
		break;
	#ifndef SDL2
	case SDL_ACTIVEEVENT: //Window event?
		lock(LOCK_INPUT);
		if (event->active.state&SDL_APPMOUSEFOCUS)
		{
			hasmousefocus = event->active.gain; //Do we have mouse focus?
		}
		if (event->active.state&SDL_APPINPUTFOCUS) //Gain/lose keyboard focus?
		{
			hasinputfocus = event->active.gain; //Do we have input focus?
		}
		if (event->active.state&SDL_APPACTIVE) //Iconified/Restored?
		{
			haswindowactive = (haswindowactive&~1)|(event->active.gain?1:0); //0=Iconified, 1=Restored.
		}
		unlock(LOCK_INPUT);
		break;
	#else
	case SDL_WINDOWEVENT: //SDL2 window event!
		switch (event->window.event) //What event?
		{
			case SDL_WINDOWEVENT_MINIMIZED:
				lock(LOCK_INPUT);
				haswindowactive &= ~1; //Iconified!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_RESTORED:
				lock(LOCK_INPUT);
				haswindowactive |= 1; //Restored!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_FOCUS_GAINED:
				lock(LOCK_INPUT);
				hasinputfocus = 1; //Input focus!
				unlock(LOCK_INPUT);
				#ifdef ANDROID
				goto didenterforeground; //Simulate foreground!
				#endif
				break;
			case SDL_WINDOWEVENT_FOCUS_LOST:
				lock(LOCK_INPUT);
				hasinputfocus = 0; //Lost input focus!
				unlock(LOCK_INPUT);
				#ifdef ANDROID
				goto didenterbackground; //Simulate background!
				#endif
				break;
			case SDL_WINDOWEVENT_ENTER:
				lock(LOCK_INPUT);
				hasmousefocus = 1; //Mouse focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_LEAVE:
				lock(LOCK_INPUT);
				hasmousefocus = 0; //Lost mouse focus!
				unlock(LOCK_INPUT);
				break;
			case SDL_WINDOWEVENT_CLOSE:
				goto quitting; //We're redirecting to the SDL_QUIT event!
				break;
			default: //Unknown event?
				break;
		}
		break;
	case SDL_APP_DIDENTERBACKGROUND: //Are we pushed to the background?
	case SDL_APP_WILLENTERBACKGROUND: //Are we pushing to the background?
		didenterbackground: //For focus gain/lost!
		lock(LOCK_INPUT);
		haswindowactive &= ~6; //We're iconified! This also prevents drawing and audio output! This is critical!
		haswindowactive |= 0x8; //Discard any future time!
		unlock(LOCK_INPUT);
		break;
	case SDL_APP_WILLENTERFOREGROUND: //Are we pushing to the foreground?
		break; //Unhandled!
	case SDL_APP_DIDENTERFOREGROUND: //Are we pushed to the foreground?
		didenterforeground: //For focus gain/lost!
		lock(LOCK_INPUT);
		haswindowactive |= 6; //We're not iconified! This also enables drawing and audio output!
		lock(LOCK_GPU);
		request_render = 1; //Requesting for rendering once!
		unlock(LOCK_GPU);
		unlock(LOCK_INPUT);
		break;
	#ifdef ANDROID
	case SDL_WINDOWEVENT_SIZE_CHANGED: //Orientation changed?
		lock(LOCK_GPU); //Lock the GPU!
		lock(LOCK_VIDEO); //Lock the video output!
		window_xres = window_yres = 0; //We're autodetecting the new resolution!
		GPU.forceRedraw = 1; //We're forcing a full redraw next frame to make sure the screen is always updated nicely!
		needvideoupdate = 1; //We need a video update!
		unlock(LOCK_VIDEO); //We're done with video!
		unlock(LOCK_GPU); //We're finshed with the GPU!
		break;
	#endif
*** END CODE ***

Is that correct? So this should prevent the continuing and incorrect behaviour on Android?
Comment 26 Sylvain 2017-09-19 09:36:32 UTC
can really say. but you indeed has identified why the ENTERBACKGROUND event where processed twice.
I believe no event should be processed twice (even if it breaks nothing).

So what about your audio now ? do you have some trace to make sure the stop request is processed ? how do you play audio and which format ?
Comment 27 superfury 2017-09-19 09:58:50 UTC
I´ve just checked on Android again with the lastest code(it now correctly seems to mute audio output(thus pausing the application effectively as well due to the other bits' effects causing running time(nanosecond counter) to be discarded)). The new additions on the focus gain/lost being redirected, after processing, to the didenterforeground/didenterbackground events (on Android only) seems to make the minimizing/restoring and standby behave as they're supposed to. The application is properly 'paused'(the code is still running, but the main execution loop is semi-blocked due to all time gotten from the high resolution clock (delta time) being discarded.

So the pausing and resuming in all those cases seems to work properly now:D

I haven't modified the BLOCK_ON_PAUSE flag on SDL2. Even when I enable it, it would cause problems with my application, because the delta timing wouldn't be discarded properly(haswindowactive bits 2,3 and 4), causing timing inconsistencies which will cause it to process the entire paused time(after reactivating the app) in one big chunk(that's the way the app is updated: it first retrieves the delta time, then updates the app's state by that time(it's a cycle-accurate x86 emulator). Although the security check should truncate that huge time to a small amount(to prevent running huge loops due to inconsistent CPU speed(or other applications on the used system taking CPU time away from the app)). Looking at the core handling, it seems it truncates the elapsed time to 1ms amounts.
Comment 28 superfury 2017-09-19 10:01:41 UTC
Audio is played in the format used by the emulator only(although I use my own resampling algorithm due to the many channels(24 MIDI channels, various emulated hardware channels)).

*** START OF CODE ***
			//dolog("soundservice","Setting desired audio device...");
			/* Open the audio device. The sound driver will try to give us
			the requested format, but it might not succeed. The 'obtained'
			structure will be filled in with the actual format data. */
			audiospecs.freq = HW_SAMPLERATE;	/* desired output sample rate */
			audiospecs.format = AUDIO_S16SYS;	/* request signed 16-bit samples */
			audiospecs.channels = 2;	/* ask for stereo */
			audiospecs.samples = SAMPLESIZE;	/* this is more or less discretionary */
			audiospecs.size = audiospecs.samples * audiospecs.channels * sizeof(sample_t);
			#ifdef SDL_QUEUEAUDIO
			audiospecs.callback = NULL; //We're queueing audio!
			#else
			audiospecs.callback = &Sound_AudioCallback; //We're not queueing audio! Use the callback instead!
			#endif
			audiospecs.userdata = NULL;	/* we don't need this */
			//dolog("soundservice","Opening audio device...");
*** END OF CODE ***
Comment 29 Sylvain 2017-09-19 10:07:46 UTC
ok, great ! so I'm closing the issue has there's not bug !
(Btw SDL_ANDROID_BLOCK_ON_PAUSE is by default enabled in SDL_androidevents.c)