In the past, many Samsung i9000 Galaxy S users reported a critical bug. Sometimes, the alarm just does not go off until they activate the display. This missbehaviour appears on every i9000 phone with Android 2.1 and is caused by a critical firmware bug, as I figured out.
AlarmDroid makes (like many other applications where events are triggered time-based) use of Android’s AlarmManager. This built-in class is used to trigger certain events at certain times. In this way, it is possible to wake up the device at a given time to perform some actions. It’s implemented this way in order to prevent battery consumption. E.g. AlarmDroid also schedules its alarm events using this mechanism. So there is NO battery consumption until the alarm goes off. And the same while AlarmDroid remains in snooze mode. And the most important aspect: It is intended to work even while the device is sleeping.
So as some users reported, the AlarmManager does not work as well as it should on their devices. This bug was already known in the past on the Motorola Milestone, they fixed it later on within a firmware upgrade.A brief experiment
In the last days, an AlarmDroid user (Thank you, Davyd!) was so kind to participate in a little experiment. I prepared a small service-based application that schedules a repeating alarm to the AlarmManager, one event per minute. Every time the event receiver is called, it saves the current time (in milliseconds) to a log file, in order to compare preset time with the real time, which is expected to be delayed in some cases. For comparison, I ran the same test on my HTC Desire.The results
I measured the time on which the alarm went off and the corresponding preset time, and plotted both against each other. If all alarms were fired up at the right time, it should look highly linear. The first figure shows the results of the HTC Desire. Since I never noticed the mentioned bug on my phone, I expect a linear graph. And indeed, it looks like it should. Every alarm went of at the correct time. The maximum delay was about 614ms, the mean delay about 207ms.
On the contrary, the results of the i9000 Galaxy S deviate considerably from this test:
Here, 33 of 480 events (6.9%) failed! The plot above shows a typical sample. Event 1 and 2 are delayed 3 minutes in each case. Event 3 has a delay of 2 minutes, event 4 of 1 minute and event 5 finally woke up the CPU correctly. So event 1, 2, 3 and 4 failed to wake up the CPU.
Now, the very odd thing is that event 2, 3, 4 and 5 were received at the same time, like expected, but event 1 was already received at the time on which actually event 4 should be received. This makes no sense at all and needs to adjust our speculation. Possibly, the CPU went on, but did not last until the event’s receive method was completed, although I used a «PARTIAL_WAKE_LOCK» to keep the CPU running.A workaround
So in the end, we need a workaround in order to treat this problem. Because the CPU woke up on the 4th try at the latest, I changed my test application in the following way. I added a second alarm event receiver that holds an own partial wake lock. Before the actual alarm event should be go off, the second receiver is triggered 10 times, e.g. 10s before, 9s before, n seconds, …. and 1s before. Every receiver holds a wakelock for a duration of n+1 seconds. So most likely, the CPU will already be awake for a few seconds when the final alarm is fired.
This works pretty well. I repeated the experiment last night with the modification described above, and here are the results:
* Fails: 0 / 375 (0%)
* Maximum delay: 194ms
* Mean delay: 22ms
So with this workaround, it works very accurate and reliable!