Android AlarmManager sometimes runs late if the phone is running on battery power

* Updated: the problem was probably resolved. Please refer to the update below, since AlarmManager was only partially to blame. *

I am currently developing an Android app with alarm functions. Unfortunately, it turned out that there seem to be some rather specific cases for which the AlarmManager does not work as expected.

When I initially tested the application, I did it using Android Studio Emulator (Nexus 5, API 21), as well as an old phone (Galaxy S2, API 16), as a result of which all the alarms were delivered on time. As soon as I switched to my Xperia Z1 Compact (API 19), although the alarms suddenly triggered minutes later.

Interestingly, this is similar to the case, especially when the phone is currently running on battery (i.e. not connected to a PC or power outlet). It is like AlarmManager will suddenly become super sluggish in a desperate attempt to save battery, completely ignoring the fact that it was used with .setExact (). If the device does not sleep, delivery is always on time.

In any case, the behavior that results from my code does not seem to be deterministic, which really scares my mind.

A simplified version of my code:

First, I plan on AlarmManager depending on the API. According to the log calendar, the correct date and time is set.

public abstract class AlarmScheduler { //... private static void schedule(AlarmManager am, PendingIntent pi, Calendar calendar){ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { am.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pi); } else { am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pi); } } //... } 

The expected intention that is planned is the WakefulBroadcastReceiver. According to the logs, every time the alarm clock is late, the call to onReceive () is also at least as far as I saw. Therefore, it seems likely that the problem is here.

 public class AlarmReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent service = new Intent(context, AlarmService.class); service.putExtras(intent); startWakefulService(context, service); } } 

For completeness, this is the service that BroadcastReceiver launches. The action that the service starts acquires its own wakelock in onResume (). I also tried forcibly delaying the release of the wakelock receiver to 1000 ms to ensure that it is active at all times, but this did not give different results.

 public class AlarmService extends Service { @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Intent alarmDisplay = new Intent(getBaseContext(), AlarmActivity.class); alarmDisplay.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); alarmDisplay.putExtras(intent); getApplication().startActivity(alarmDisplay); /** Some simple database operations here */ AlarmReceiver.completeWakefulIntent(intent); return super.onStartCommand(intent, flags, startId); } } 

I honestly got lost where I was wrong. But since an alarm clock that can start for several minutes on some devices is certainly unacceptable, I would really appreciate any input - thanks in advance.

UPDATE

Good, so first of all, AlarmManager.setExact () really works until late, but only seconds, not minutes. According to the documentation, this is apparently intended as it reads:

"The alarm will be delivered as close as possible to the requested start time."

Unfortunately, this sounds like milliseconds, not seconds, so I assumed that AlarmManager was behaving incorrectly. If he obviously delivered a few seconds later, I thought he was able to deliver minutes later. However, my mistake is ultimately.

Secondly, the problem described at the beginning was the Wakelock problem, which, at least in my case, only showed up on my phone with API 19+ when it was currently running on battery. While API 19 seems to have introduced very aggressive power management for the sake of the battery, the management seems even more aggressive if the phone is running on battery power. This, apparently, is also the reason that everything worked fine on the emulator (by default it is always in the process of charging, if you need to believe the icons).

The problem with the originally published code is that the wakelock receiver is freed before the activity acquires its own wakelock in onResume (). Just a matter of milliseconds, but still enough to make the processor seem to be thrown back. As I said in my initial post, I already thought of this as a potential source of the problem, so I tried to delay the release of wakelock strongly to ensure that at least one would be active at all. For testing, I did it quickly and dirty with wait (), although the OS seemed to not really like it and thus forcibly disconnected my service at some point, which was not something that did not appear on regular logcat output. From now on, subsequent alarms were usually faulty, although I am not knowledgeable enough from the point of view of Android to really explain why.

In any case, the problem can be solved by purchasing and releasing only one single wakelock instead of two separate ones (note that due to the nature of the problem there is no absolute certainty, but the test results look great).

+7
android alarmmanager
source share

No one has answered this question yet.

See related questions:

2097
Is there a way to run Python on Android?
890
How to check if the service is running on Android?
4
Android AlarmManager does not work when the phone is sleeping
3
What is the best thing between AlarmManager and Handler + WakeLock?
2
Battery Conservation and AlarmManager Performance
one
AlarmManager sometimes does not wake up the phone (XPERIA)
one
Android AlarmManager for reading periodic sensors
0
Android AlarmManager setRepeating Issue
0
AlarmManager - does not turn off if set to 10 minutes
0
ANDROID: AlarmManager, PowerManager.WakeLock and asynchronous call?

All Articles