Android - How to decide whether to run a Service in a separate Process?

I am working on an Android application that collects sensor data over the course of multiple hours. For that, we have a Service that collects the Sensor Data (e.g. Acceleration, GPS, ..), does some processing and stores them remotely on a server.

Currently, this Service runs in a separate process (using android:service=":background" in the manifest). This complicates the communication between the Activities and the Service, but my predecessors created the Application this way because they thought that separating the Service from the Activities would make it more stable.

I would like some more factual reasons for the effort of running a separate process. What are the advantages? Does it really run more stable? Is the Service less likely to be killed by the OS (to free up resources) if it's in a separate process?

Our Application uses startForeground() and friends to minimize the chance of getting killed by the OS.

The Android docs are not very specific about this, the mostly state that it depends on the Application's purpose ;-)

TL;DR What are objective reasons to put a long-running Service in a separate process (in Android)?


Solution 1:

Reduced RAM Usage

The Android developer documentation suggests this might be appropriate to keep the service's RAM usage down.

From Managing Your App's Memory: Use multiple processes:

An example of when multiple processes may be appropriate is when building a music player that plays music from a service for long period of time. If the entire app runs in one process, then many of the allocations performed for its activity UI must be kept around as long as it is playing music, even if the user is currently in another app and the service is controlling the playback. An app like this may be split into two process: one for its UI, and the other for the work that continues running in the background service.

So running the service in a separate process could consequently reduce performance impact of the app while also reducing the likelihood of the service being killed when the system is low on RAM.

Reduced Performance Impact

From Managing Your App's Memory: Switching Apps:

If your app has a cached process and it retains memory that it currently does not need, then your app—even while the user is not using it—is constraining the system's overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache beginning with the process least recently used, but also giving some consideration toward which processes are most memory intensive.

Reduced Likelihood of Being Killed

From Managing Your App's Memory: Release memory as memory becomes tight:

Note: When the system begins killing processes in the LRU cache, although it primarily works bottom-up, it does give some consideration to which processes are consuming more memory and will thus provide the system more memory gain if killed. So the less memory you consume while in the LRU list overall, the better your chances are to remain in the list and be able to quickly resume.

So your service is less likely to be killed when it's in a separate process since the process's RAM usage will be smaller since the service isn't sharing UI resources.

When to do this

If your service doesn't use startForeground(), I've found that Android will just kill it when it needs to free up RAM, so the service's RAM consumption isn't too important. So if you're just considering the performance impact on the OS and other apps, I don't think it's worth running the service in a separate process.

However, if you do use startForeground(), Android will try to keep your service alive as much as possible, so any RAM that the process uses will impact the OS and other apps. So in this case, I recommend using a separate process, which could save at least 10MB of RAM, so you don't slow down your users' devices.

Also, note that making your app multi-process is not easy; Android's SharedPreferences doesn't support multiple processes.

Solution 2:

The first place to start is by reading through the description of component lifecycles. The take away from that is you really are not guaranteed that a Service or other component will be allowed to run for a long period of time.

However, it does sound like a Service is the right choice for the functionality you describe. This is because you are doing some operations that are not user facing. Going back to the lifecycle description, any time an Activity is not in the foreground, it is essentially a candidate for being killed.

What you should consider doing is using AlarmManager to periodically trigger your Service. You might want also to look at using the WakefulIntent library that @CommonsWare has created.

There is a good article describing multitasking and processes on the Android blog called Multitasking the Android Way that might get at some of the more details regarding processes you are interested in. For example:

A common misunderstanding about Android multitasking is the difference between a process and an application. In Android these are not tightly coupled entities: applications may seem present to the user without an actual process currently running the app; multiple applications may share processes, or one application may make use of multiple processes depending on its needs; the process(es) of an application may be kept around by Android even when that application is not actively doing something.

Solution 3:

Running a service in its own process has the small advantages that the garbage collector for the service does not affect your application and that the memory footprint of the service is a bit smaller if it runs alone.

If consumption of the service by other applications is not a requirement for you, prefer a local service. Alternatively you can still run the service in its own process and use different communication with your application, e.g. via a broadcast receiver. See Android service tutorial for details.

Solution 4:

Separating the service to run in a different process doesn't make it more stable, but in some cases, makes your application more stable, since if this service crashes, your application will not crash with it, and can recover.

Eli