结论: PendingIntent 是延迟触发的一种 Intent , 通过上图的过程看,PendingIntent 的执行,是一种跨进程通信.首先创建PendingIntent对象时,就把该对象定义到 ActivityManagerService, 到执行 PengdingIntent 动作时, 也是在 ActivityManagerService 找到 目标PengdingIntent, 从而执行相应操作.
1. PendingIntent 在 Android 通知中的使用场景
使用场景: 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());
2. PendingIntent 的使用
(1) PendingIntent 的获取
核心源码路径 : frameworks/base/core/java/android/app/PendingIntent.java1. 跳转到 Activity ,指定一个 Activitypublic 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)
(2) 参数说明:
- requestCode : 发送方设定的请求码.
- intent : 要启动的意图.(注意: 需要使用显示 Intent , 即明确将要启动的组件名).
- flags : 主要是方便后续管理所有的PendingIntent对象,可选的标签如下:
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 可变.
3. PendingIntent 的源码分析
以上图通知的代码为例子,说明创建 PendingIntent 对象的过程.
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_MUTABLE);
(1) 调用 PendingIntent 中的 getActivity() , 源码如下 :
核心源码路径 : frameworks/base/core/java/android/app/PendingIntent.javapublic 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 nullfinal 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()); //获取 IntentSenderreturn target != null ? new PendingIntent(target) : null; //创建 PendingIntent 对象,} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
上面最终会调用到 getActivityAsUser( ) , 其中 创建 PendingIntent 对象的时候,需要传入 IIntentSender target 的对象, 而该对象是从 ActivityManagerService.getIntentSenderWithFeature( ) 获取,其中的第一个参数,这里传递的是 INTENT_SENDER_ACTIVITY , 代码获取启动 activity 的PendingIntent , 其他的类型如下:
- ActivityManager. INTENT_SENDER_ACTIVITY
- ActivityManager. INTENT_SENDER_ACTIVITY_RESULT
- ActivityManager. INTENT_SENDER_SERVICE
- ActivityManager. INTENT_SENDER_FORGROUND_SERVICE
- ActivityManager. INTENT_SENDER_BROADCAST
(2) ActivityManagerService.getIntentSenderWithFeature( )的源码如下:
核心源码路径 : frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javapublic 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) { //必须指定至少一个intentthrow 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()来获取IIntentSenderreturn 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 .
(3) PendingIntentRecord 对象源码分析
核心代码路径 : frameworks/base/services/core/java/com/android/server/am/PendingIntentRecord.javapublic 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,一般情况下都是指定一个intentfinal String requestResolvedType;final SafeActivityOptions options;Intent[] allIntents; //获取所有的intent,如果设定了多个intentString[] allResolvedTypes;final int flags;final int hashCode;final int userId;
(4) PendingIntentController 类简介, 以及 getIntentSender() 方法来获取 IIntentSender 对象
核心路径: 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;}}// 更新完毕,返回 PendingIntentRecordreturn rec;}// 设置 PendingIntent.FLAG_CANCEL_CURRENT,即 PendingIntent 取消makeIntentSenderCanceled(rec);mIntentSenderRecords.remove(key);decrementUidStatLocked(rec);}if (noCreate) {return rec;}//如果列表中没有找到匹配的PendingIntentRecord,则创建新的PendingIntentRecordrec = new PendingIntentRecord(this, key, callingUid);//把新的PendingIntentRecord,存入列表mIntentSenderRecords.put(key, rec.ref);incrementUidStatLocked(rec);// 返回新的PendingIntentRecordreturn 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.过程如下:
3. PendingIntent.send() 源码分析
在通知的场景中,第三方应用通过监听到新通知,获取到通知携带的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是PendingIntentRecordreturn 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);}}
(1) ActivityManagerService.sendIntentSender() 源码分析
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;}}
(2) PendingIntentRecord.sendWithResult() 源码分析
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 启动Servicecontroller.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 就分析完毕了.