java.lang.SecurityException: !@Too many alarms (500) registered from pid 10790 uid 10206

I'm getting this error at the time of Schedule alarm using Alarm Manager

am.setExact(AlarmManager.RTC_WAKEUP, timeMillis, pendingIntent);

Error is as follow

java.lang.SecurityException: !@Too many alarms (500) registered from pid 10790 uid 10206
at android.os.Parcel.readException(Parcel.java:1540)
at android.os.Parcel.readException(Parcel.java:1493)
at android.app.IAlarmManager$Stub$Proxy.set(IAlarmManager.java:206)
at android.app.AlarmManager.setImpl(AlarmManager.java:428)
at android.app.AlarmManager.setExact(AlarmManager.java:376)

Why this error is coming and how we can fix it.


Unlike what the comment suggests, this might not be your fault. This started happening for us in production code somewhere mid March, this only happens on Samsung with Lollipop which only recently started to be rolled out.

Update: This issue finally happened on one of the phones we have available.

like @goncalossilva said the problem is due to use of FLAG_CANCEL_CURRENT, it seems that Samsung introduces a cap of 500 on the amount of alarms and no other vendor have this limit.

when creating a PendingIntent with FLAG_CANCEL_CURRENT it will cancel the pending intent (obviously) won't cancel the alarm (also obvious), later if you cancel the alarm using the new pending intent it won't cancel the alarm (less obvious as Intent.filterEquals should be true). That being said, because the pending intent was canceled the old alarm won't actually fire, so there it no fear in introducing bugs by switching FLAG_UPDATE_CURRENT.

regarding the need to restart the device after changing to FLAG_UPDATE_CURRENT, you don't have to restart you just need to wait for one of the alarms to fire so that you have a new slot for a new alarm.

you can try this code to reproduce the issue, then change to FLAG_UPDATE_CURRENT to see what happens. you should also run "adb shell dumpsys alarm" to see all the generated alarms

    AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);

    for (int i = 0; i<1000; i++)
    {
        Intent intent = new Intent("FOOFOOFOO");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        alarmManager.cancel(pendingIntent);

        long firstTime = SystemClock.elapsedRealtime() + 1000;
        alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, pendingIntent);
    } 

For those encountering this problem solely on Samsung devices running Lollipop, you are probably using FLAG_CANCEL_CURRENT with your PendingIntents. Switch to FLAG_UPDATE_CURRENT (making any other adjustments, if necessary), and the problem should go away.

My completely unfounded guess is that Samsung is doing some "optimizations" with FLAG_CANCEL_CURRENT where they don’t remove the canceled PendingIntent right away but only mark it for deletion and then do it too infrequently (or not at all?).

Edit

We've found that devices where this problem occurs will be in a broken state (filled with PendingIntents?) until they are restarted or the app is reinstalled.


Never use FLAG_CANCEL_CURRENT with PendingIntents that you use when setting alarms. If you want to reschedule the alarm for a different time you don't need any flag at all; just create a duplicate PendingIntent with flags of zero and then use it to set() an alarm: this will implicitly cancel the existing alarm and then set it for the newly-specified time. If you used FLAG_CANCEL_CURRENT when you created the new PendingIntent, though, it breaks the Alarm Manager's ability to recognize that it's "the same" as the now-canceled PendingIntent, and you wind up with the old one hanging around, undeliverable, taking up memory and CPU. I've seen apps with this bug rack up literally hundreds of stale alarms in the system, enough to be a noticeable performance and memory-usage hit.

If you just want to change the extras without actually rescheduling the existing alarm, that is what FLAG_UPDATE_CURRENT is for. If you just want to reschedule or cancel the alarm, just use 0 for the flags.