Android Service Killed

Android service killed

First be sure to read: http://developer.android.com/guide/components/processes-and-threads.html#Lifecycle

The key to this is that on Android a process is just a container for code -- or specifically one or more components (activities, services, receivers, providers). By default all components in a .apk get their own, dedicated process, that they all run in together. This is almost always what you want.

When the user is directly interacting with a component of that process (that is an activity) Android will try very hard to keep that process running, and you won't see it killed except under extraordinary circumstances.

When the user is no longer directly interacting with the process, then it becomes expendable relative to other processes as described in the referenced documentation. That is, empty processes (no interesting components) will be killed before processes holding activities that the user had been using, which will be killed before processes with running services. So having a running service will tend to keep your process around at the expense of other processes.

At the same time, we need to deal well with more and more applications leaving services running, often indefinitely, and often with memory leaks. So has a service runs for an increasingly long time, Android will try less and less hard to keep its process going. Effectively this means moving it down to the background bucket until the out of memory killer takes it out. After that, if the service still wants to run, then a new process will be created for it to be restarted in.

The upshot is that for normal services that are running a long time, it is expected behavior that their process will get killed after a while. This doesn't need to stop the service; a service that wants to continue running will do so, it will just need to be instantiated in a new process.

Of course as long as the user is interacting with an activity in your process, the process won't be killed, since this pulls it to the foreground category regardless of what is going on with any services in it.

Service is killed in sleep mode.Why?

The murder mystery has been solved, and I know what killed my service. Here's what I did:

  1. After I realized that startsticky, startforeground, alarmmanager, scheduleTaskExecutor, and even wakelock were unable to save my service, I realized the murderer couldn't be the Android system, because I had taken every measure possible to prevent the system from killing my service and it still would get killed.
  2. I realized I needed to look for another suspect, since the service wasn't dying because of the system. For that, I had to run an investigation. I ran the following command:

    adb shell dumpsys activity processes > tmp.txt

This would give me a detailed log of all the processes running and their system priorities. Essentially, tmp.txt would be the detective in this murder mystery.


  1. I looked through the file with lots of detail. It looked like my service was prioritized properly by the system:

    Proc #31: adj=prcp /FS trm= 0 2205:servicename.service/uID (fg-service)

The above line indicates the exact priority of a process running on the Android device. adj=prcp means the service is a visible foreground service.

At this point, I realized that my service must be encountering some error a couple hours after running, so I let it run and die. After it died, I produced a dumpsys again to examine the error:


  1. At this point, my service wasn't listed as a task in the tmp.txt file. Excited, I scrolled to the bottom of the dumpsys and solved the mystery!

com.curlybrace.ruchir.appName.MyService$2.onForeground(MyService.java:199)
at com.rvalerio.fgchecker.AppChecker$2.run(AppChecker.java:118)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)

The stack trace that caused the killing of my service was displayed right there! Essentially, a variable that would check for the foreground app being used would become null after a few hours of inactivity, which would cause an exception, and kill the service!

Key Takeaways:
If your service is getting killed, and you've done everything you can to make sure that it shouldn't be killed, perform a dumpsys and examine the nitty gritty of your device's activity process. I guarantee you will find the issue that way.

I still would like to have the bounty awarded to @Khemraj since his answer could be a great solution for someone who hasn't started their service properly. However, I am accepting this answer since it is the solution that actually fixed the issue.

Minimal android foreground service killed on high-end phone

A service started by startForeground belongs to the second most important group visible process:


  1. A visible process is doing work that the user is currently aware of,
    so killing it would have a noticeable negative impact on the user
    experience. A process is considered visible in the following
    conditions:

  2. It is running an Activity that is visible to the user on-screen but not in the foreground (its onPause() method has been called). This
    may occur, for example, if the foreground Activity is displayed as a
    dialog that allows the previous Activity to be seen behind it.

  3. It has a Service that is running as a foreground service, through Service.startForeground() (which is asking the system to treat the
    service as something the user is aware of, or essentially visible to
    them).

  4. It is hosting a service that the system is using for a particular feature that the user is aware, such as a live wallpaper, input method
    service, etc.

The number of these processes running in the system is less bounded
than foreground processes, but still relatively controlled. These
processes are considered extremely important and will not be killed
unless doing so is required to keep all foreground processes running
.

That being said, you can never be sure that your service is not killed at any time. E.g. memory pressure, low battery etc. See who-lives-and-who-dies.


For how to handle it, basically you answered the question yourself. The way to go is START_STICKY:

