ActivityManagerService广播并行发送与串行发送怎么实现(activitymanagerservice,开发技术)

时间:2024-05-08 21:37:23 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    ActivityManagerService%E5%B9%BF%E6%92%AD%E5%B9%B6%E8%A1%8C%E5%8F%91%E9%80%81%E4%B8%8E%E4%B8%B2%E8%A1%8C%E5%8F%91%E9%80%81%E6%80%8E%E4%B9%88%E5%AE%9E%E7%8E%B0

本文以 ActivityManagerService之广播(1): 注册与发送 为基础,分析“串行”和“并行”广播的发送流程,并介绍广播 ANR 的原理。

第3步,把广播记录保存到并行队列中

第4步,调度发送广播,最终会调用如下方法

虽然名为“并行”广播,但是仍然是从队列取出广播,然后逐个发送给动态接收器。很显然,这里的行为与“并行”的含义并不一致?那么广播的“并行”发送究竟是什么意思?

接着看“并行”广播如何发送给动态接收器的

抛开一些细节,直接看 performReceiveLocked()

很简单,就是通过进程 attach 的 IApplicationThread 接口,发送广播给进程。这个过程,暂时先不分析,后面会分析到。

那么,现在来回答一下,何为“并行”广播?其实这个答案,我也是对比了串行广播的发送过程,才得出来的。所谓的"并行"发送,实际上就是把广播逐个发送给动态接收器,但是不需要等待前一个接收器反馈处理结果,就可以发送下一个。而“串行”广播的发送,是需要等待前一个广播接收器反馈处理结果后,才能调度发送下一个广播。

第3步,广播加入到串行队列中

并行发送的广播保存到 BroadcastQueue#mParallelBroadcasts 中,而串行发送的广播保存到 BroadcastDispatcher#mOrderedBroadcasts 中,为何要这样设计呢?有兴趣的读者可以研究下。

第4步,“串行”广播的调度发送,仍然使用的是 processNextBroadcastLocked() 方法,但是代码量是非常的大,下面将把函数分段解析。

processNextBroadcastLocked() 函数有400多行代码,这个函数里有很多东西都可以抽出来的,但是随着版本的更新,这块代码一直没有优化过。

当发送一个广播给 receiver 时,如果 receiver 进程没有启动,那么会先 fork 一个 receiver 进程,然后用 mPendingBroadcast 保存待发送的广播。当 receiver 进程起来的时候,会与 AMS 执行 attach application 过程,在这个过程中,会自动把 mPendingBroadcast 保存的广播发送给 receiver 进程。

因此,这里检测到 mPendingBroadcast 不为 null 时,那么 receiver 进程肯定在启动中,只要 receiver 进程没有死亡,就什么也不用做,因为广播会自动发送给 receiver 进程。

接着看下一步的处理

先从整体看,通过一个 do-while 循环,最终是为了找到下一个处理的广播。为何要用一个循环来寻找呢? 因为广播可能没有接收器,或者已经严重超时,又或者广播需要推迟发送。所以要通过一个循环,找到一个能立即发送的广播。

由于本文主要是为了分析广播发送的整体流程,对于有些细节,只做注释而不做细致分析。需要深入研究的读者,可以在本文的基础上继续分析。

继续接着看下一步

在广播发送给一个 receiver 之前,会先发送一个超时消息。从广播准备发送给一个 receiver 算起,到 receiver 处理完广播,并反馈给 AMS,如果这个时间段超过了一个时间阈值,就会引发 ANR。触发 ANR 的代码设计非常巧妙,后面会具体分析这个过程。

接着看下一步

现在一切就绪,那么开始获取一个 receiver,当这个 receiver 是一个动态接收器时,直接发送广播给它,这个发送过程前面已经分析过。

注意,这里处理的情况是,把有序广播发送给动态接收器。并且发送完成后,直接 return, 也就是结束了此次广播的发送流程。

