当前位置: 首页 > news >正文

PendingIntent相关流程解析

流程分析

get流程

pendingIntent主要是对Intent的封装

​
// 创建一个Intent对象
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("key", "value");// 创建一个PendingIntent对象,用于在点击通知时触发Intent
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);// 通过pendinIntent封装一个广播
Intent intent = new Intent("action");
intent.putExtra("x", i);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);​

以getBroadcast流程为例:

重点内容包含如下:

1.AMS中对于PendingIntent的处理是交给PendingIntentController的

2.PendingIntent在AMS侧对应的是PendingIntentRecord对象

3.PendingIntentController中存了一个比较重要的数据结构mIntentSenderRecords,他是一个hashMap

key就是PendIntentRecord.Key

value是PendIntentRecord.ref,对应的就是PendIntentRecord的弱引用

PendIntentRecord.Key的创建,

PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, featureId,token, resultWho, requestCode, intents, resolvedTypes, flags,new SafeActivityOptions(opts), callingUid, userId);

PendIntentRecord的创建是根据key进行创建的

rec = new PendingIntentRecord(this, key, callingUid);

4.AMS侧返回给到应用侧的其实就是这个PendIntentRecord的binder,它实现了IIntentSender对象

 public static PendingIntent getBroadcastAsUser(Context context, int requestCode,Intent intent, int flags, UserHandle userHandle) {String packageName = context.getPackageName();String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());checkPendingIntent(flags, intent, context, /* isActivityResultType */ false);try {intent.prepareToLeaveProcess(context);IIntentSender target =ActivityManager.getService().getIntentSenderWithFeature(INTENT_SENDER_BROADCAST, packageName,context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },resolvedType != null ? new String[] { resolvedType } : null,flags, null, userHandle.getIdentifier());return target != null ? new PendingIntent(target) : null;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

最后再把IIntentSender封装成了PendingIntent对象

send流程

比如我们创建了一个通知,并在通知里面闯入了PendingIntent,当我们点击通知的时候,就会触发PendingIntent的send流程,可能是发送一个广播,或者拉起一个activity之类的

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()) {// Set the context display id as preferred for this activity launches, so that it// can land on caller's display. Or just brought the task to front at the display// where it was on since it has higher preference.ActivityOptions activityOptions = options != null ? new ActivityOptions(options): ActivityOptions.makeBasic();activityOptions.setCallerDisplayId(context.getDisplayId());options = activityOptions.toBundle();}final IApplicationThread app = ActivityThread.currentActivityThread().getApplicationThread();return ActivityManager.getService().sendIntentSender(app,mTarget, mWhitelistToken, code, intent, resolvedType,onFinished != null? new FinishedDispatcher(this, onFinished, handler): null,requiredPermission, options);} catch (RemoteException e) {throw new CanceledException(e);}}

应用侧实际发送的是PendingInten中的mTarget对象给到AMS

AMS侧的处理:

调用mTarget的send方法,相当于调用了PendingIntentRecord的send方法,并走到sendInner方法

sendInner

1.如果PendingIntentRecord已经被cancel的话,返回-96,抛出CanceledException

2.处理PendingIntent.FLAG_ONE_SHOT,如果是这个标签,此处就可以先cancel了

3.处理PendingIntent.FLAG_IMMUTABL这个flag

4.根据key.type,决定最后的处理逻辑,是启动activity,还是发广播还是启动service

switch (key.type) {case ActivityManager.INTENT_SENDER_ACTIVITY:try {// Note when someone has a pending intent, even from different// users, then there's no need to ensure the calling user matches// the target user, so validateIncomingUser is always false below.if (key.allIntents != null && key.allIntents.length > 1) {res = controller.mAtmInternal.startActivitiesInPackage(uid, callingPid, callingUid, key.packageName, key.featureId,allIntents, allResolvedTypes, resultTo, mergedOptions, userId,false /* validateIncomingUser */,this /* originatingPendingIntent */,getBackgroundStartPrivilegesForActivitySender(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 */,getBackgroundStartPrivilegesForActivitySender(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 BackgroundStartPrivileges backgroundStartPrivileges =getBackgroundStartPrivilegesForActivitySender(mAllowBgActivityStartsForBroadcastSender, allowlistToken,options, callingUid);// If a completion callback has been requested, require// that the broadcast be delivered synchronouslyint sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,key.featureId, uid, callingUid, callingPid, finalIntent,resolvedType, finishedReceiverThread, finishedReceiver, code, null,null, requiredPermission, options, (finishedReceiver != null),false, userId, backgroundStartPrivileges,null /* broadcastAllowList */);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 BackgroundStartPrivileges backgroundStartPrivileges =getBackgroundStartPrivilegesForActivitySender(mAllowBgActivityStartsForServiceSender, allowlistToken,options, callingUid);// MIUI ADD:Security_ProcessAutoStartif (!PendingIntentRecordStub.get().checkRunningCompatibility(finalIntent, resolvedType, callingUid, callingPid, userId)) {return ActivityManager.START_CANCELED;}// END Security_ProcessAutoStartcontroller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,key.packageName, key.featureId, userId,backgroundStartPrivileges);} 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;

cancel流程

因为cancle了需要把pendingIntentRecord从缓存mIntentSenderRecords移除

另外需要把PendingIntent.cancle标志位设置为false

例如我在A进程创建的PendingIntent,通过Notification发送到了通知上,此时我A进程调用了PendingIntent中的cancel方法,但是通知里面的pendingIntent并不知道自己已经被cancel了,当通知点击的时候,消息发送到了AMS进程,AMS进程就会知道,这个PendingIntent是已经cancel过的了,就可以抛出CanceledException来提醒使用方;

http://www.lryc.cn/news/607237.html

相关文章:

  • 我的博客系统测试报告
  • PHP转Java笔记
  • 前端图片懒加载的深度指南:从理论到实战
  • 浏览器环境segmentit实现中文分词
  • windows内核研究(软件调试-调试事件采集)
  • 性能测试-性能测试中的经典面试题一
  • Nginx跨域问题与 MIME 类型错误深度排错指南:解决 MIME type of “application/octet-stream“ 报错
  • CAN通信协议
  • 从零到英雄:掌握神经网络的完整指南
  • 大模型开发框架LangChain之构建知识库
  • YOLOv8/YOLOv11 C++ OpenCV DNN推理
  • 深入浅出理解WaitForSingleObject:Windows同步编程核心函数详解
  • 大模型幻觉的本质:深度=逻辑层次,宽度=组合限制,深度为n的神经网络最多只能处理n层逻辑推理,宽度为w的网络无法区分超过w+1个复杂对象的组合
  • 前沿智能推荐算法:基于多模态图神经网络的隐私保护推荐系统
  • JS字符串匹配,检测字符中是否包含ABC,includes,indexOf
  • 网络配置+初始服务器配置
  • C++ AI 实用案例强化学习
  • UE5多人MOBA+GAS 番外篇:同时造成多种类型伤害,以各种属性值的百分比来应用伤害(版本二)
  • MySQL常见的聚合函数:
  • 逻辑回归----银行贷款模型优化
  • 【C++/STL】vector基本介绍
  • git pull和git fetch的区别
  • Linux---编辑器vim
  • vi/vim跳转到指定行命令
  • 达梦数据库权限体系详解:系统权限与对象权限
  • Js引用数据类型和ES6新特性
  • X2Doris是SelectDB可视化数据迁移工具,安装与部署使用手册,轻松进行大数据迁移
  • 向量投影计算,举例说明
  • rhcsa笔记大全
  • 华锐矩阵世界平台与海外客户洽谈合作