For started services, there are two additional major modes of
operation they can decide to run in, depending on the value they
return from onStartCommand(): START_STICKY is used for services that
are explicitly started and stopped as needed, while START_NOT_STICKY
or START_REDELIVER_INTENT are used for services that should only
remain running while processing any commands sent to them
. See the
linked documentation for more detail on the semantics.

As a general guideline you should do as little as possible in the background (ore foreground) service, i.e. only do the location tracking and keep everything else in your foreground activity. Only the tracking should require very little configuration an can be loaded quickly. Also the smaller your service is the less likely it is to be killed. Your activity will be restored by the system in the state that is was before it went into background, as long as it is not killed as well. A "cold-start" of the foreground activity on the other hand should not be a problem.

I don't consider that as ugly, because this guarantees that the phone always provides the best experience to the user. This is the most important thing it has to do. That some devices close services after 30 minutes (possibly without user interaction) is unfortunate.

So, as you stated, you have to

Persist everything in the service in e.g. a Room database. Every
variable, every custom class, every time any of them changes and then
start the service with START_STICKY.

See creating a never ending service

Implicit question:

Depending on how long it takes for Android to re-create the
service after killing it, a large portion of locations may be lost.

This usually takes only a really short time. Especially because you can use the Fused Location Provider Api for the location updates, which is an independent system service and very unlikely to be killed. So it mainly depends on the time you need to recreate the service in onStartCommand.

Also take note that from Android 8.0 onwards you need to use a
forground service because of the background location
limits.


Edit:
As recently covered in the news:
Some manufacturers may give you a hard time to keep your service running. The site https://dontkillmyapp.com/ keeps track of the manufacturers and possible mitigations for your device. Oneplus is currently (29.01.19) one of the worst offenders.

When releasing their 1+5 and 1+6 phones, OnePlus introduced one of the
most severe background limits on the market to date, dwarfing even
those performed by Xiaomi or Huawei. Not only did users need to enable
extra settings to make their apps work properly, but those settings
even get reset with firmware update so that apps break again and users
are required to re-enable those settings on a regular basis.

Solution for users

Turn off System Settings > Apps > Gear Icon > Special Access > Battery
Optimization.

sadly there is

No known solution on the developer end

How to kill an android service?

You should not rely on onDestroy() because it only gets called, when service is properly stopped (by calling stopService() or stopSelf() method).

If you want to save service state, you should either save it as you go (for instance a player service can store it when play/pause function is activated), or use a timer to save it periodically.

If you want to react to memory events, you should use ComponentCallbacks2 class, which will notify you, when Android needs more memory. If you free memory inside those callbacks, you will increase probability your service will stay in memory longer.

Hope this helps.

Service is killed after a short period of time (1 minute)

I found a solution with the help of @emandt.

I just added these lines of code in onStartCommand() :

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Service Started");
Notification notification = new NotificationCompat.Builder(this, CHANNELID)
.setContentTitle("title")
.setContentText("text")
.setSmallIcon(R.drawable.baseline_pause_white_24)
.build();
startForeground(2001,notification);
return START_NOT_STICKY;
}

According to docs the startForeground method :

If your service is started then also make this service run in the foreground, supplying the ongoing notification to be shown to the user while in this state...By default started services are background, meaning that their process won't be given foreground CPU scheduling (unless something else in that process is foreground)

Also,

If your app targets API level 26 or higher, the system imposes restrictions on using or creating background services unless the app itself is in the foreground. If an app needs to create a foreground service, the app should call startForegroundService(). That method creates a background service, but the method signals to the system that the service will promote itself to the foreground. Once the service has been created, the service must call its startForeground() method within five seconds.

Background Service getting killed in android

The main problem is that we cannot say

Services are not meant to be killed. They are meant to run in background as long as we want it to.

Basically, that is not true. System still can terminate the service in low memory and possibly other situations.
There are 2 ways to overcome this:

  1. If you are implementing the service, override onStartCommand() and return START_STICKY as the result. It will tell the system that even if it will want to kill your service due to low memory, it should re-create it as soon as memory will be back to normal.
  2. If you are not sure 1st approach will work - you'll have to use AlarmManager http://developer.android.com/reference/android/app/AlarmManager.html . That is a system service, which will execute actions when you'll tell, for example periodically. That will ensure that if your service will be terminated, or even the whole process will die(for example with force close) - it will be 100% restarted by AlarmManager.


Related Topics



Leave a reply



Submit