PendingIntent
has an interesting property: not only does it bundle up an Intent
and the operation to be performed upon it, but it also effectively bundles up the security context in which that operation is performed.
In other words, it can be used to allow a foreign process to talk to one of your components, even if that component is not exported.
We see this a lot in standard uses of PendingIntent
, such a AlarmManager
or Notification
. We usually use an explicit Intent
inside the PendingIntent
(e.g., new Intent(this, MyOtherComponent.class)
). And usually those components do not have an <intent-filter>
or are otherwise exported in our manifest. Yet, they work. That's because while the OS process that manages alarms and/or notifications does not have the right to talk to our component normally, it can execute the PendingIntent
, and the PendingIntent
is our way of saying "yes, you can talk to this component, but only for whatever this PendingIntent
does, not arbitrary stuff".
So, if one app wants to set up a callback mechanism with another app, a slick approach is to use a PendingIntent
. The first app's component (e.g., BroadcastReceiver
) does not have to be exported, let alone have an <intent-filter>
. Yet, the second app can trigger that component via the PendingIntent
. Since a PendingIntent
is Parcelable
, it can be packaged easily enough as an extra on some other Intent
, passed via an AIDL-defined interface for a bound service, or otherwise traverse process boundaries.