当前位置: 首页 > 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.dtcms.com/a/309557.html

相关文章:

  • MySQL——事务详解
  • React Refs:直接操作DOM的终极指南
  • RAGFlow Agent 知识检索节点源码解析:从粗排到精排的完整流程
  • Java学习第九十六部分——Eureka
  • Elasticsearch IK 中文分词器指南:从安装、配置到自定义词典
  • IPAM如何帮助企业解决IP冲突、识别未经授权设备并管理子网混乱
  • MAC 升级 Ruby 到 3.2.0 或更高版本
  • ARM Cortex-M 处理器的应用
  • Smart Launcher:安卓设备上的智能启动器
  • ElasticSearch Linux 下安装及 Head 插件 | 详情
  • 设计Mock CUDA库的流程与实现
  • 【秋招笔试】07.27文远知行-第一题
  • Git 实现原理剖析
  • Boost.Asio学习(5):c++的协程
  • Python Flask框架Web应用开发完全教程
  • 后台管理系统权限管理:前端实现详解
  • 关于WIKI的一些使用技巧
  • windows系统安装文生图大模型Stable diffusion V3.5 large(完整详细可用教程)
  • 20250801在Ubuntu24.04.2LTS下编译firefly_itx_3588j的Android12时解决boot.img过大的问题
  • 李宏毅深度学习教程 第4-5章 CNN卷积神经网络+RNN循环神经网络
  • 基于SpringBoot+MyBatis+MySQL+VUE实现的经方药食两用服务平台管理系统(附源码+数据库+毕业论文+部署教程+配套软件)
  • 【科普】进程与线程的区别
  • 电商前端Nginx访问日志收集分析实战
  • 机器学习【三】SVM
  • 无人机避让路径规划模块运行方式
  • uniapp无线(WIFI)运行调试APP(真机)
  • C++继承中虚函数调用时机问题及解决方案
  • 无人机模式的切换
  • 服务端之nestJS常用异常类及封装自定义响应模块
  • 无人机上的 “气象侦察兵”:无人机用气象仪