Richard Le Mesurier Richard Le Mesurier - 2 months ago 11
Android Question

Does Android kill each Service or the whole Process?

Many of us know that (in loose terms) a

Service
in Android will get killed by the system if it does not call
Service.startForeground()
. But is this the whole story...?




I am working on some legacy code, porting a "system" permission app to the Play store. This app has 5 background services (that do not call
startForeground()
), which until now, were safe, due to the "system" permission that the app ran with. It was installed on a custom device. Due to tight timelines and budgets, refactoring these 5 into 1 is not a short term solution, but we would like to move to open beta as soon as possible.

The short question is:


  • If there is no foreground
    Activity
    or
    Service
    , does Android kill each individual background service, or does it just kill the process itself?



Here is some info from the Android docs on Processes and Threads that discusses how Android will terminate processes when under pressure:


Android might decide to shut down a process at some point, when memory
is low and required by other processes that are more immediately
serving the user. Application components running in the process that's
killed are consequently destroyed. A process is started again for
those components when there's again work for them to do.

When deciding which processes to kill, the Android system weighs their
relative importance to the user. For example, it more readily shuts
down a process hosting activities that are no longer visible on
screen, compared to a process hosting visible activities. The decision
whether to terminate a process, therefore, depends on the state of the
components running in that process.
...





Common knowledge says that "Android will kill the Service"

Personal experience has shown that Android will also kill the process itself (as described in the quote above). This can be shown by storing objects in the
Application
object, and noting that they get reinitialised after the service is killed.




With the above in mind, there are a few options for solving the problem:

1) Do the Right Thing



Refactor the 5 services into 1, running on various different threads. Bring the 1 service into the foreground. Problem solved.

Unfortunately no budget for this at the moment, and we would prefer to find a quick fix due to project timelines.

This is the final solution that will be implemented going forwards into full production.

2) Many Notifications



Start each service in foreground, each with its own
Notification
icon.

This is a messy solution, but will work for the beta field trials, buying us some time.

I think of this as the "brute force" approach.

3) Process protected by one Service



If it is the process that is killed, rather than each individual service, then it will be good enough to have a single foreground service running.

This would "prevent" (i.e. lower the probability of) Android from killing the process.

All 5 services would thus survive.

4) One Service to rule them all



The docs on Services tell us that if a service is bound to another context, then


stopService() or stopSelf() does not actually stop the service until
all clients unbind.


If I bind to the other services from a single foreground service, will that keep them all alive?




So:




  • Does Android kill each unbound, background Service?

  • Or does it just kill the VM that the application is running in?






Update



After 18 41 hours of testing #3 (Process protected by one Service), all 6 services are still running (5 old plus the 1 new).

So it is looking as if Android would kill the process if no foreground activities or services are running.

Answer

If there is no foreground Activity or Service, does Android kill each individual background service, or does it just kill the process itself?

Android does not kill individual Activities or Services, that wouldn't make much sense. For example if an Activity is in the background Android will never decide to specifically kill this one Activity. It doesn't matter what kind of Java Object is in memory all those Object instances share the same fate: If they are no longer needed/used they will be garbage collected. People often talk about an Activity being killed when it is in the background and that is really misleading because they just mean it can be garbage collected and eventually will be. So this garbage collecting is what would destroy a specific instance of an object. It has nothing to do with the device having low memory.

When Android is running out of memory it will decide to kill a whole process, and as you already read in the documentation it chooses the least important ones.

What I'm trying to tell you is that those are two fundamentally different processes. One is the Android OS killing not important processes when its running out of memory and the other one is the garbage collector which is constantly looking for no longer used memory which it can free.

Common knowledge says that "Android will kill the Service"

As I explained above, this can be misleading and is not completely true, if the device is running out of memory it will kill the whole process, not just a specific Service. This is different from the Service being garbage collected when it is no longer used.


And now on to your solutions:

Refactor the 5 services into 1, running on various different threads. Bring the 1 service into the foreground. Problem solved.

This obviously is the best option but as you said you are not able to implement this now.

Start each service in foreground, each with its own Notification icon.

This would be a kind of bad solution, there is no reason to have multiple notifications. The other options are clearly better.

If it is the process that is killed, rather than each individual service, then it will be good enough to have a single foreground service running.

This could definitely work, I would try it.

The docs on Services tell us that if a service is bound to another context, then

stopService() or stopSelf() does not actually stop the service until all clients unbind.

If I bind to the other services from a single foreground service, will that keep them all alive?

This is the next best option in my opinion.


I initially thought about starting each Service in its own process. But I am not sure if this is applicable to you. Especially if you want to keep all Services running at all times. The benefit of starting a Service in its own process is obviously that it is independent from the rest of the app. So even if some part is killed due to memory constraints the rest of the app will keep running in the other process.

Have you ever thought about using inheritance to solve the problem? It might be the simplest way to implement your option 1).