Je reçois cette erreur au moment de programmer l'alarme à l'aide d'Alarm Manager
am.setExact(AlarmManager.RTC_WAKEUP, timeMillis, pendingIntent);
L'erreur est la suivante
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)
Pourquoi cette erreur arrive et comment nous pouvons la corriger.
Contrairement à ce que suggère le commentaire, ce n'est peut-être pas de votre faute. Cela a commencé à se produire pour nous dans le code de production vers la mi-mars, cela ne se produit que sur Samsung avec Lollipop qui n'a commencé que récemment à être déployé.
Mise à jour: ce problème s'est finalement produit sur l'un des téléphones dont nous disposons.
comme @goncalossilva, le problème est dû à l'utilisation de FLAG_CANCEL_CURRENT
, il semble que Samsung introduit un plafond de 500 sur le nombre d'alarmes et aucun autre fournisseur n'a cette limite.
lors de la création d'un PendingIntent
avec FLAG_CANCEL_CURRENT
il annulera l'intention en attente (évidemment) n'annulera pas l'alarme (également évident), plus tard si vous annulez l'alarme en utilisant la nouvelle intention en attente, il n'annulera pas l'alarme (moins évident que Intent.filterEquals
doit être true
). Cela étant dit, comme l'intention en attente a été annulée, l'ancienne alarme ne se déclenchera pas, donc il n'y a aucune crainte à introduire des bogues en commutant FLAG_UPDATE_CURRENT
.
concernant la nécessité de redémarrer l'appareil après être passé à FLAG_UPDATE_CURRENT
, vous n'avez pas besoin de redémarrer, il vous suffit d'attendre que l'une des alarmes se déclenche pour disposer d'un nouvel emplacement pour une nouvelle alarme.
vous pouvez essayer ce code pour reproduire le problème, puis passez à FLAG_UPDATE_CURRENT
pour voir ce qui se passe. vous devez également exécuter "adb Shell dumpsys alarm"
pour voir toutes les alarmes générées
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);
}
Pour ceux qui rencontrent ce problème uniquement sur les appareils Samsung exécutant Lollipop, vous utilisez probablement FLAG_CANCEL_CURRENT
avec vos PendingIntent
s. Basculer vers FLAG_UPDATE_CURRENT
(en faisant d'autres ajustements, si nécessaire), et le problème devrait disparaître.
Ma supposition totalement infondée est que Samsung fait des "optimisations" avec FLAG_CANCEL_CURRENT
où ils ne suppriment pas immédiatement le PendingIntent
annulé, mais le marquent uniquement pour suppression, puis le font trop rarement (ou pas du tout?).
Modifier
Nous avons constaté que les appareils sur lesquels ce problème se produit seront dans un état défectueux (remplis de PendingIntent
s?) Jusqu'à ce qu'ils soient redémarrés ou que l'application soit réinstallée.
Jamais utilisez FLAG_CANCEL_CURRENT avec PendingIntents que vous utilisez lors de la définition des alarmes. Si vous souhaitez replanifier l'alarme pour une heure différente, vous n'avez pas besoin d'indicateur du tout; créez simplement un PendingIntent en double avec des drapeaux de zéro, puis utilisez-le pour définir () une alarme: cela annulera implicitement l'alarme existante, puis la définira pour la nouvelle heure spécifiée. Si vous avez utilisé FLAG_CANCEL_CURRENT lorsque vous avez créé le nouveau PendingIntent, cela brise la capacité du gestionnaire d'alarmes à reconnaître qu'il est "le même" que le PendingIntent maintenant annulé, et vous vous retrouvez avec l'ancien qui traîne, non livrable, prenant de la mémoire et CPU. J'ai vu des applications avec ce bogue accumuler littéralement des centaines d'alarmes périmées dans le système, suffisamment pour être un succès notable en termes de performances et d'utilisation de la mémoire.
Si vous souhaitez simplement modifier les extras sans vraiment replanifier l'alarme existante, c'est à cela que sert FLAG_UPDATE_CURRENT. Si vous souhaitez simplement replanifier ou annuler l'alarme, utilisez simplement 0 pour les indicateurs.
Il semble que la dernière version de Lollipop sur les appareils Samsung limite le nombre d'alarmes que vous pouvez enregistrer. J'ai temporairement résolu le problème dans mon application en enregistrant uniquement au plus X alarmes à un moment donné (j'ai choisi arbitrairement X = 50 mais à en juger par le message d'erreur, je pense que vous pouvez aller jusqu'à 499. Je n'ai pas testé cela pourtant).
J'ai publié une version avec ce correctif temporaire il y a une semaine et je n'ai plus signalé ce plantage depuis.
Pour moi, le passage à FLAG_UPDATE_CURRENT
Seul n'a pas aidé à se débarrasser des entrées multiples de mes Intents en attente (regardé avec adb Shell dumpsys alarm > dump.txt
).
Je l'ai corrigé en modifiant la façon dont j'annule ces intentions en attente de
PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT).cancel();
à
PendingIntent pi = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT).cancel();
alarmManager.cancel(pi);
Cela était nécessaire pour .getBroadcast()
et .getService()
. Fait intéressant avec .getActivity()
ce n'était pas le cas. Malheureusement, je ne sais pas pourquoi c'est le cas.
Le tout sur un Samsung Galaxy S4 avec Android 5.0.1. Peut-être que cela aide aussi quelqu'un d'autre.