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:
- After I realized that
startsticky
,startforeground
,alarmmanager
,scheduleTaskExecutor
, and evenwakelock
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. 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.
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:
- At this point, my service wasn't listed as a task in the
tmp.txt
file. Excited, I scrolled to the bottom of thedumpsys
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.
Your service was killed by Doze or Standby mode of Android. That was introduced in Android 6.0 (API level 23).
Doze restrictions
The following restrictions apply to your apps while in Doze:
- Network access is suspended.
- The system ignores wake locks.
- Standard
AlarmManager
alarms (includingsetExact()
andsetWindow()
) are deferred to the next maintenance window.- If you need to set alarms that fire while in Doze, use
setAndAllowWhileIdle()
orsetExactAndAllowWhileIdle()
.- Alarms set with
setAlarmClock()
continue to fire normally — the system exits Doze shortly before those alarms fire.- The system does not perform Wi-Fi scans.
- The system does not allow sync adapters to run. The system does not allow
JobScheduler
to run.
So system ignored your Alarm Clocks, Scheduler
, etc.
In Android Oreo release Android defined limits to background services.
To improve the user experience, Android 8.0 (API level 26) imposes limitations on what apps can do while running in the background.
Still if app need to run its service always, then we can create foreground service.
Background Service Limitations: While an app is idle, there are limits to its use of background services. This does not apply to foreground services, which are more noticeable to the user.
So create a foreground service. In which you will put a notification for user while your service is running. See this answer (There are many others)
Now what if you don't want a notification for your service. A solution is for that.
You can create some periodic task that will start your service, service will do its work and stops itself. By this your app will not be considered battery draining.
You can create periodic task with Alarm Manager, Job Scheduler, Evernote-Jobs or Work Manager.
- Instead of telling pros & cons of each one. I just tell you best. Work manager is best solution for periodic tasks. Which was introduced with Android Architecture Component.
- Unlike Job-Scheduler(only >21 API) it will work for all versions.
- Also it starts work after a Doze-Standby mode.
- Make a Android Boot Receiver for scheduling service after device boot.
I created forever running service with Work-Manager, that is working perfectly.