Подтвердить что ты не робот

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

Я получаю эту ошибку во время тревоги по расписанию с помощью диспетчера аварийных сигналов

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

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

java.lang.SecurityException: [email protected] 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)

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

4b9b3361

Ответ 1

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

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

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

при создании PendingIntent с FLAG_CANCEL_CURRENT он отменяет ожидающее намерение (очевидно) не отменяет сигнал тревоги (также очевидно), позже, если вы отмените будильник с помощью нового ожидающего намерения, он не отменяет (менее очевидно, как Intent.filterEquals должно быть true). При этом, поскольку ожидаемое намерение было отменено, старая тревога на самом деле не срабатывает, поэтому нет никаких опасений при введении ошибок путем переключения 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);
    } 

Ответ 2

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

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

Edit

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

Для меня изменение только на 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. Возможно, это тоже помогает кому-то другому.

Ответ 6

Я исправил его с помощью флага: 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.