[ Android源码分析 ] Android注册、发送和接收广播流程总结

[ Android源码分析 ] Android注册、发送和接收广播流程总结

尊重原创,转载请注明出处!

引言

这段时间由于解决客户问题,研究了一下 Android 发送广播的流程,写了 4 篇博客,在分析源码的过程中,也对 Android 广播相关的知识有了更深的认识。
本来打算准备开始研究 PackageManagerService 相关的源码,但是强迫症犯了,总觉得虽然对广播注册和发送的流程有了一定的了解,但是没有把整个流程贯穿起来,还没有一些总结性的东西,总觉得有点不得劲儿。
所以,就有了这篇博客。

注册接收器

对于一般的广播,一定是先要注册接收器,这样在广播发出之后系统才能找到要接收此广播的对象。当然,粘性广播例外,这个暂且不提。

Android 注册 BroadcastReceiver 的方式分为静态注册和动态注册。这两种注册流程在之前的博客中已经对系统源码进行过分析,感兴趣的可以看下:

[ Android源码分析 ] 静态注册在源码中是如何实现的

[ Android源码分析 ] 动态注册在源码中是如何实现的

既然源码已经分析过了,这里就不再废话,直接做下简单的总结:

关于静态注册,Android 系统在启动过程中,会扫描 /system/app,/data/app 等目录下的应用,并进行解析;应用安装、升级过程中,同样会对应用进行解析。解析完成后,将接收器 add 到 PKMS 中的 mReceivers 中保存起来。

关于动态注册,应用进程起来之后,手动调用 registerReceiver 方法注册接收器,将接收器 add 到 AMS 中的 mReceiverResolver 中保存起来。

发送广播时,会依次查询 PKMS 中的 mReceivers,AMS 中的 mReceiverResolver,得到广播对应的静态注册和动态注册的接收器,再进行分发的流程。

发送广播

Android 中的广播分为普通广播(sendBroadcast)、有序广播(sendOrderedBroadcast)和粘性广播(sendStickyBroadcast)。

但是无论是哪种广播,最终都是通过封装调用流程走到 AMS 中的 broadcastIntentLocked 方法中,通过 它的 ordered 和 sticky 参数进行区分。参数传递的源码虽然很简单,但是要占用大量篇幅,就不贴代码了,直接给出结论:

广播类型orderedsticky
普通广播falsefalse
有序广播truefalse
粘性广播falsetrue

在之前的 [ Android源码分析 ] Android 广播队列中的 mParallelBroadcasts 和 mOrderedBroadcasts 中,对 broadcastIntentLocked 的源码实现进行了分析,虽然忽略了大量我认为无关的代码,但是和广播相关的逻辑,尽量都保留下来:

broadcastIntentLocked 方法的代码有 600 多行,但是概括起来,主要做了这几件事情:

1、为广播加上 FLAG_EXCLUDE_STOPPED_PACKAGES 的 flag,所以默认情况下,安装完后未启动过的应用、以及强制停止运行的广播是无法接收到广播的。

2、如果发送粘性广播,需要申请 BROADCAST_STICKY 的权限,并且先判断系统中是否存在相同的粘性广播,如果已存在则进行替换,如果不存在则加入到 mStickyBroadcasts 中保存起来,等待后续处理。

3、调用 collectReceiverComponents 获取静态注册了该广播的 Receiver,放到 receivers 队列中

4、调用 mReceiverResolver.queryIntent 获取动态注册了该广播的 Receiver,放到 registeredReceivers队列中

5、先处理无序广播,将动态注册的 registeredReceivers 封装为 BroadcastRecord,加入到mParallelBroadcasts 广播队列,进行并行处理

6、通过 priority 优先级调整静态 Receiver 和动态 Receiver 的顺序,最终都放到 receivers 中,加入到mOrderedBroadcasts广播队列,进行串行处理

PS:如果发送的是无序广播,那么在第 5 点中动态 Receiver 已经被处理完了,第 6 点就不需要处理 registeredReceivers;如果到了第 6 点 registeredReceivers 不为空,说明发送的是有序广播,仍需要对动态 Receiver 进行处理

广播队列分发

广播分发主要在 BroadcastQueue 中实现。enqueueParallelBroadcastLocked 和 enqueueOrderedBroadcastLocked 只是把 BroadcastRecord 分别加入到 mParallelBroadcasts 队列和 mOrderedBroadcasts 队列中,真正的分发处理逻辑还是通过 scheduleBroadcastsLocked 发送 message,在 BroadcastHandler 中调用 processNextBroadcast 方法实现。

