I have written a foreground service which is working properly for all OS version lower than Oreo. From Oreo application process is getting killed after 5 minutes of closing and removing the application from recents.
As per android developer documentation for background execution limitations OS should not kill application for which a foreground service is running and notification is shown in notification window.
As per guidelines on developer documentation. I followed below steps to start foreground-service.
- Foreground service is started with
startForegroundService()
method - Within 5 sec after starting service a notification is shown for the service using
startForeground()
- Return
START_STICKY
fromonStartCommand()
ofservice
I am facing this issue on following phones:
- OnePlus 5T
- Vivo
- Oppo
- Mi
What I tried to prevent foreground-service from being destroyed?
- Disable the battery optimization for the application by showing system dialog to user to disable doze mode.
What I tried to restart the foreground-service?
- Used
AlarmManager
to restart the service from onTaskRemoved(). Please check this link for details.
As per my understanding these manufacturers have customized the AOSP and are not respecting the OS guidelines for allowing foreground service to run. May be these manufacturers have done this because of giving long battery life time to users.
Foreground service class
class DataCaptureService : Service() {
private var isServiceStarted = false
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WakelockTag123").apply {
acquire()
}
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val serviceAction = intent?.action
LogUtils.logD("OnStartCommand(). Action=$serviceAction")
if (Constants.INTENT.ACTION_STOP_SERVICE == serviceAction) {
LogUtils.logD("Stopping data capture service")
stopForeground(true)
stopSelf()
} else if (Constants.INTENT.ACTION_START_SERVICE == serviceAction && !isServiceStarted) {
LogUtils.logD("Starting data capture service")
isServiceStarted = true
// Here showing notification using a utility method (startForeground(id, notification))
createNotification(this)
// Doing some stuff here
----------------------
//
}
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
if (isServiceStarted) {
LogUtils.logD("onDestroy of DataCaptureService method is invoked")
// Doing some stuff here
----------------------
//
isServiceStarted = false
if (wakeLock.isHeld) {
wakeLock.release()
}
}
}
override fun onTaskRemoved(rootIntent: Intent?) {
LogUtils.logD("onTaskRemoved of DataCaptureService method is invoked")
ensureServiceStaysRunning()
super.onTaskRemoved(rootIntent)
}
private fun ensureServiceStaysRunning() {
val restartAlarmInterval = 60 * 1000
val resetAlarmTimer = 30 * 1000L
// From this broadcast I am restarting the service
val restartIntent = Intent(this, ServiceRestartBroadcast::class.java)
restartIntent.action = "RestartedViaAlarm"
restartIntent.flags = Intent.FLAG_RECEIVER_FOREGROUND
val alarmMgr = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val restartServiceHandler = @SuppressLint("HandlerLeak")
object : Handler() {
override fun handleMessage(msg: Message) {
val pendingIntent = PendingIntent.getBroadcast(applicationContext, 87, restartIntent, PendingIntent.FLAG_CANCEL_CURRENT)
val timer = System.currentTimeMillis() + restartAlarmInterval
val sdkInt = Build.VERSION.SDK_INT
if (sdkInt < Build.VERSION_CODES.KITKAT)
alarmMgr.set(AlarmManager.RTC_WAKEUP, timer, pendingIntent)
else if (Build.VERSION_CODES.KITKAT <= sdkInt && sdkInt < Build.VERSION_CODES.M)
alarmMgr.setExact(AlarmManager.RTC_WAKEUP, timer, pendingIntent)
else if (sdkInt >= Build.VERSION_CODES.M) {
alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timer, pendingIntent)
}
sendEmptyMessageDelayed(0, resetAlarmTimer)
stopSelf()
}
}
restartServiceHandler.sendEmptyMessageDelayed(0, 0)
}
}
Please share your suggestion if you have faced similar type of issue and managed to find a solution for this.