结论: PendingIntent 是延迟触发的一种 Intent , 通过上图的过程看,PendingIntent 的执行,是一种跨进程通信.首先创建PendingIntent对象时,就把该对象定义到 ActivityManagerService, 到执行 PengdingIntent 动作时, 也是在 ActivityManagerService 找到 目标PengdingIntent, 从而执行相应操作.
使用场景: Android 通知的 setContentIntent() 需要传入 PendingIntent , 即当点击通知时,执行 intent 的动作.如下例子:
Intent intent = new Intent(this, MainActivity1.class);
//1.获取能启动 Activity 的PendingIntent 对象
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_MUTABLE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "channel_id")
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Notification Title")
.setContentText("Notification content text...")
.setContentIntent(pendingIntent) //2.设置PendingIntent
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManager notificationManager = (NotificationManager.class);
NotificationChannel channel = new NotificationChannel("11", "channel-name", NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
notificationManager.notify(11, builder.build());
核心源码路径 : frameworks/base/core/java/android/app/PendingIntent.java
1. 跳转到 Activity ,指定一个 Activity
public static PendingIntent getActivity(Context context, int requestCode,
Intent intent, @Flags int flags)
2. 跳转到 Activity , 指定多各 Activity
public static PendingIntent getActivities(Context context, int requestCode,
@NonNull Intent[] intents, @Flags int flags)
3. 打开 广播 组件
public static PendingIntent getBroadcast(Context context, int requestCode,
@NonNull Intent intent, @Flags int flags)
4. 打开 服务 组件
public static PendingIntent getService(Context context, int requestCode,
@NonNull Intent intent, @Flags int flags)
? ? 1) FLAG_ONE_SHOT :??PendingIntent 只能使用一次.该标签后面还能说明.
? ? 2) FLAG_NO_CREATE :?不创建 PendingIntent, 如果PendingIntent存在,则返回null.
? ? 3) FLAG_CANCEL_CURRENT :?如果所描述 PendingIntent 已存在,则在生成新的 PendingIntent 之前,取消当前已存在的PendingIntent.
? ? 4) FLAG_UPDATE_CURRENT :?如果所描述 PendingIntent 已存在,则保留该对象,并用新的数据更新该对象.
? ? 5) FLAG_IMMUTABLE : PendingIntent 不可变.
? ? 6) FLAG_MUTABLE :?PendingIntent 可变.
以上图通知的代码为例子,说明创建 PendingIntent 对象的过程.
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_MUTABLE);
核心源码路径 : frameworks/base/core/java/android/app/PendingIntent.java
public static PendingIntent getActivity(Context context, int requestCode,
Intent intent, @Flags int flags) {
return getActivity(context, requestCode, intent, flags, null);
}
public static PendingIntent getActivity(Context context, int requestCode,
@NonNull Intent intent, @Flags int flags, @Nullable Bundle options) {
// Some tests only mock Context.getUserId(), so fallback to the id Context.getUser() is null
final UserHandle user = context.getUser();
return getActivityAsUser(context, requestCode, intent, flags, options,
user != null ? user : UserHandle.of(context.getUserId()));
}
public static PendingIntent getActivityAsUser(Context context, int requestCode,
@NonNull Intent intent, int flags, Bundle options, UserHandle user) {
String packageName = context.getPackageName(); //获取包名
String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
checkFlags(flags, packageName);
try {
intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
INTENT_SENDER_ACTIVITY, packageName,
context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, options, user.getIdentifier()); //获取 IntentSender
return target != null ? new PendingIntent(target) : null; //创建 PendingIntent 对象,
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
? ? ? ?上面最终会调用到 getActivityAsUser( ) , 其中 创建 PendingIntent 对象的时候,需要传入 IIntentSender target 的对象, 而该对象是从 ActivityManagerService.getIntentSenderWithFeature( ) 获取,其中的第一个参数,这里传递的是?INTENT_SENDER_ACTIVITY , 代码获取启动 activity 的PendingIntent , 其他的类型如下:
核心源码路径 : frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public IIntentSender getIntentSenderWithFeature(int type, String packageName, String featureId,
IBinder token, String resultWho, int requestCode, Intent[] intents,
String[] resolvedTypes, int flags, Bundle bOptions, int userId) {
enforceNotIsolatedCaller("getIntentSender");
return getIntentSenderWithFeatureAsApp(type, packageName, featureId, token, resultWho,
requestCode, intents, resolvedTypes, flags, bOptions, userId,
Binder.getCallingUid());
}
public IIntentSender getIntentSenderWithFeatureAsApp(int type, String packageName,
String featureId, IBinder token, String resultWho, int requestCode, Intent[] intents,
String[] resolvedTypes, int flags, Bundle bOptions, int userId, int owningUid) {
if (intents != null) {
if (intents.length < 1) { //必须指定至少一个intent
throw new IllegalArgumentException("Intents array length must be >= 1");
}
for (int i=0; i<intents.length; i++) {
Intent intent = intents[i];
if (intent != null) {
if (intent.hasFileDescriptors()) { //不能携带文件描述符
throw new IllegalArgumentException("File descriptors passed in Intent");
}
//广播类的PendingIntent中,定义的intent不能携带 FLAG_RECEIVER_BOOT_UPGRADE(启动并升级) 的标签
if (type == ActivityManager.INTENT_SENDER_BROADCAST &&
(intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
throw new IllegalArgumentException(
"Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
}
intents[i] = new Intent(intent);
}
}
if (resolvedTypes != null && resolvedTypes.length != intents.length) {
throw new IllegalArgumentException(
"Intent array length does not match resolvedTypes length");
}
}
if (bOptions != null) {
if (bOptions.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in options");
}
}
int origUserId = userId;
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), owningUid, userId,
type == ActivityManager.INTENT_SENDER_BROADCAST,
ALLOW_NON_FULL, "getIntentSender", null);
if (origUserId == UserHandle.USER_CURRENT) {
// We don't want to evaluate this until the pending intent is
// actually executed. However, we do want to always do the
// security checking for it above.
userId = UserHandle.USER_CURRENT;
}
try {
if (owningUid != 0 && owningUid != SYSTEM_UID) {
final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(owningUid));
if (!UserHandle.isSameApp(owningUid, uid)) {
String msg = "Permission Denial: getIntentSender() from pid="
+ Binder.getCallingPid()
+ ", uid=" + owningUid
+ ", (need uid=" + uid + ")"
+ " is not allowed to send as package " + packageName;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
return mAtmInternal.getIntentSender(type, packageName, featureId, owningUid,
userId, token, resultWho, requestCode, intents, resolvedTypes, flags,
bOptions);
}
// 继续调用 PendingIntentController 类的getIntentSender()来获取IIntentSender
return mPendingIntentController.getIntentSender(type, packageName, featureId,
owningUid, userId, token, resultWho, requestCode, intents, resolvedTypes,
flags, bOptions);
} catch (RemoteException e) {
throw new SecurityException(e);
}
}
? ? ? ?通过对 intent 等信息的过滤后,函数的最后继续调用 PendingIntentController 类的 getIntentSender() 方法来获取 IIntentSender 对象(请看下面(4)), 在介绍?getIntentSender( )之前,首先介绍一下,系统把每个?PendingIntent 对象都封装成 PendingIntentRecord 对象,然后通过PendingIntentController 对象来统一管理?PendingIntentRecord 对象,从而达到管理?PendingIntent .
核心代码路径 : frameworks/base/services/core/java/com/android/server/am/PendingIntentRecord.java
public final class PendingIntentRecord extends IIntentSender.Stub {
final PendingIntentController controller;
final Key key; //内部类对象
final int uid;
public final WeakReference<PendingIntentRecord> ref;
boolean sent = false;
boolean canceled = false;
// PendingIntentRecord对象的内部类,主要用于存储PendingIntent 对象中的参数
final static class Key {
final int type;
final String packageName;
final String featureId;
final IBinder activity;
final String who;
final int requestCode;
final Intent requestIntent; //获取最后一个intent,一般情况下都是指定一个intent
final String requestResolvedType;
final SafeActivityOptions options;
Intent[] allIntents; //获取所有的intent,如果设定了多个intent
String[] allResolvedTypes;
final int flags;
final int hashCode;
final int userId;
核心路径: frameworks/base/services/core/java/com/android/server/am/PendingIntentController.java
/**
* 该类主要的职责就是协助 ActivityManagerService 管理所有的 PendingIntent
*/
public class PendingIntentController {
/** 保存所有可用的IntentSenderRecord 对象. */
final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
= new HashMap<>();
......
public PendingIntentRecord getIntentSender(int type, String packageName,
@Nullable String featureId, int callingUid, int userId, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions) {
synchronized (mLock) {
if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid);
if (intents != null) {
for (int i = 0; i < intents.length; i++) {
intents[i].setDefusable(true);
}
}
Bundle.setDefusable(bOptions, true);
//根据PendingIntent中设置的flag,从而决定该PendingIntent对象是取消或更新等操作
final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0;
final boolean cancelCurrent = (flags & PendingIntent.FLAG_CANCEL_CURRENT) != 0;
final boolean updateCurrent = (flags & PendingIntent.FLAG_UPDATE_CURRENT) != 0;
flags &= ~(PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_UPDATE_CURRENT);
//把PendingIntent的信息传入PendingIntentRecord内部类Key对象中
PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, featureId,
token, resultWho, requestCode, intents, resolvedTypes, flags,
SafeActivityOptions.fromBundle(bOptions), userId);
WeakReference<PendingIntentRecord> ref;
ref = mIntentSenderRecords.get(key);
PendingIntentRecord rec = ref != null ? ref.get() : null;
//遍历 列表,如果该 PendingIntentRecord 已经存在,则需要根据 flags 来进一步处理
if (rec != null) {
if (!cancelCurrent) {
// 没有设置 PendingIntent.FLAG_CANCEL_CURRENT,即 PendingIntentRecord 不取消
if (updateCurrent) {
//设置了PendingIntent.FLAG_UPDATE_CURRENT ,则更新 PendingIntentRecord
if (rec.key.requestIntent != null) {
rec.key.requestIntent.replaceExtras(intents != null ?
intents[intents.length - 1] : null);
}
if (intents != null) {
intents[intents.length - 1] = rec.key.requestIntent;
rec.key.allIntents = intents;
rec.key.allResolvedTypes = resolvedTypes;
} else {
rec.key.allIntents = null;
rec.key.allResolvedTypes = null;
}
}
// 更新完毕,返回 PendingIntentRecord
return rec;
}
// 设置 PendingIntent.FLAG_CANCEL_CURRENT,即 PendingIntent 取消
makeIntentSenderCanceled(rec);
mIntentSenderRecords.remove(key);
decrementUidStatLocked(rec);
}
if (noCreate) {
return rec;
}
//如果列表中没有找到匹配的PendingIntentRecord,则创建新的PendingIntentRecord
rec = new PendingIntentRecord(this, key, callingUid);
//把新的PendingIntentRecord,存入列表
mIntentSenderRecords.put(key, rec.ref);
incrementUidStatLocked(rec);
// 返回新的PendingIntentRecord
return rec;
}
}
//取消 PendingIntent
private void makeIntentSenderCanceled(PendingIntentRecord rec) {
rec.canceled = true; //设置 取消 标志,这样下次遍历列表时,直接跳出if判断,如上
final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
if (callbacks != null) {
final Message m = PooledLambda.obtainMessage(
PendingIntentController::handlePendingIntentCancelled, this, callbacks);
mH.sendMessage(m);
}
final AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class);
ami.remove(new PendingIntent(rec));
}
? ? ? 到此,? 不管是新创建的,还是更新的PendingIntentRecord ,这样原路返回给??ActivityManagerService.java, 最后到 PendingIntent.java,即前面 new PendingIntent(target) 中需要的 IIntentSender 对象, 这样就成功创建了PendingIndent.过程如下:
? ? ? ?在通知的场景中,第三方应用通过监听到新通知,获取到通知携带的PendingIntent 对象,然后执行PendingIntent.send()方法,即可实现PendingIntent中intent指定的动作.send() 经过一系列的调用,最终调用 sendAndReturnResult() 方法,源码分析如下:
public int sendAndReturnResult(Context context, int code, @Nullable Intent intent,
@Nullable OnFinished onFinished, @Nullable Handler handler,
@Nullable String requiredPermission, @Nullable Bundle options)
throws CanceledException {
try {
String resolvedType = intent != null ?
intent.resolveTypeIfNeeded(context.getContentResolver())
: null;
if (context != null && isActivity()) {
ActivityOptions activityOptions = options != null ? new ActivityOptions(options)
: ActivityOptions.makeBasic();
activityOptions.setCallerDisplayId(context.getDisplayId());
options = activityOptions.toBundle();
}
//通过ActivityManagerService的sendIntentSender()获取IIntentSender,其中mTarget是PendingIntentRecord
return ActivityManager.getService().sendIntentSender(
mTarget, mWhitelistToken, code, intent, resolvedType,
onFinished != null
? new FinishedDispatcher(this, onFinished, handler)
: null,
requiredPermission, options);
} catch (RemoteException e) {
throw new CanceledException(e);
}
}
public int sendIntentSender(IIntentSender target, IBinder allowlistToken, int code,
Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
if (target instanceof PendingIntentRecord) {
//继续调用PendingIntentRecord.sendWithResult()
return ((PendingIntentRecord)target).sendWithResult(code, intent, resolvedType,
allowlistToken, finishedReceiver, requiredPermission, options);
} else {
if (intent == null) {
Slog.wtf(TAG, "Can't use null intent with direct IIntentSender call");
intent = new Intent(Intent.ACTION_MAIN);
}
try {
target.send(code, intent, resolvedType, allowlistToken, null,
requiredPermission, options);
} catch (RemoteException e) {
}
if (finishedReceiver != null) {
try {
finishedReceiver.performReceive(intent, 0,
null, null, false, false, UserHandle.getCallingUserId());
} catch (RemoteException e) {
}
}
return 0;
}
}
sendWithResult()最终调用 sendInner() 方法,源码如下:
public int sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken,
IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo,
String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) {
if (intent != null) intent.setDefusable(true);
if (options != null) options.setDefusable(true);
TempAllowListDuration duration = null;
Intent finalIntent = null;
Intent[] allIntents = null;
String[] allResolvedTypes = null;
SafeActivityOptions mergedOptions = null;
synchronized (controller.mLock) {
if (canceled) {
return ActivityManager.START_CANCELED;
}
sent = true;
//检查PendingIntent标签,如果设置了FLAG_ONE_SHOT,表示清除该PendingIntent对象,
//即把 IIntentSender 对象清除,接着再从列表中清除
if ((key.flags & PendingIntent.FLAG_ONE_SHOT) != 0) {
controller.cancelIntentSender(this, true);
}
//获取最后一个Intent,对于只设置一个intent的场景也适用
finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent();
final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
if (!immutable) {
if (intent != null) {
int changes = finalIntent.fillIn(intent, key.flags);
if ((changes & Intent.FILL_IN_DATA) == 0) {
resolvedType = key.requestResolvedType;
}
} else {
resolvedType = key.requestResolvedType;
}
flagsMask &= ~Intent.IMMUTABLE_FLAGS;
flagsValues &= flagsMask;
finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
} else {
resolvedType = key.requestResolvedType;
}
final ActivityOptions opts = ActivityOptions.fromBundle(options);
if (opts != null) {
finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
}
mergedOptions = key.options;
if (mergedOptions == null) {
mergedOptions = new SafeActivityOptions(opts);
} else {
mergedOptions.setCallerOptions(opts);
}
if (mAllowlistDuration != null) {
duration = mAllowlistDuration.get(allowlistToken);
}
if (key.type == ActivityManager.INTENT_SENDER_ACTIVITY
&& key.allIntents != null && key.allIntents.length > 1) {
allIntents = new Intent[key.allIntents.length];
allResolvedTypes = new String[key.allIntents.length];
System.arraycopy(key.allIntents, 0, allIntents, 0, key.allIntents.length);
if (key.allResolvedTypes != null) {
System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
key.allResolvedTypes.length);
}
allIntents[allIntents.length - 1] = finalIntent;
allResolvedTypes[allResolvedTypes.length - 1] = resolvedType;
}
}
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
int res = START_SUCCESS;
try {
if (duration != null) {
StringBuilder tag = new StringBuilder(64);
tag.append("setPendingIntentAllowlistDuration,reason:");
tag.append(duration.reason == null ? "" : duration.reason);
tag.append(",pendingintent:");
UserHandle.formatUid(tag, callingUid);
tag.append(":");
if (finalIntent.getAction() != null) {
tag.append(finalIntent.getAction());
} else if (finalIntent.getComponent() != null) {
finalIntent.getComponent().appendShortString(tag);
} else if (finalIntent.getData() != null) {
tag.append(finalIntent.getData().toSafeString());
}
controller.mAmInternal.tempAllowlistForPendingIntent(callingPid, callingUid,
uid, duration.duration, duration.type, duration.reasonCode, tag.toString());
} else if (key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE
&& options != null) {
BroadcastOptions brOptions = new BroadcastOptions(options);
if (brOptions.getTemporaryAppAllowlistDuration() > 0) {
controller.mAmInternal.tempAllowlistForPendingIntent(callingPid, callingUid,
uid, brOptions.getTemporaryAppAllowlistDuration(),
brOptions.getTemporaryAppAllowlistType(),
brOptions.getTemporaryAppAllowlistReasonCode(),
brOptions.getTemporaryAppAllowlistReason());
}
}
boolean sendFinish = finishedReceiver != null;
int userId = key.userId;
if (userId == UserHandle.USER_CURRENT) {
userId = controller.mUserController.getCurrentOrTargetUserId();
}
//暂时允许接收者和服务从后台打开活动
final boolean allowTrampoline = uid != callingUid
&& controller.mAtmInternal.isUidForeground(callingUid);
//根据不同类型的PendingIntent,执行不相应的操作
switch (key.type) {
case ActivityManager.INTENT_SENDER_ACTIVITY:
try {
if (key.allIntents != null && key.allIntents.length > 1) {
//启动通过ActivityManagerService 启动Activity,
res = controller.mAtmInternal.startActivitiesInPackage(
uid, callingPid, callingUid, key.packageName, key.featureId,
allIntents, allResolvedTypes, resultTo, mergedOptions, userId,
false /* validateIncomingUser */,
this /* originatingPendingIntent */,
mAllowBgActivityStartsForActivitySender.contains(
allowlistToken));
} else {
res = controller.mAtmInternal.startActivityInPackage(uid, callingPid,
callingUid, key.packageName, key.featureId, finalIntent,
resolvedType, resultTo, resultWho, requestCode, 0,
mergedOptions, userId, null, "PendingIntentRecord",
false /* validateIncomingUser */,
this /* originatingPendingIntent */,
mAllowBgActivityStartsForActivitySender.contains(
allowlistToken));
}
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startActivity intent", e);
}
break;
case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
controller.mAtmInternal.sendActivityResult(-1, key.activity, key.who,
key.requestCode, code, finalIntent);
break;
case ActivityManager.INTENT_SENDER_BROADCAST:
try {
final boolean allowedByToken =
mAllowBgActivityStartsForBroadcastSender.contains(allowlistToken);
final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null;
//启动通过ActivityManagerService 发送广播,
int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
key.featureId, uid, callingUid, callingPid, finalIntent,
resolvedType, finishedReceiver, code, null, null,
requiredPermission, options, (finishedReceiver != null), false,
userId, allowedByToken || allowTrampoline, bgStartsToken);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
sendFinish = false;
}
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startActivity intent", e);
}
break;
case ActivityManager.INTENT_SENDER_SERVICE:
case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
try {
final boolean allowedByToken =
mAllowBgActivityStartsForServiceSender.contains(allowlistToken);
final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null;
//启动通过ActivityManagerService 启动Service
controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
key.packageName, key.featureId, userId,
allowedByToken || allowTrampoline, bgStartsToken);
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startService intent", e);
} catch (TransactionTooLargeException e) {
res = ActivityManager.START_CANCELED;
}
break;
}
if (sendFinish && res != ActivityManager.START_CANCELED) {
try {
finishedReceiver.performReceive(new Intent(finalIntent), 0,
null, null, false, false, key.userId);
} catch (RemoteException e) {
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
PendingIntent 最终还是通过 ActivityManagerService 来启动相应的组件.到此, Activity类型的 PendingIntent 就分析完毕了.