Открыть сервис

PendingIntent

PendingIntent — это специальный объект в операционной системе Android, предоставляющий механизм для отложенного выполнения действия от имени приложения, даже если само приложение в данный момент неактивно или не запущено. По сути, это токен (маркер), который передаётся другому компоненту системы (например, системному менеджеру уведомлений, будильнику, другому приложению) и позволяет этому компоненту в будущем выполнить заранее заданное действие — запустить Activity, Service, BroadcastReceiver или отправить Intent — с теми же правами и разрешениями, что и у исходного приложения.

Принцип работы

Основная идея PendingIntent заключается в том, что приложение создаёт «заготовку» намерения (Intent), упаковывает её в объект PendingIntent и передаёт другому компоненту системы. Этот компонент, когда наступает подходящий момент (например, пользователь нажимает на уведомление, срабатывает будильник, поступает Push-уведомление), вызывает метод send() у объекта PendingIntent, что приводит к выполнению исходного Intent. При этом система Android при выполнении восстанавливает контекст исходного приложения, включая его идентификатор (UID) и разрешения, что гарантирует, что действие выполняется от имени создателя, а не вызывающего компонента.

Типы PendingIntent

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

  • FLAG_ONE_SHOT: PendingIntent может быть выполнен только один раз. После вызова send() он становится недействительным. Используется для одноразовых действий, например, для реакции на нажатие кнопки в уведомлении, которое после нажатия должно исчезнуть.
  • FLAG_NO_CREATE: Если PendingIntent с данным Intent уже существует, он возвращается, но не создаётся новый. Если не существует — возвращается null. Используется для проверки существования PendingIntent без его создания.
  • FLAG_CANCEL_CURRENT: Если PendingIntent с данным Intent уже существует, он отменяется (становится недействительным) и создаётся новый. Полезно для обновления данных в уведомлениях, когда старый Intent должен быть заменён.
  • FLAG_UPDATE_CURRENT: Если PendingIntent с данным Intent уже существует, он не отменяется, а обновляется: его внутренний Intent заменяется новым, но сам объект PendingIntent остаётся тем же. Это наиболее распространённый флаг для обновления уведомлений, так как позволяет сохранить привязку к существующему уведомлению.
  • FLAG_IMMUTABLE (добавлен в Android 6.0, API 23): PendingIntent является неизменяемым — его внутренний Intent не может быть изменён другими приложениями. Рекомендуется для всех новых приложений, так как повышает безопасность, предотвращая атаки типа «замена Intent» (Intent redirection).
  • FLAG_MUTABLE (добавлен в Android 12, API 31): PendingIntent является изменяемым — его внутренний Intent может быть модифицирован вызывающим компонентом. Используется только в тех случаях, когда это необходимо по функциональности (например, для заполнения данных в Intent сторонним приложением).

Создание PendingIntent

Для создания PendingIntent используются статические методы классов PendingIntent, которые принимают контекст, запрос (request code), сам Intent и флаги:

  • PendingIntent.getActivity() — для запуска Activity.
  • PendingIntent.getService() — для запуска Service.
  • PendingIntent.getBroadcast() — для отправки BroadcastReceiver.

Пример создания PendingIntent для запуска Activity при нажатии на уведомление:

``java Intent intent = new Intent(context, TargetActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); ``

Применение

PendingIntent широко используется в Android для реализации различных сценариев взаимодействия между компонентами системы:

  • Уведомления (Notifications): Наиболее распространённое применение. При создании уведомления через NotificationCompat.Builder или Notification.Builder объект PendingIntent передаётся в метод setContentIntent(). При нажатии на уведомление система вызывает этот PendingIntent, что приводит к открытию указанного Activity. Также PendingIntent используется для действий на кнопках уведомлений (addAction()).
  • Будильники (AlarmManager): При установке будильника через AlarmManager.set() передаётся PendingIntent, который будет выполнен в заданное время. Это может быть запуск Service, BroadcastReceiver или Activity.
  • Виджеты (AppWidgets): При нажатии на элемент виджета (например, кнопку) система вызывает PendingIntent, который был установлен для этого элемента через RemoteViews.setOnClickPendingIntent().
  • Push-уведомления (Firebase Cloud Messaging): При получении Push-уведомления, которое содержит данные для открытия определённого экрана, приложение создаёт PendingIntent и передаёт его в системное уведомление.
  • Запуск приложений из других приложений: Приложение может передать PendingIntent другому приложению, чтобы то выполнило действие от имени первого. Например, приложение-календарь может передать PendingIntent для открытия события, а приложение-напоминание — для его выполнения.
  • Системные вызовы: Некоторые системные сервисы, такие как NotificationManager, AlarmManager, AppWidgetManager, принимают PendingIntent для выполнения действий в будущем.

Безопасность

Использование PendingIntent связано с рядом рисков безопасности, особенно в многопользовательской среде Android. Основные угрозы:

  • Перехват Intent (Intent hijacking): Если PendingIntent является изменяемым (FLAG_MUTABLE), злоумышленник может изменить его внутренний Intent, перенаправив действие на свой компонент. Это может привести к утечке данных или выполнению несанкционированных действий. Для защиты рекомендуется использовать FLAG_IMMUTABLE во всех случаях, кроме тех, где изменяемость необходима.
  • Замена PendingIntent (PendingIntent replacement): Если приложение создаёт PendingIntent с одинаковым Intent и request code, но с флагом FLAG_CANCEL_CURRENT, старый PendingIntent отменяется, что может нарушить работу других компонентов, ожидающих его выполнения.
  • Утечка контекста: PendingIntent сохраняет ссылку на контекст приложения, что может привести к утечке памяти, если объект PendingIntent не освобождается своевременно.

Рекомендации по безопасному использованию:

  • Всегда указывать FLAG_IMMUTABLE для PendingIntent, если не требуется изменяемость.
  • Использовать уникальные request code для разных PendingIntent, чтобы избежать конфликтов.
  • Не передавать PendingIntent ненадёжным приложениям без необходимости.
  • Проверять, что Intent, который будет выполнен, не содержит конфиденциальных данных, которые могут быть перехвачены.

История версий

  • Android 1.0 (API 1): PendingIntent представлен как часть базового фреймворка.
  • Android 6.0 (API 23): Введён флаг FLAG_IMMUTABLE, но его использование стало обязательным только с Android 12.
  • Android 12 (API 31): Введён флаг FLAG_MUTABLE. При создании PendingIntent без указания FLAG_IMMUTABLE или FLAG_MUTABLE система выдаёт предупреждение, а начиная с Android 15 (API 35) такое создание вызывает исключение IllegalArgumentException. Это сделано для повышения безопасности.

Источники

  • Android Developers. PendingIntent. Официальная документация.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →