19

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.

Richard Le Mesurier
  • 29,432
  • 22
  • 140
  • 255
  • How is it going? Any progress or setbacks? Is there something else I can add to my answer which might help you? – Xaver Kapeller Jul 29 '14 at 14:25
  • @XaverKapeller It seems like you agree with me, and also can tell you that solution #3 does the trick. Still 3 days to go, but looking like the points are yours unless one of the Big Dogs chimes in with some extra amazing insight... – Richard Le Mesurier Jul 29 '14 at 14:57
  • 2
    Just wanted to say good job for writing such a thorough and useful question! – Sam Jun 16 '15 at 10:29

2 Answers2

10

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).

Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
  • 1
    At what point would a `Service` become eligible for garbage collection? Assuming it is not in the foreground, not bound, but is executing (an event handling thread for example)? – Richard Le Mesurier Jul 25 '14 at 12:53
  • 1
    The same conditions that prevent a `String` from being garbage collected, when there is no reference to it anymore. This will happen some time after the `Service` is stopped, Android manages that for us. – Xaver Kapeller Jul 25 '14 at 12:55
  • In an ideal device a `Service` would never be killed as long as it is running, but the reality is of course different. But on a modern device the `Service` can run for a very long time. Memory constraints are barely a problem nowadays with 2GB+ ram. – Xaver Kapeller Jul 25 '14 at 12:57
  • yes, but unlike a `String` where we normally hold the reference to it ourselves, when we start an unbound `Service` it is the system that holds the reference to it. So at what point does the system drop that reference, making it available? – Richard Le Mesurier Jul 25 '14 at 13:43
  • At some point after the `Service` is stopped. You can maybe look at the Android source and find out how it exactly happens but I don't think that the exact moment is relevant for you. The point is: As long as the `Service` is running it cannot just magically be destroyed. Pretty much the only thing that can happen is that the OS kills the whole process because of resource constraints. Use the callback of the [**Application**](http://developer.android.com/reference/android/app/Application.html) class like `onLowMemory()` to determine when your `Services` might face being killed. – Xaver Kapeller Jul 25 '14 at 13:57
  • well you are backing up my suspicion about it being the process that is killed, not the services. Option 3 is 70+ hours into testing and still holding up. – Richard Le Mesurier Jul 25 '14 at 14:02
  • 1
    "But on a modern device the Service can run for a very long time. Memory constraints are barely a problem nowadays with 2GB+ ram" Memory constraints are not the only reason to kill an unused process. e.g. my Nexus 5 with not many apps running has killed the original version of this app within minutes of it being sent to background. – Richard Le Mesurier Jul 25 '14 at 14:04
  • 1
    Yes, there are other reasons a process might be killed, that's why I like solution **4)**. This should be the most stable one since one is in the foreground and the others being bound. – Xaver Kapeller Jul 25 '14 at 14:06
  • Just to clarify, it sounds like your point about components (Activities, Services) being garbage collected only applies when those components have finished/stopped. Is that correct? – Sam Jun 16 '15 at 10:33
  • @Sam Well as soon as an `Activity` is in the background it can be killed. However services can be killed at any time, that is however extremely unlikely of the `Service` does not perform some long running operation. But technically under extreme circumstances anything can be killed, visible `Activities` and foreground `Services`. However the point of my answer is the mindset a developer should have: you have to implement your app as if any component could be killed at any time. – Xaver Kapeller Jun 16 '15 at 10:51
  • @XaverKapeller can you solve this question? https://stackoverflow.com/q/63350856/5359340 – FGH Aug 11 '20 at 06:52
2

Every android application is a fork of zygote process and has its own process. Each application process can host more activities and services: so definetely, killing one process (example: kill PID) will kill everything which is inside.

By default a service is in the same process of its application; however it is possible, to let a service running on a dedicated separate process, with declaration in the manifest:

<service android:name=".MyService"
     android:isolatedProcess=true />
Zanna
  • 676
  • 9
  • 13