Java.lang.SecurityException:! @Too много сигналов тревоги (500), зарегистрированных с pid 10790 uid 10206

Я получаю эту ошибку во время расписания с помощью Alarm Manager

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

Ошибка следующая.

 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) 

Почему эта ошибка приходит и как мы можем ее исправить.

Solutions Collecting From Web of "Java.lang.SecurityException:! @Too много сигналов тревоги (500), зарегистрированных с pid 10790 uid 10206"

В отличие от комментариев, это может быть не ваша ошибка. Это началось для нас в производственном коде где-то в середине марта, это происходит только на Samsung с Lollipop, который только недавно начал выпускаться.

Обновление: эта проблема, наконец, произошла на одном из доступных нами телефонов.

Например, @goncalossilva заявила, что проблема связана с использованием FLAG_CANCEL_CURRENT , похоже, что Samsung вводит ограничение в размере 500 на количество аварийных сигналов, и ни один другой поставщик не имеет этого ограничения.

При создании PendingIntent с FLAG_CANCEL_CURRENT он отменит ожидающее намерение (очевидно) не отменит сигнал тревоги (также очевидно), позже, если вы отмените будильник с помощью нового ожидающего намерения, он не отменяет сигнал тревоги (менее очевидным как Intent.filterEquals должно быть true ). При этом, поскольку ожидаемое намерение было отменено, старая тревога на самом деле не срабатывает, поэтому нет опасений в том, что вы FLAG_UPDATE_CURRENT ошибки, переключая FLAG_UPDATE_CURRENT .

В связи с необходимостью перезапуска устройства после перехода на FLAG_UPDATE_CURRENT , вам не нужно перезагружать компьютер, вам просто нужно дождаться, когда один из аварийных сигналов будет FLAG_UPDATE_CURRENT , чтобы у вас появился новый слот для нового сигнала тревоги.

Вы можете попробовать этот код для воспроизведения проблемы, а затем перейти на FLAG_UPDATE_CURRENT чтобы узнать, что произойдет. Вы также должны запустить "adb shell dumpsys alarm" чтобы увидеть все сгенерированные аварийные сигналы

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

Для тех, кто сталкивается с этой проблемой исключительно на устройствах Samsung, работающих с Lollipop, вы, вероятно, используете FLAG_CANCEL_CURRENT с вашим PendingIntent s. Переключитесь на FLAG_UPDATE_CURRENT (при необходимости FLAG_UPDATE_CURRENT любые другие настройки), и проблема должна исчезнуть.

Мое совершенно необоснованное предположение заключается в том, что Samsung делает некоторые «оптимизации» с FLAG_CANCEL_CURRENT где они сразу не удаляют отмененный PendingIntent а только отмечают его для удаления, а затем делают это слишком редко (или вообще не?).

редактировать

Мы обнаружили, что устройства, в которых происходит эта проблема, будут в состоянии разбиты (заполнены PendingIntent s?) До тех пор, пока они не будут перезапущены или приложение не будет переустановлено.

Кажется, что новейшие Lollipop на устройствах Samsung ограничивают количество тревог, которые вы можете зарегистрировать. Я временно исправил проблему в своем приложении, зарегистрировав не более X аварийных сигналов в любой момент времени (я произвольно выбрал X = 50, но, судя по сообщению об ошибке, я считаю, что вы можете подняться до 499. Я не тестировал это Однако).

Я выпустил версию с этим временным исправлением неделю назад, и с этого момента я не сообщал об этом сбое.

Для меня изменение только на FLAG_UPDATE_CURRENT не помогло избавиться от нескольких записей моих pendingIntents (просмотренных с помощью adb shell dumpsys alarm > dump.txt ).

Я исправил это, изменив способ отмены этих ожидающих намерений

 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); 

Это было необходимо для .getBroadcast() и .getService() . Интересно, что с .getActivity() это не так. К сожалению, я не знаю, почему это так.

Все на Samsung Galaxy S4 с Android 5.0.1. Возможно, это помогает и кому-то другому.

Никогда не используйте FLAG_CANCEL_CURRENT с PendingIntents, которые вы используете при настройке аварийных сигналов. Если вы хотите перенести будильник на другое время, вам совсем не нужен какой-либо флаг; Просто создайте дубликат PendingIntent с флагами с нулем, а затем используйте его для установки () тревоги: это косвенно отменяет существующий аварийный сигнал, а затем устанавливает его для вновь заданного времени. Если вы использовали FLAG_CANCEL_CURRENT, когда вы создали новый PendingIntent, тем не менее, он нарушает способность диспетчера Alarm распознавать, что он «тот же», что и теперь отмененный PendingIntent, и вы завершаетесь старым, который висит вокруг, недоступен, занимает память И процессор. Я видел, что приложения с этой ошибкой заполняют буквально сотни устаревших сигналов тревоги в системе, что достаточно для заметной производительности и использования памяти.

Если вы просто хотите изменить дополнительные функции, не переназначая существующий аварийный сигнал, для этого необходим FLAG_UPDATE_CURRENT. Если вы просто хотите перенести или отменить будильник, просто используйте 0 для флагов.

Я исправил его с помощью флага: PendingIntent.FLAG_UPDATE_CURRENT

 PendingIntent pendingIntent = PendingIntent.getService( MainActivity.this, 200, intent, PendingIntent.FLAG_UPDATE_CURRENT ); am.setExact(AlarmManager.ELAPSED_REALTIME, realtime + 2000, pendingIntent); 

Я тестировал его в Galaxy S4, работающий в Android 5.0.1.