web-dev-qa-db-fra.com

java.lang.SecurityException:! @Trop de plusieurs alarmes (500) enregistrées à partir du pid 10790 uid 10206

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.

31
Manpreet Patil

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);
    } 
44
sagiema

Pour ceux qui rencontrent ce problème uniquement sur les appareils Samsung exécutant Lollipop, vous utilisez probablement FLAG_CANCEL_CURRENT avec vos PendingIntents. 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 PendingIntents?) Jusqu'à ce qu'ils soient redémarrés ou que l'application soit réinstallée.

4
goncalossilva

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.

2
ctate

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.

1
jguerinet

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.

1
Dominikus K.