Jump to content
Rollo62

TThread.Sleep in iOS/android background mode threads, what to choose ?

Recommended Posts

Hi there,

 

I'm checking in iOS (and later for Android, Windows, etc.), what is the best, right way to Sleep in a background mode of the OS.

The implementation for iOS seems to be same, as Posix, for iOS, Android, Macos, but I didn't checked that.

My goal is to stop any OS operation in the background mode, to avoid killed apps by the OS.

While the Thead loop is still active, but only throttled.

 

TThread.Sleep

- uses usleep, which is external function, as far as I know based on nanosleep

- is this really affecting the current thread only ?

class procedure TThread.Sleep(Timeout: Integer);
begin
{$IF Defined(MSWINDOWS)}
  Winapi.Windows.Sleep(Timeout);
{$ELSEIF Defined(POSIX)}
  usleep(Timeout * 1000);
{$ENDIF POSIX}
end;

System.SysUtils.Sleep

- is bascially same

{$IFDEF MSWINDOWS}
procedure Sleep; external kernel32 name 'Sleep'; stdcall;
{$ENDIF MSWINDOWS}
{$IFDEF POSIX}
procedure Sleep(milliseconds: Cardinal);
begin
  usleep(milliseconds * 1000);  // usleep is in microseconds
end;
{$ENDIF POSIX}

System.SyncObjs.TEvent.WaitFor

- is defintively based differently

- uses a sem_timedwait  (here and here also)

- this probably waits by counting in a semaphore, so its not a "real" sleep of the OS, right ?

 

Shall I better use Sleep or TEvent.WaitFor, to let threads sleep in the OS, while avoiding too many wakeups and operations in the background ?

Is TEvent.WaitFor really sleeping, from a iOS OS perspective, or will it be seen as running app ?

 

What I assumed before is that TThread.Sleep really stops the thread, and passes back CPU operation to other tasks, but I'm not so sure anymore under IOS.

 

 

Edited by Rollo62

Share this post


Link to post

Yes, Sleep()/usleep() really does block the calling thread, stopping it at the OS level, yielding to other threads so they can run, for at least the specified time (may be more).

 

TEvent.WaitFor() is waiting for its internal event/semaphore object to be signaled by TEvent.SetEvent(), up to the specified time.  During that wait time, the calling thread is stopped in a blocking sleep, yes.  It is just using a different API to accomplish that.

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post

@Remy Lebeau

Thanks for the clarification.

 

But is there any possible negative effect on iOS/(Android) apps when running in background mode ?

Are the apps more likely to be killed when using one or the other in a running thread loop ?

I assume that TThread.Sleep should be safe in background mode, while TEvent.WaitFor is probably not the right choice, but I'm very unsure about that.

Share this post


Link to post

This is something that has puzzled me with Android apps.  

 

Background: 

In Norway, we have a walkabout game app ("Stolpejakten" which translate to "The Pole Hunt" ) which has you locating real world markers via a map, and when you arrive at the location, there is a QR code on a wooden pole that you scan to register at the location.  It is a nice motivator for extending your walks for "just one more marker".


The app uses the GPS to indicate your location in relation to the marker, the app has a somewhat lengthy startup, apparently logging onto a central server, loading the maps and pole locations, and marking your latest marker visits, and restarting at the "home" screen, and not where you last left off.  Hence there is a very visible difference between waking up a sleeping instance, vs a dead instance.

 

On my Nokia 7 Plus, this app would go dead in a few minutes behind the lock screen, but on my Pixel 3a XL, it will stay alive for a fairly lengthy period, although sometimes it can die rather quickly.


Question:

What can prevent or at least reduce the chance of the app being killed?  

What governs the "survivability" of your app? 

 

Share this post


Link to post
15 minutes ago, Lars Fosdal said:

On my Nokia 7 Plus, this app would go dead in a few minutes behind the lock screen, but on my Pixel 3a XL, it will stay alive for a fairly lengthy period, although sometimes it can die rather quickly.

Did those two devices run the same Android version?

 

Concerning iOS AFAIK the OS will suspend an App that has been moved to the background in a short time, if it is not registered as an App that needs to stay alive (i.e. for navigation).  Correct handling of that situation is to store the momentary state of ones App and load that state at reactivation. In my opinion there is no need to sleep, just handle the events efficiently.

Share this post


Link to post

At the time, my son was using a Pocophone F1 also running Android 9, and his phone did not kill the app.

My 7 Plus also was on Android 9, while the 3a XL is on 10.

It could be OS specific energy saving settings that govern how quick it is to kill apps.

 

Otherwise, I totally agree on sensible state saving and restoring on reactivation.

 

Are there other stay-alive options than navigation, without running as a service?

Share this post


Link to post

I have done some experiments, and see that background mode behaves a little tricky.

 

See the little iOS test enclosed.
Its missing the wonderful Grijjy TestToSpeech library, available here.

