What happens if I run an Android thread in the background indefinitely
Asked Answered
C

4

6

Android docs indicate that Oreo has new restrictions on background execution: https://developer.android.com/about/versions/oreo/background. This seems reasonable and they're clearly aiming to make their platform more like iOS and prevent apps running rampant in the background.

The thing that's unclear to me (in fact, not documented at all) is what can you do on a thread when the UI goes to the background. Specifically,

GIVEN I create a thread with

new Thread(() -> { 
     // Naughty thread doing something forever
}).start();

AND I send the app to the background

THEN ...what happens to that thread?

I've created very simple code to do this and my thread has been happily churning out to logcat for 10+ minutes with no issues.

Does anyone have any clear information on what restrictions there are on such threads? I would have thought that since Android restricts what a background service can do that it would also restrict what such threads can do.

Note that we have no plans to write an app which does anything like this. We just want to be able to write safe code which doesn't cause issues on newer versions of android. On iOS, if you go to the background then you get a period of grace to finish off whatever you're doing (and you can ask for more time) but eventually your thread will be suspended.

Clarenceclarenceux answered 12/7, 2018 at 3:39 Comment(2)
The link specifies Background Service Limitations, not Thread Limitations.Sibelle
Understood. But I presumed that the reason for these limitations was to prevent apps sucking up battery in the background and potentially doing nefarious things without the user knowing (hence the need for foreground services and notifications). Seems odd that they wouldn't put restrictions on app threads as well.Clarenceclarenceux
N
3

Does anyone have any clear information on what restrictions there are on such threads? I would have thought that since Android restricts what a background service can do that it would also restrict what such threads can do.

There are no restrictions as such on how long such threads can run. As long as your app is running in background, you can continue to execute Thread in background

However, you need to consider how to gracefully terminate/release the Thread, since the Thread won't run endlessly. If OS needs to relinquish memory during memory crunch then the process of your app hosting this background Activity will be terminated, eventually destroying the thread. If not handled properly, this would lead to Thread/memory leaks.

Nassir answered 12/7, 2018 at 3:45 Comment(7)
Thanks for the response. That is the behaviour I've observed. Is this documented behaviour or just what you've experienced. It surprises me as it seems contrary to Android's stated behaviour for services on Oreo.Clarenceclarenceux
Note that terminating the thread etc. is no problem. In fact we are "stopping" the thread on background, but the thread may not stop immediately (in a bad situation it could potentially hang around for a while). It's not a big deal if the app gets killed, but I wanted to understand whether the thread not stopping might actually cause the app to get killed (which would be a problem).Clarenceclarenceux
It surprises me as it seems contrary to Android's stated behaviour for services on Oreo. It doesn't contradict. As the limitations are imposed on execution of background service. However, you can create a ForegroundService and keep the Thread running until OS terminates it during Doze mode ( this termination could happen if CPU intensive task is performed during doze mode)Nassir
You should use Foreground services for cases which requires to be run through completion and could out-live Activity.Nassir
Does a foreground service really terminate during doze mode? I would have thought that a foreground service explicitly wouldn't be terminated during doze mode. The thread I describe is outliving the all activities in my appClarenceclarenceux
The documentation doesnt say so, but I tried to run the Service forever. After 3-4 hours I saw the Service got terminated(Tested on Google pixel2). It makes sense not to kill it( in case of Music apps) it was strange for me though. This doesnt happen on Android M.Nassir
@AndrewParker You should use Foreground services for tasks which needs to be executed immediately without interruption.Nassir
E
1

According to my tests on emulator APIs 26 and 27, a started thread will continue to work as long as the app is still in the background and not terminated, and the system doesn't decide to kill the thread or terminate the app.

I even forced the emulators to deep doze using:

$ adb shell dumpsys deviceidle force-idle

Yet, still the thread was running. However, this does not happen on real physical devices. Threads pause when entering doze. So based on experience, do not fully trust emulators.

So, your observations were normal as you mentioned in your question.

As for this:

Does anyone have any clear information on what restrictions there are on such threads? I would have thought that since Android restricts what a background service can do that it would also restrict what such threads can do.

