Foreground Coroutine Worker causing android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()

Viewed 642

Getting the following crash on coroutine worker, the crash is happening on only some Samsung, Vivo and Oppo devices specifically and only on Android 10

Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{2dcabaa u0 `app_id_hidden`/androidx.work.impl.foreground.SystemForegroundService}
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2159)
       at android.os.Handler.dispatchMessage(Handler.java:107)
       at android.os.Looper.loop(Looper.java:230)
       at android.app.ActivityThread.main(ActivityThread.java:7752)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:526)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)

The doWork function on the worker is implemented as, where the init() function does my job.

override suspend fun doWork(): Result {
    setForeground(createForegroundInfo())
    return init()
}

private fun init() {
    //implementation hidden
}

private fun createForegroundInfo(): ForegroundInfo {
    val notificationId = 1
    return ForegroundInfo(notificationId, createNotification())
}

private fun createNotification(): Notification {
    val context = applicationContext

    val builder = NotificationCompat.Builder(context, ChannelType.NOTIFICATION_CHANNEL_GENERAL)
                .setContentTitle("Message")
                .setSmallIcon(R.drawable.ic_notif_small)
                .setOngoing(true)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        createNotificationChannel(
                    ChannelType.NOTIFICATION_CHANNEL_GENERAL,
                    ChannelType.NOTIFICATION_CHANNEL_GENERAL
        ).also {
            builder.setChannelId(it.id)
        }
    }
    return builder.build()
}

@TargetApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(
         channelId: String,
         name: String
    ): NotificationChannel {
        return NotificationChannel(
                channelId, name, NotificationManager.IMPORTANCE_LOW
        ).also { channel ->
            notificationManager.createNotificationChannel(channel)
    }
}

I am not using any location or microphone or any default foreground service types. It's a plain worker which does some job.

1 Answers

In the latest Workmanager API, you can use "setExpedited" along with "getForegroundInfo" instead of "setForeground" in your Worker. It will mark your work as starting immediately (meeting the constraints).

Steps :

  • Override the getForegroundInfo method and return the ForegroundInfo.
  • While building the workrequest, use setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) (for more quota policy, checkout the link below)
  • And done.

Note: setExpedited would only work with OneTimeRequest and not with PeriodicWorkRequest

For more info : setExpedited

Related