一个广播可能有多个接收器,为何这里只发送给一个动态接收器,就直接返回了? 这就是从“串行”广播的本质,需要等待当前的广播接收器处理完广播,并返回结果后,才能把广播发送给下一个广播接收器。

接着看下一步

如果这个 reciever 是静态接收器,那么在把广播发送给它之前,首先得进行一大堆的检测。最常见的就是权限,但是这里展示了一段 Android O+ 限制广播发送给静态接收器的限制,有兴趣的读者可以详细分析。

接着看下一步

如果没有限制,那么现在就可以把广播发送给静态接收器。

如果静态接收器所在的进程已经运行了,那么把广播发送给这个进程,这个过程与前面发送广播给动态接收器的过程非常类似,这里就不分析了。

注意,这里把广播发送给一个静态接收器,也是直接 return,懂了吧?

接着往下看

刚才已经处理了静态接收器的进程存在的情况,那么现在处理进程不存在的情况,因此首先得 fork 进程。当成功 fork 进程后,保存待发送的广播的数据,例如,用 mPendingBroadcast 保存广播,然后当进程启动时,与 AMS 进行 attach application 时,会自动把广播发送给该进程。这个过程后面会分析。

注意,此时函数已经结束,而广播正在发送给一个正在启动的进程。很显然,需要等待这个广播的处理结果,才能继续下一个广播的发送,这也符合“串行”广播的定义。

刚才,我们分析到一个过程,当静态接收器所在的进程没有启动的时候,首先 fork 进程,那么广播之后是如何发送给进程的呢?

首先,我们知道当进程启动后,会执行 attach application 过程,最终会调用 AMS 如下方法

看到了,AMS 首先对进程进行了初始化,然后就会把等待进程启动的广播,发送给它。

mPendingBroadcast 保存的就是等待进程启动启动后,需要发送的广播。现在进程已经启动,立即发送广播

现在 AMS 通知 receiver 所在的进程来处理广播

最终调用 handleReceiver() 处理广播数据

这里的过程很清晰明了吧,直接看最后一步,把广播的处理结果反馈给 AMS

现在看下 AMS 如何处理这个反馈的结果

看到了,只有当前 receiver 处理完广播,才会发送广播给下一个 receiver,这就是“串行”广播的本质。

最后,来探讨一个广播 ANR 的原理,本来我以为很简单的,就是发送一个超时消息嘛。但是当我细看的时候,我发现这个 ANR 设计的很巧妙,我觉得我们可以学习下,因此这里单独拿出来分析。

这里,我得提醒大家一点,只有“串行”广播才会发生 ANR,因为它要等待 receiver 的处理结果。

根据前面分析,“串行”广播发送给 receiver 前,会发送一个超时消息,如下

当这个消息被执行的时候,会调用如下代码

第2步,引发 ANR ,很简单,就是因为整个发送与反馈过程超时了。

而第1步,就是处理不超时的情况。这里大家是不是很疑惑,移除超时消息不是在接收到广播反馈后进行的吗? 我可以负责地告诉你,并不是!那这里第1步怎么理解呢?

首先这个超时消息一定触发,但是触发这个超时消息,并不代表一定会引发 ANR。

假如当前 receiver 的广播处理流程,在超时时间之前就完成了,那么 AMS 会调度广播发送给下一个 receiver。

于是,针对下一个 receiver ,会更新 r.receiverTime,那么第一步此时计算出来的 timeoutTime 是下一个 receiver 的广播超时时间,很显然是大于 now 的,于是就不会走第2步的 ANR 流程。

最后利用这个 timeoutTime,为下一个 receiver 再发送一个超时消息,简直是完美!

至于为何不在广播反馈的时候,移除这个超时消息,我心中有一点小小的想法,但是也不能确定是不是这个原因,才这样设计的。不过,对我来说,这一招,我算是学会了。

本文:ActivityManagerService广播并行发送与串行发送怎么实现的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:C# WPF如何实现3D操作几何体效果下一篇:

11 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18