Well, threads had always been less of a concern themselves than services when it comes to eating up memory and battery. Pre-Marshmallow, services could keep doing work forever even if you close the app and if the system kills it to reclaim memory, they restart again after a while (START_STICKY). So, this behavior was dangerous when it comes to battery consumption and resource consumption.

On the other hand, threads terminate as soon as the app is terminated and they do not start automatically again. Also, the system would rather terminate a background app having no service running even if it had lots of running threads, than one that has a service running.

Starting Marshmallow, they introduced Doze mode to pause almost everything only when the phone goes to sleep to save battery. But, still that didn't fix the problem of apps that the user is not currently using from doing intensive work in the background (Services) as soon as the device exits doze and making performance of the user's running app deteriorate.

So, starting Oreo they imposed restrictions on services of apps that are not in the foreground as they are the main reason of causing performance hazards. So, maybe in the future they will impose restrictions on the threads of apps when they are in the background too, to even further improve resource consumption.

Engrossing answered 29/9, 2019 at 12:56 Comment(0)
M
0

As @Sagar's answer mentioned, while the system may selectively terminate "background services", it does not selectively terminate individual "background threads".

But your question has more to it than just avoiding termination; you expect your thread to execute continuously. Other answers on this page don't mention WakeLocks, and there are some misleading comments in that regard, so I will address that here.

We are dealing with two separate issues: App termination, and device sleep.

App termination: Android terminates apps to free up resources -- preferring apps that are in the background (e.g., apps that are not on screen, and that don't contain a foreground service). When your app is terminated, all its threads are terminated too.

Device sleep: Android will pause your thread, as it pauses all threads, when the device goes to sleep. That's how so much of the battery savings are realized on mobile devices: The CPU goes into a low-power "standby" mode, and ceases executing instructions. Even though the device may be sleeping, your app (and its threads) continue to exist.

  • Use a foreground service to stop your app from being terminated after it leaves the screen.
  • Use a WakeLock (PARTIAL_WAKE_LOCK) to keep the CPU in a state where it can execute, even though the screen may be off.

Having a foreground service does not stop the device from going to sleep. Similarly, holding a WakeLock does not prevent your app from being terminated. Note that newer versions of Android can ignore WakeLocks in doze. See here for one approach to dealing with this.

Having a Foreground service does not guarantee your code will execute any faster than with a background service. Foreground services do not "terminate" doze.

If your logs continued to print out for 10 minutes, I would suggest it's probably because your device was plugged in. On most Android devices, the CPU stays awake when plugged in (even though the screen may be off).

Martini answered 24/11, 2018 at 16:38 Comment(3)
I entered in Doze mode using this command : adb shell dumpsys deviceidle force-idle, and a simple thread during doze mode continued to be executed. Nothing was paused during deep sleep. #53594990Dissatisfy
@Dissatisfy question was posted by a different individual?Martini
Yess. I try it myself. Thread was still running after Doze mode. Any ideas?Dissatisfy
S
-1

As long as you start the thread when the App is in foreground, the thread might(I mean might) continue to run when the App goes to background.

BUT, the thread would be killed if the phone is running low on Memory and the System decides to reclaim memory. This is prone to happen on lower end devices much frequently. You need to have a look at Android GO.

Alternative : By all means, you can leverage JobScheduler or the new and improved WorkManager to achieve the same functionality which you might be wanting to achieve by running a thread. Since JobScheduler and WorkManager are managed by the Android System, you can be guaranteed that your functionality keeps working irrespective of the constrains on the System. Additionally, you can specify contains like Network/Battery when you are using JobScheduler/WorkManager. This is something you don't get when using a Thread.

Slope answered 12/7, 2018 at 4:0 Comment(2)
The thread will absolutely run in the background, until you go into Doze. After doze it would be paused, as all your threads would be paused. It may be deprioritized when int he background, but that's it. The Thread will NOT be killed due to low memory. The entire app may be, but an individual thread won't, as there's no way to do so safely without risking deadlocking or breaking a generic app.Aerodonetics
In some cases JobScheduler or WorkManager are an appropriate replacement for a Thread, but not always. It should be considered, but it rarely makes sense.Aerodonetics

© 2022 - 2024 — McMap. All rights reserved.