Just copy all .pas files into the .dproj folder.

 

And in the _Assets\Sounds folder you can put the downloaded Codex_Machine_-_02_-_Controlled_Relaxation.mp3 file from here.

 

Sorry for the German texts, manby that sound fuzzy in other languages, its a poem from Paul Fleming 05.10.1609.

 

The demo:

1.) When pressing the "Speak" button it start an infinite thread, with Sleep( 3000 ), counting and speaking the numbers.

2.) In foreground no problem, but in background the thread get stopped

3.) Back in foreground, the suspended thread resumes as it should

4.) Press "Stop" to leave the thread loop

 

5. ) Start long lasting spoken text, or the long playing music, by pressing "Speak long" and/or "Music long"

6.) You can move into background mode, it don't stop playing, as desired

7. ) When back in FG, you can add the "Speak" counter, and all text + musik is playing nicely together

8.) Put into background, also the thread loop with the Sleep is not still counting, that is the desired behavior.

 

What I'm looking for is a background thread, which seems to stay active under some special conditions

(either BLuetooth, Location can keep BG awake, as seen above also permanent Audio-Play can keep it awake).

 

You can try

09.) Restart the app

10.) Play musik  and/or "Speak" counter

11.) Enter background

12.) Stop music

13.) Start "Speak" counter

14.) Enter background

15.) "Speak" counter will stop, if no music is running parallel

 

16.) Restart the app

17.) Play musik  and/or "Speak" counter

18.) Enter background

12.) Wait until the music finished (Ok takes a while, but you can use shorter .mp3 maybe)

13.) "Speak" counter is still active

14.) Enter background

15.) "Speak" counter is still active

16.) Enter foreground

17.) "Speak" counter is still active

18.) Enter background

19.) "Speak" counter is still active

20.) It seems the MediaPlayer changed the AVAudioSession awake somehow, so that is can keep the thread loop active

 

What I have noticed: If I play music plus the "Speak", then even after music has stopped the speech contrinues !!!

That is probably because the MediaPlayer opens a AVAudioSession, but didn't close it, so maybe an  open session is enough to keep BG alive.
But also I noticed that this sometimes works, sometimes not, timing and sequence seems very important too.

 

Are there any signals that could keep the thread awake in background, if I don't have BLE or Location active ?

Some people from iOS propose to play "Silence.mp3" sound for > 500ms, but that would be a hard way, and probably against Apple restrictions.


Are there any more tricks how to that behaviour (active thread in BG, with Sleep) could be achieved reliably ?

 

 

 

 

 

 

 

 

 

T345_BG_AudioTest.zip

Share this post


Link to post
16 hours ago, Lars Fosdal said:

Question:

What can prevent or at least reduce the chance of the app being killed?  

What governs the "survivability" of your app?

Processes and Application Lifecycle

Understand the Activity Lifecycle

15 hours ago, Sherlock said:

Concerning iOS AFAIK the OS will suspend an App that has been moved to the background in a short time, if it is not registered as an App that needs to stay alive (i.e. for navigation).

Android is the same way.  Background apps have to let the OS know that they are still "running" and should not be killed off.  The OS is still free to kill them if it NEEDS to, though (low resources, etc).

Edited by Remy Lebeau
  • Like 2

Share this post


Link to post
4 hours ago, Rollo62 said:

Are there any more tricks how to that behaviour (active thread in BG, with Sleep) could be achieved reliably ?

Short answer - background tasks that want to stay awake and running need to be done in a background service, not in a thread in an app that moves between the foreground and background.

Share this post


Link to post
14 hours ago, Remy Lebeau said:

Short answer - background tasks that want to stay awake and running need to be done in a background service, not in a thread in an app that moves between the foreground and background.

The interesting thing is that it sometimes work, and sometimes not.
I will do some more tests if MediaPlayer might allow longer background task, technically its working fine.

In other apps I can use other background modes to keep awake, so its under some conditions possible to get around special service on iOS,
but still I don't see the full picture.
 

Share this post


Link to post

@Remy Lebeau

You are talking about Android, thats all true.
But my question was especially regarding iOS, where things are very much different.

https://stackoverflow.com/questions/11044095/ios-keep-an-app-running-like-a-service

 

The background mode in iOS can be kept active only by those few background modes available, like Audio, Bluetooth, Location, etc.

My goal is too keep some background activity, like a alarm timer, if none of the above is active.

If the timer has ended, then a special alarm tone and speech might occur, together with a local notification.

I do use timed local notifications, to wake up the system right now, but the Tts and audio works not always reliable.

 

The most reliable way to keep threads running so far I found is the Bluetooth-periperial background mode, where the app itself may act as BLE device,
also in background.

That may keep iOS active, but if you never need that "peripheral", only to keep it up, then Apple will ask you to show and explain where you need this mode probably.

 

I think a possible way would be to introduce some "function", that can be shown, but may never be used in practice.

 

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×