Search code examples
androidandroid-servicealarmmanagerandroid-alarmsandroid-8.1-oreo

How to implement robust alarm clock applications for Android 26+


I maintain an Alarm Clock application as a hobby which I have recently started to migrate to the target API level 26. Because of the background service limitation my app does not work reliably anymore.

Current implementation works like this:

  1. User sets an alarm in UI
  2. android.app.AlarmManager#setAlarmClock is called with a PendingIntent.getBroadcast as the payload
  3. When the alarm fires, a BroadcastReceiver gets it
  4. First, it grabs a Wakelock
  5. Then it starts a Service
  6. Service processes the event and produces more events, for example statring other services for music, starting activities or notifications
  7. Wakelock is released

With Target SDK 25 everything was fine. With the taraget API 26 application reliably wakes up from Doze, but point .5 fails sometimes, because the application is in the background:

    AlarmsService$Receiver: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.better.alarm.ACTION_FIRED flg=0x14 cmp=com.better.alarm/.model.AlarmsService (has extras) }: app is in background

Services in point .6 can be foreground services, I got no problem with that, but service in point .5 does not only process alarm fired events, but also timezone changes, several user interaction intents dispatched from notifications, etc. It cannot be a foreground service.

Android documentation suggests using JobScheduler for such cases, but JobScheduler does not guarantee that the job is executed in time. This kind of defeats the purpose of the alarm clock.

What options do I have to execute code reliably when the alarm which is set using android.app.AlarmManager#setAlarmClock is fired?

Thank you


Solution

  • After I have tried quite a few approaches I came to this conclusion: the only reliable way to execute the Code is to do it within the BroadcastReceiver or start a foreground service. Everything elso has proven to be unreliable.

    So, back to big fat BroadcastReceivers!