广播(Broadcast内部机制讲解)
2014-09-25 16:00
267 查看
http://my.oschina.net/youranhongcha/blog/226274
摘要 我们在编写Android程序时,常常会用到广播(Broadcast)机制。从易用性的角度来说,使用广播是非常简单的。不过,这个不是本文关心的重点,我们希望探索得再深入一点儿。我想,许多人也不想仅仅停留在使用广播的阶段,而是希望了解一些广播机制的内部机理。如果是这样的话,请容我斟一杯红茶,慢慢道来。
Android Broadcast Receiver
目录[-]
1 概述
2 两种receiver
2.1 动态receiver
2.2 静态receiver
3 激发广播
3.1 AMS一侧的broadcastIntentLocked()
3.1.1 为intent添加FLAG_EXCLUDE_STOPPED_PACKAGES标记
3.1.2 处理和package相关的广播
3.1.3 处理其他一些系统广播
3.1.4 判断当前是否有权力发出广播
3.1.5 必要时更新一下系统中的sticky广播列表
3.1.6 尝试向并行receivers递送广播
3.1.7 整理两个receiver列表
3.1.8 尝试逐个向串行receivers递送广播
3.2 最重要的processNextBroadcast()
3.2.1 用deliverToRegisteredReceiverLocked()递送到平行动态receiver
3.2.2 静态receiver的递送
3.2.2.1 processCurBroadcastLocked()
3.2.2.2 必要时启动新进程
3.2.3 说说有序广播是如何循环起来的?
3.2.4 说说有序广播的timeout处理
4 尾声
品茗论道说广播(Broadcast内部机制讲解)
侯 亮
简单地说,Android广播机制的主要工作是为了实现一处发生事情,多处得到通知的效果。这种通知工作常常要牵涉跨进程通讯,所以需要由AMS(Activity Manager Service)集中管理。
![](http://static.oschina.net/uploads/space/2014/0424/201441_jyH9_174429.png)
在Android系统中,接收广播的组件叫作receiver,而且receiver还分为动态和静态的。动态receiver是在运行期通过调用registerReceiver()注册的,而静态receiver则是在AndroidManifest.xml中声明的。动态receiver比较简单,静态的就麻烦一些了,因为在广播递送之时,静态receiver所从属的进程可能还没有启动呢,这就需要先启动新的进程,费时费力。另一方面,有些时候用户希望广播能够按照一定顺序递送,为此,Android又搞出了ordered
broadcast的概念。
细节如此繁杂,非一言可以说清。我们先从receiver这一侧入手吧。
?
注册之时,用户会把一个自定义的receiver对象作为第一个参数传入。当然,用户的receiver都是继承于BroadcastReceiver的。使用过广播机制的程序员,对这个BroadcastReceiver应该都不陌生,这里就不多说了。我们需要关心的是,这个registerReceiverInternal()内部还包含了什么重要的细节。
registerReceiverInternal()代码的截选如下:
?
请大家注意那个rd对象(IIntentReceiver rd)。我们知道,在Android架构中,广播动作最终其实都是由AMS递送出来的。AMS利用binder机制,将语义传递给各个应用进程,应用进程再辗转调用到receiver的onReceive(),完成这次广播。而此处的rd对象正是承担“语义传递工作“的binder实体。
为了管理这个重要的binder实体,Android搞出了一个叫做ReceiveDispatcher的类。该类的定义截选如下:
【frameworks/base/core/java/android/app/LoadedApk.java】
?
这样看来,“动态注册的BroadcastReceiver”和“ReceiverDispatcher节点”具有一一对应的关系。示意图如下:
![](http://static.oschina.net/uploads/space/2014/0424/210455_ny00_174429.png)
一个应用里可能会注册多个动态receiver,所以这种一一对应关系最好整理成表,这个表就位于LoadedApk中。前文mPackageInfo.getReceiverDispatcher()一句中的mPackageInfo就是LoadedApk对象。
在Android的架构里,应用进程里是用LoadedApk来对应一个apk的,进程里加载了多少个apk,就会有多少LoadedApk。每个LoadedApk里会有一张“关于本apk动态注册的所有receiver”的哈希表(mReceivers)。当然,在LoadedApk初创之时,这张表只是个空表。
mReceivers表的定义如下:
?
该表的key项是我们比较熟悉的Context,也就是说可以是Activity、Service或Application。而value项则是另一张“子哈希表”。这是个“表中表”的形式。言下之意就是,每个Context(比如一个activity),是可以注册多个receiver的,这个很好理解。mReceivers里的“子哈希表”的key值为BroadcastReceiver,value项为ReceiverDispatcher,示意图如下:
![](http://static.oschina.net/uploads/space/2014/0424/210601_MymB_174429.png)
图:客户进程中的mReceivers表
接下来我们继续看registerReceiverInternal(),它最终调用到
?
registerReceiver()函数的filter参数指明了用户对哪些intent感兴趣。对同一个BroadcastReceiver对象来说,可以注册多个感兴趣的filter,就好像声明静态receiver时,也可以为一个receiver编写多个<intent-filter>一样。这些IntentFilter信息会汇总到AMS的mRegisteredReceivers表中。在AMS端,我们可以这样访问相应的汇总表:
?
其中的receiver参数为IIntentReceiver型,正对应着ReceiverDispatcher中那个binder实体。也就是说,每个客户端的ReceiverDispatcher,会对应AMS端的一个ReceiverList。
ReceiverList的定义截选如下:
?
ReceiverList继承于ArrayList<BroadcastFilter>,而BroadcastFilter又继承于IntentFilter,所以ReceiverList可以被理解为一个IntentFilter数组列表。
?
现在,我们可以绘制一张完整一点儿的图:
![](http://static.oschina.net/uploads/space/2014/0424/210642_v7QA_174429.png)
这张图只画了一个用户进程,在实际的系统里当然会有很多用户进程了,不过其关系是大致统一的,所以我们不再重复绘制。关于动态receiver的注册,我们就先说这么多。至于激发广播时,又会做什么动作,我们会在后文阐述,现在我们先接着说明和动态receiver相对的静态receiver。
在PKMS内部,会有一个针对receiver而设置的Resolver(决策器),其示意图如下:
![](http://static.oschina.net/uploads/space/2014/0424/210720_Tdr7_174429.png)
关于PKMS的查询动作的细节,可参考PKMS的相关文档。目前我们只需知道,PKMS向外界提供了queryIntentReceivers()函数,该函数可以返回一个List<ResolveInfo>列表。
我们举个实际的例子:
?
这是AMS的systemReady()函数里的一段代码,意思是查找有多少receiver对ACTION_PRE_BOOT_COMPLETED感兴趣。
ResolveInfo的定义截选如下:
?
总之,当系统希望发出一个广播时,PKMS必须能够决策出,有多少静态receiver对这个广播感兴趣,而且这些receiver的信息分别又是什么。
关于receiver的注册动作,我们就先说这么多。下面我们来看看激发广播时的动作。
摘要 我们在编写Android程序时,常常会用到广播(Broadcast)机制。从易用性的角度来说,使用广播是非常简单的。不过,这个不是本文关心的重点,我们希望探索得再深入一点儿。我想,许多人也不想仅仅停留在使用广播的阶段,而是希望了解一些广播机制的内部机理。如果是这样的话,请容我斟一杯红茶,慢慢道来。
Android Broadcast Receiver
目录[-]
1 概述
2 两种receiver
2.1 动态receiver
2.2 静态receiver
3 激发广播
3.1 AMS一侧的broadcastIntentLocked()
3.1.1 为intent添加FLAG_EXCLUDE_STOPPED_PACKAGES标记
3.1.2 处理和package相关的广播
3.1.3 处理其他一些系统广播
3.1.4 判断当前是否有权力发出广播
3.1.5 必要时更新一下系统中的sticky广播列表
3.1.6 尝试向并行receivers递送广播
3.1.7 整理两个receiver列表
3.1.8 尝试逐个向串行receivers递送广播
3.2 最重要的processNextBroadcast()
3.2.1 用deliverToRegisteredReceiverLocked()递送到平行动态receiver
3.2.2 静态receiver的递送
3.2.2.1 processCurBroadcastLocked()
3.2.2.2 必要时启动新进程
3.2.3 说说有序广播是如何循环起来的?
3.2.4 说说有序广播的timeout处理
4 尾声
品茗论道说广播(Broadcast内部机制讲解)
侯 亮
1 概述
我们在编写Android程序时,常常会用到广播(Broadcast)机制。从易用性的角度来说,使用广播是非常简单的。不过,这个不是本文关心的重点,我们希望探索得再深入一点儿。我想,许多人也不想仅仅停留在使用广播的阶段,而是希望了解一些广播机制的内部机理。如果是这样的话,请容我斟一杯红茶,慢慢道来。简单地说,Android广播机制的主要工作是为了实现一处发生事情,多处得到通知的效果。这种通知工作常常要牵涉跨进程通讯,所以需要由AMS(Activity Manager Service)集中管理。
![](http://static.oschina.net/uploads/space/2014/0424/201441_jyH9_174429.png)
在Android系统中,接收广播的组件叫作receiver,而且receiver还分为动态和静态的。动态receiver是在运行期通过调用registerReceiver()注册的,而静态receiver则是在AndroidManifest.xml中声明的。动态receiver比较简单,静态的就麻烦一些了,因为在广播递送之时,静态receiver所从属的进程可能还没有启动呢,这就需要先启动新的进程,费时费力。另一方面,有些时候用户希望广播能够按照一定顺序递送,为此,Android又搞出了ordered
broadcast的概念。
细节如此繁杂,非一言可以说清。我们先从receiver这一侧入手吧。
2 两种receiver
Android中的receiver,分为“动态receiver”和“静态receiver”。2.1 动态receiver
动态receiver必须在运行期动态注册,其实际的注册动作由ContextImpl对象完成:?
registerReceiverInternal()代码的截选如下:
?
为了管理这个重要的binder实体,Android搞出了一个叫做ReceiveDispatcher的类。该类的定义截选如下:
【frameworks/base/core/java/android/app/LoadedApk.java】
?
![](http://static.oschina.net/uploads/space/2014/0424/210455_ny00_174429.png)
一个应用里可能会注册多个动态receiver,所以这种一一对应关系最好整理成表,这个表就位于LoadedApk中。前文mPackageInfo.getReceiverDispatcher()一句中的mPackageInfo就是LoadedApk对象。
在Android的架构里,应用进程里是用LoadedApk来对应一个apk的,进程里加载了多少个apk,就会有多少LoadedApk。每个LoadedApk里会有一张“关于本apk动态注册的所有receiver”的哈希表(mReceivers)。当然,在LoadedApk初创之时,这张表只是个空表。
mReceivers表的定义如下:
?
![](http://static.oschina.net/uploads/space/2014/0424/210601_MymB_174429.png)
图:客户进程中的mReceivers表
接下来我们继续看registerReceiverInternal(),它最终调用到
?
?
ReceiverList的定义截选如下:
?
?
![](http://static.oschina.net/uploads/space/2014/0424/210642_v7QA_174429.png)
这张图只画了一个用户进程,在实际的系统里当然会有很多用户进程了,不过其关系是大致统一的,所以我们不再重复绘制。关于动态receiver的注册,我们就先说这么多。至于激发广播时,又会做什么动作,我们会在后文阐述,现在我们先接着说明和动态receiver相对的静态receiver。
2.2 静态receiver
静态receiver是指那些在AndroidManifest.xml文件中声明的receiver,它们的信息会在系统启动时,由Package Manager Service(PKMS)解析并记录下来。以后,当AMS调用PKMS的接口来查询“和intent匹配的组件”时,PKMS内部就会去查询当初记录下来的数据,并把结果返回AMS。有的同学认为静态receiver是常驻内存的,这种说法并不准确。因为常驻内存的只是静态receiver的描述性信息,并不是receiver实体本身。在PKMS内部,会有一个针对receiver而设置的Resolver(决策器),其示意图如下:
![](http://static.oschina.net/uploads/space/2014/0424/210720_Tdr7_174429.png)
关于PKMS的查询动作的细节,可参考PKMS的相关文档。目前我们只需知道,PKMS向外界提供了queryIntentReceivers()函数,该函数可以返回一个List<ResolveInfo>列表。
我们举个实际的例子:
?
ResolveInfo的定义截选如下:
?
关于receiver的注册动作,我们就先说这么多。下面我们来看看激发广播时的动作。
相关文章推荐
- 品茗论道说广播(Broadcast内部机制讲解)(上)
- (链接)品茗论道说广播(Broadcast内部机制讲解)
- 品茗论道说广播(Broadcast内部机制讲解)
- 品茗论道说广播(Broadcast内部机制讲解)
- 品茗论道说广播(Broadcast内部机制讲解)
- 广播(Broadcast内部机制讲解)
- Broadcast内部机制讲解
- Broadcast内部机制讲解 << 推荐
- 第一行代码 广播机制Broadcast Receiver 学习笔记
- 《老罗的Android之旅》阅读笔记——广播(Broadcast)机制
- Android系统中的广播(Broadcast)机制简要介绍和学习计划
- Android系统中的广播(Broadcast)机制简要介绍和学习计划
- Android 广播内部机制详解(三)
- 一个activity控制另一个activityUI更新(利用broadcast广播机制)
- Android系统中的广播(Broadcast)机制简要介绍和学习计划
- Android系统中的广播(Broadcast)机制简要介绍和学习计划
- Android系统中的广播(Broadcast)机制简要介绍和学习计划
- Android系统中的广播(Broadcast)机制注册注销发送原理总结
- 四大组件 广播机制之Broadcast
- Android系统中的广播(Broadcast)机制简要介绍和学习计划