http://my.oschina.net/youranhongcha/blog/226274
目录[-]
- 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)集中管理。
在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对象完成:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Override
public
Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
{
return
registerReceiver(receiver, filter,
null
,
null
);
}
@Override
public
Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler)
{
return
registerReceiverInternal(receiver, filter, broadcastPermission,
scheduler, getOuterContext());
}
|
注册之时,用户会把一个自定义的receiver对象作为第一个参数传入。当然,用户的receiver都是继承于BroadcastReceiver的。使用过广播机制的程序员,对这个BroadcastReceiver应该都不陌生,这里就不多说了。我们需要关心的是,这个registerReceiverInternal()内部还包含了什么重要的细节。
registerReceiverInternal()代码的截选如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
private
Intent registerReceiverInternal(BroadcastReceiver receiver,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context)
{
IIntentReceiver rd =
null
;
if
(receiver !=
null
)
{
if
(mPackageInfo !=
null
&& context !=
null
)
{
if
(scheduler ==
null
)
{
scheduler = mMainThread.getHandler();
}
// 查找和context对应的“子哈希表”里的ReceiverDispatcher,如果找不到,就重新new一个
rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,
mMainThread.getInstrumentation(),
true
);
}
. . . . . .
}
try
{
return
ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission);
}
catch
(RemoteException e)
{
return
null
;
}
}
|
请大家注意那个rd对象(IIntentReceiver rd)。我们知道,在Android架构中,广播动作最终其实都是由AMS递送出来的。AMS利用binder机制,将语义传递给各个应用进程,应用进程再辗转调用到receiver的onReceive(),完成这次广播。而此处的rd对象正是承担“语义传递工作“的binder实体。
为了管理这个重要的binder实体,Android搞出了一个叫做ReceiveDispatcher的类。该类的定义截选如下:
【frameworks/base/core/java/android/app/LoadedApk.java】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
static
final
class
ReceiverDispatcher
{
final
static
class
InnerReceiver
extends
IIntentReceiver.Stub {
. . . . . .
. . . . . .
}
final
IIntentReceiver.Stub mIIntentReceiver;
// 请注意这个域!它就是传到外面的rd。
final
BroadcastReceiver mReceiver;
final
Context mContext;
final
Handler mActivityThread;
final
Instrumentation mInstrumentation;
final
boolean
mRegistered;
final
IntentReceiverLeaked mLocation;
RuntimeException mUnregisterLocation;
boolean
mForgotten;
. . . . . .
|
这样看来,“动态注册的BroadcastReceiver”和“ReceiverDispatcher节点”具有一一对应的关系。示意图如下:
一个应用里可能会注册多个动态receiver,所以这种一一对应关系最好整理成表,这个表就位于LoadedApk中。前文mPackageInfo.getReceiverDispatcher()一句中的mPackageInfo就是LoadedApk对象。
在Android的架构里,应用进程里是用LoadedApk来对应一个apk的,进程里加载了多少个apk,就会有多少LoadedApk。每个LoadedApk里会有一张“关于本apk动态注册的所有receiver”的哈希表(mReceivers)。当然,在LoadedApk初创之时,这张表只是个空表。
mReceivers表的定义如下:
1
2
3
|
private
final
HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers
=
new
HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
|
该表的key项是我们比较熟悉的Context,也就是说可以是Activity、Service或Application。而value项则是另一张“子哈希表”。这是个“表中表”的形式。言下之意就是,每个Context(比如一个activity),是可以注册多个receiver的,这个很好理解。mReceivers里的“子哈希表”的key值为BroadcastReceiver,value项为ReceiverDispatcher,示意图如下:
图:客户进程中的mReceivers表
接下来我们继续看registerReceiverInternal(),它最终调用到
1
2
3
|
ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission);
|
registerReceiver()函数的filter参数指明了用户对哪些intent感兴趣。对同一个BroadcastReceiver对象来说,可以注册多个感兴趣的filter,就好像声明静态receiver时,也可以为一个receiver编写多个<intent-filter>一样。这些IntentFilter信息会汇总到AMS的mRegisteredReceivers表中。在AMS端,我们可以这样访问相应的汇总表:
1
|
ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
|
其中的receiver参数为IIntentReceiver型,正对应着ReceiverDispatcher中那个binder实体。也就是说,每个客户端的ReceiverDispatcher,会对应AMS端的一个ReceiverList。
ReceiverList的定义截选如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
class
ReceiverList
extends
ArrayList<BroadcastFilter>
implements
IBinder.DeathRecipient
{
final
ActivityManagerService owner;
public
final
IIntentReceiver receiver;
public
final
ProcessRecord app;
public
final
int
pid;
public
final
int
uid;
BroadcastRecord curBroadcast =
null
;
boolean
linkedToDeath =
false
;
String stringName;
. . . . . .
|
ReceiverList继承于ArrayList<BroadcastFilter>,而BroadcastFilter又继承于IntentFilter,所以ReceiverList可以被理解为一个IntentFilter数组列表。
1
2
3
4
5
|
class
BroadcastFilter
extends
IntentFilter {
final
ReceiverList receiverList;
final
String packageName;
final
String requiredPermission;
. . . . . .
|
现在,我们可以绘制一张完整一点儿的图:
这张图只画了一个用户进程,在实际的系统里当然会有很多用户进程了,不过其关系是大致统一的,所以我们不再重复绘制。关于动态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(决策器),其示意图如下:
关于PKMS的查询动作的细节,可参考PKMS的相关文档。目前我们只需知道,PKMS向外界提供了queryIntentReceivers()函数,该函数可以返回一个List<ResolveInfo>列表。
我们举个实际的例子:
1
2
3
4
|
Intent intent =
new
Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
List<ResolveInfo> ris =
null
;
try
{
ris = AppGlobals.getPackageManager().queryIntentReceivers(intent,
null
,
0
,
0
);
}
catch
(RemoteException e) {}
|
这是AMS的systemReady()函数里的一段代码,意思是查找有多少receiver对ACTION_PRE_BOOT_COMPLETED感兴趣。
ResolveInfo的定义截选如下:
1
2
3
4
5
6
7
8
9
10
|
public
class
ResolveInfo
implements
Parcelable
{
public
ActivityInfo activityInfo;
public
ServiceInfo serviceInfo;
public
IntentFilter filter;
public
int
priority;
public
int
preferredOrder;
public
int
match;
. . . . . .
. . . . . .
|
总之,当系统希望发出一个广播时,PKMS必须能够决策出,有多少静态receiver对这个广播感兴趣,而且这些receiver的信息分别又是什么。
关于receiver的注册动作,我们就先说这么多。下面我们来看看激发广播时的动作。