processNextBroadcast 的实现在 [ Android源码分析 ] Android 广播队列中的 mParallelBroadcasts 和 mOrderedBroadcasts 中也已经做了比较完整的说明,这里不贴代码了,直接做下总结:

1、先处理并行广播队列(无序广播 + 动态注册的 receiver),遍历所有的 BroadcastRecord 以及 Receiver,调用 deliverToRegisteredReceiverLocked 异步发送广播。
PS:deliverToRegisteredReceiverLocked 通过 performReceiveLocked 调用到 ActivityThread 中的 scheduleRegisteredReceiver,而 IApplicationThread 是被修饰为 oneway 的接口,因此是异步调用

2、再处理串行广播,从 mOrderedBroadcasts 中取出一个 BroadcastRecord,即调用一次 processNextBroadcast 只处理其中的一个 Receiver

4、如果当前 receiver 为动态注册,调用 deliverToRegisteredReceiverLocked 分发给应用进行处理

5、如果当前 receiver 为静态注册,分为两种情况:

5.1、应用已启动:调用 processCurBroadcastLocked 通过 ActivityThread.scheduleReceiver,最终调用到应用的 onReceive 进行处理

5.2、应用未启动:调用 AMS.startProcessLocked 启动应用,将要处理的 BroadcastRecord 保存到 mPendingBroadcast,等待应用启动完成后在 AMS.attachApplicationLocked 中调用 BroadcastQueue.sendPendingBroadcastsLocked,也是一样通过 ActivityThread.scheduleReceiver 进行分发处理。

6、应用在 BroadcastReceiver.onReceive 中处理完广播事件后,BroadcastQueue 再找到下一个接收广播的 Receiver,再次调用 processNextBroadcast 进行处理,直至清空 mOrderedBroadcasts。

接收回调

从前面的分析中,我们已经知道 BroadcastQueue 在分发广播给静态注册 Receiver 处理的时候,最终调用到 ActivityThread 中的 scheduleReceiver。

而分发广播给动态注册 Receiver 处理的时候,最终调用的则是 ActivityThread 中的 scheduleRegisteredReceiver。

scheduleReceiver 是通过 Handler,调用到 handleReceiver 中,反射构造出 BroadcastReceiver 的实例,再调用它的 onReceive 方法接收广播。

ActivityThread ReceiverData ActivityThread.H BroadcastReceiver new ReceiverData scheduleReceiver handleReceiver newInstance onReceive ActivityThread ReceiverData ActivityThread.H BroadcastReceiver

.
scheduleRegisteredReceiver 则是调用 IIntentReceiver.performReceive。这个参数是在 ContextImp 中调用 registerReceiverInternal 注册接收器时构造的,主要用于跨进程传输 BroadcastReceiver。在 LoadApk.ReceiverDispatcher.performReceive 中,通过 Args.getRunnable 回调 BroadcastReceiver.onReceive。

动态广播注册过程中,IIntentReceiver 的传递可以参考下面的时序图:

ContextImpl LoadedApk IIntentReceiver ActivityManagerService registerReceiver getReceiverDispatcher registerReceiver ContextImpl LoadedApk IIntentReceiver ActivityManagerService

.
scheduleRegisteredReceiver 到 BroadcastReceiver.onReceive 的流程可以参考下图:

BroadcastQueue ActivityThread IIntentReceiver LoadedApk.ReceiverDispatcher BroadcastReceiver scheduleRegisteredReceiver performReceive performReceive Arg.Runnable onReceive BroadcastQueue ActivityThread IIntentReceiver LoadedApk.ReceiverDispatcher BroadcastReceiver

PS:实在不会画图,画得很烂,仅供参考。看不懂就算了 ~

思考

广播只是 Android 的一个小的组成成分,但仍花了我不少时间去研究和总结源码,即便如此,依然还有不少细节是没有看透的。但是,还是得继续往前看,广播只是研究 Android 源码的起点,不能只停留在广播的这一小个模块,还是得多看一些更重要的模块。

后续还会继续研究 AMS、PKMS、WMS、Camera 等模块的源码,期待自己对 Android 系统有更深的了解,写出更多更好的文章。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值