Search code examples
androidservicealarmmanager

Android AlarmManager sometimes late


I have an application that's supposed to run a background service at regular intervals and I'm using the AlarmManager to achieve this behavior. To cut a long story short, it's set up to run twice per minute (every 30 seconds) and it takes about 20 seconds to execute (mostly sleeping).

I am using several Android devices for testing (Galaxy SII with 4.1.2, Nexus 4 with 4.2.2 and later with CyanogenMOD 10.1.2 and Nexus 7 with 4.2.2) and all of them behave consistently while connected to USB and debugger.

Once I unplug the device and leave it on the desk, I notice that SOMETIMES the service will miss one interval. Looking very closely at the log I see that the service is sometimes DELAYED by a certain period of time. If it's supposed to run at xx:05 and xx:35 I'll notice it starting at xx:45 (10 seconds later than it should).

The very first thing the service does is acquire the partial wake lock to ensure the CPU doesn't go to sleep while it's running - this wake lock isn't released until it's fully done with what it's supposed to do.

My first thought was that it was some share resource contention that was causing the behavior (there are other processes running with the app) but the service doesn't even start, it doesn't even acquire the wake lock until some 10 seconds later.

It's worth mentioning this behavior is most pronounced on the Nexus 4 where up to 30% of the data is missing, while it's substantially less on the Galaxy SII and Nexus 7 (around ~2%) but it's still a concern since it's unexplained behavior.


Solution

  • You did not state what sort of alarm that you are using, but given your complaints, I assume that it is a _WAKEUP alarm. If so, the only guarantee we have is if we use a broadcast PendingIntent, Android will keep the device awake during the call to onReceive(). Using a service PendingIntent, as you are doing, is unreliable, as the device could fall back asleep before the service starts up and can acquire a WakeLock.

    Hence, a more reliable pattern for a _WAKEUP alarm is to use a broadcast PendingIntent, have the BroadcastReceiver acquire() the WakeLock, then have it call startService() to pass control to your service. Your service does its work, then releases the WakeLock.

    I have this pattern wrapped up in my WakefulIntentService component.