本文为原创文章,欢迎转载!转载时请注明出处:http://blog.csdn.net/windskier
这篇文章开始从framework的角度来研究一下android四大控件最后一个控件BroadcastReceiver 的机制与原理,BroadcastReceiver 字面意思就是广播接收器,它能接收来自于系统的以及其他appliaction的广播消息,是android中非常重要的一个component。
BroadcastReceiver的注册有两种方式,一种是通过Context.registerReceiver()方法来进行动态注册,或者通过在AndroidManifest.xml中进行静态注册。AMS对两种不同注册方式的Receiver有不同的管理方式。静态注册就不用说了,静态注册的receiver的管理是有PMS负责的,而AMS则需要对动态注册的receiver注册和管理。下面就研究一下AMS对receiver的动态管理过程。
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();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission);
} catch (RemoteException e) {
return null;
}
}
oneway interface IIntentReceiver {
void performReceive(in Intent intent, int resultCode,
String data, in Bundle extras, boolean ordered, boolean sticky);
}
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
如果有多个符合receiver条件的
sticky
broadcast的话,那么AMS将会只返回一个时间较早的sticky broadcast,并且会将这些所有满足要求的sticky broadcast均发送给reciever,交由receiver去处理。sticky broadcast的发送于取消通过方法sendStickyBroadcast()/sendStickyOrderedBroadcast() 以及removeStickyBroadcast()来控制。
// Enqueue broadcasts for all existing stickies that match
// this filter.
if (allSticky != null) {
ArrayList receivers = new ArrayList();
receivers.add(bf);
int N = allSticky.size();
for (int i=0; i
对于每个注册过程,由两部分组成,一部分是是BroadcastReceiver,另一部分是IntentFilter,BroadcastReceiver通过IntentFilter来指定要接收的Intent BroadCast。而BroadcastFilter则是继承自IntentFilter,它记录了当前需注册的Receiver的IntentFilter信息。因此每一组BroadcastReceiver和IntentFilter对应一次注册过程,每个注册过程即是一个BroadcastReceiver向AMS指示一个Intent Broadcast的需求,如果有多个Intent Broadcast需求,BroadcastReceiver需要向AMS进行多次注册。
final IntentResolver mReceiverResolver
= new IntentResolver()
mReceiverResolver是一个IntentResolver类型的对象,通过它AMS可以将BroadcastFilter按照不同的元素,如action、data、category,进行管理,这样的话在AMS收到broadcast之后,会根据这个broadcast的Intent的元素去query mReceiverResolver,获取对应的BroadcastFilter。
既然mReceiverResolver实现了对BroadcastFilter的管理,那么前面的ReceiverList类型存在的意义是什么呢? mReceiverResolver和ReceiverList的关系其实并不冲突,AMS可以通过mReceiverResolver来获得可以接收发来的Broadcast的所有的BroadcastFilter。通过上面的类型关系图,我们可以看出BroadcastFilter中反向链接到自己所处的ReceiverList,看见两者之间的关系并不是对立的,而是适用于AMS接收分发过程的不同阶段。
就向前面介绍的android中的其他几大component一样,BroadReceiver在被处理时同样是通过一个BroadcastRecord的Record类型来进行管理的,BroadcastRecord只有在AMS在处理分发Broadcast时才去创建,它记录着每个Broadcast的信息,在Receiver的过程并不涉及Broadcast。
Broadcast根据不同的需求有多种不同的发送方式,下面来分析一下具体有几种发送方式。下面的表格列出了application几种不同的发送方式以及不同方式对应的方法。
不同的发送方式 |
对应的方法 |
普通模式 |
sendBroadcast(Intent intent) |
Broadcast sender 指定了receiver的permission,只有符合这个permission的receiver才能接收这个Broadcast |
sendBroadcast(Intent intent, String receiverPermission) |
要求符合要求的所有receiver (包括动态注册和静态注册的receiver)按照优先级顺序来接收这个Broadcast |
sendOrderedBroadcast(Intent intent, String receiverPermission) |
某些情况下,Broadcast sender在发出Broadcast之后,向AMS指定一个resultReceiver,期望所有的receiver接收并处理完Broadcast之后,将在各个receiver间传递的resultExtras返回给resultReceiver。这个resultExtras既可以由sender指定,也可以由某一个receiver指定,一般情况下只要receiver需要向sender返回数据,则可以通过这个resultExtras |
sendOrderedBroadcast(Intent intent,String receiverPermission, BroadcastReceiver resultReceiver,Handler scheduler, int initialCode, String initialData,Bundle initialExtras) |
Sticky Broadcast。前面已描述 |
sendStickyBroadcast(Intent intent); endStickyOrderedBroadcast(Intent intent,BroadcastReceiver resultReceiver,Handler scheduler, int initialCode, String initialData,Bundle initialExtras) |
AMS在处理收到的Broadcast时,需要对一些特殊的Broadcast做特殊处理,比如Package manager发来的关于Package移除、增加、修改等操作的,由于android系统允许user在package内部component在运行的情况下进行如上所述的操作,因此每当发生这些操作时,PM则会通过发送Broadcast的方式通知AMS进行属于AMS范畴的一些操作,如当PM移除某个Package的时候,要求AMS停止这个Package相关的所有Component等。
同样的,关于timezone的一些事件也是通过Broadcast的方式通知AMS,这里就不再分析。
从其名称看即是受保护的Broadcast,它声明在AndroidManifest.xml的一级节点中,对应的节点名称为
首先看一下protectedbroadcast的定义,它的主要元素就是一个action name,这些action只能被系统发送,我们可以想象一下,系统级别的broadcast可以不受限制的被所有的应用发送的后果,那将是非常严重的,不可想象的。因此从安全性的角度出发,android为了保证这些系统级别的broadcast不被第三方的应用滥发,提出了这个protected broadcast的概念。
Android规定了一些可以发送protected broadcast的进程,
● android:sharedUserId="android.uid.system"
● android:sharedUserId="android.uid.phone"
● android:sharedUserId="android.uid.shell"
● 设置android:persistent的appliaction。
对于其他不符合上述四条的进程发送broadcast时,AMS回去检查该是否是protected broadcast规定的action,如果是,那么将不允许这个broadcast发送。具体代码如下:
broadcastIntentLocked()@ActivityManagerService.java
if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
|| callingUid == Process.SHELL_UID || callingUid == 0) {
// Always okay.
} else if (callerApp == null || !callerApp.persistent) {
try {
if (AppGlobals.getPackageManager().isProtectedBroadcast(
intent.getAction())) {
String msg = "Permission Denial: not allowed to send broadcast "
+ intent.getAction() + " from pid="
+ callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
return BROADCAST_SUCCESS;
}
}
上面介绍了Protected Broadcast的作用,知道这类Broadcast一般是系统发送的,那么我们再来分析一下哪些AndroidManifest.xml中可以定义Protected Broadcast。我们可容易的想到,Protected Broadcast也不是随随便便定义在一个application的AndroidManifest.xml。
只有系统appliaction才能在其AndroidManifest.xml中定义Protected Broadcast,系统appliaction包括/system/framework、/system/app、vendor/app下的package,因此设备中安装的第三方apk中如果定义了Protected Broadcast,那么这个Protected Broadcast将不生效。下面代码是对parsePackage ()@PackageParser.java
} else if (tagName.equals("protected-broadcast")) {
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
// Note: don't allow this value to be a reference to a resource
// that may change.
String name = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
sa.recycle();
if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
if (pkg.protectedBroadcasts == null) {
pkg.protectedBroadcasts = new ArrayList();
}
if (!pkg.protectedBroadcasts.contains(name)) {
pkg.protectedBroadcasts.add(name.intern());
}
}
XmlUtils.skipCurrentTag(parser);
}
这一节来分析一下AMS在收到Broadcast之后,查找匹配的receiver来向其分发这个Broadcast。前面说过receiver有两种,一种是动态注册的,另一种则是预先定义静态注册的。不同类型的receiver有不同的管理方式,动态注册的receiver从上面章节中介绍的IntentResolver mReceiverResolver中获取;静态注册的receiver则是从PM中获取。
ordered模式下,动态注册的receiver将会采取和静态注册的receiver相同的处理模式,类似于一种同步模式,AMS会等待一个reciever处理完这个Broadcast,才会将Broadcast分发给下一个receiver。这种模式下,receiver的处理有了先后顺序,因此必须考虑如何布置这个先后顺序,这里按照优先级的顺序来给receiver的处理顺序进行排序。
对于动态注册的receiver,可以在其IntentFilter类型中定义它的优先级;而对于静态注册的receiver,同样的我们可以在其
broadcastIntentLocked()@ActivityManagerService.java
int NT = receivers != null ? receivers.size() : 0;
int it = 0;
ResolveInfo curt = null;
BroadcastFilter curr = null;
while (it < NT && ir < NR) {
if (curt == null) {
curt = (ResolveInfo)receivers.get(it);
}
if (curr == null) {
curr = registeredReceivers.get(ir);
}
if (curr.getPriority() >= curt.priority) {
// Insert this broadcast record into the final list.
receivers.add(it, curr);
ir++;
curr = null;
it++;
NT++;
} else {
// Skip to the next ResolveInfo in the final list.
it++;
curt = null;
}
}
}
while (ir < NR) {
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(registeredReceivers.get(ir));
ir++;
}
Broadcast分发过程是一个异步过程,AMS在收到Broadcast之后,会根据不同类型的receiver,按照Broadcast发送发指定的发送模式进行分发,现在我们来分析一下Broadcast分发过程。
AMS向自己的消息队列发送消息BROADCAST_INTENT_MSG对所有的receiver进行分发操作,所有的分发操作由方法processNextBroadcast()来实现,因此这一部分我们着重分析一下这个方法中的实现过程。
上面已经对ordered模式和非ordered模式进行了简单介绍,这里不再多介绍了。对于非ordered模式的分发过程,AMS则会将Broadcast直接分发给符合要求的receiver的进程的消息队列,这种分发的方式可以视作一种异步方式,也可以看作是将该Broadcast同时分发给符合要求的动态注册的receiver,上面章节中我们分析过只有动态注册的receiver才会有ordered和非ordered模式之分,而静态注册的reciever则无此之分,一概视为ordered模式。
我们知道需要ordered分发的receiver既包括动态注册的receiver,又包括静态注册的receiver,但是AMS向两种不同的注册方式的receiver分发Broadcast的方式有不尽相同,但是最基本的发送及处理过程是按照上面的图示进行的,两种注册方式具体的分发和处理内容如下图所示:
针对每个BroadcastRecord的处理,均会设置一个总时长,这个总时长是指所有符合BroadcastRecord条件的receiver处理完这个Broadcast的总时长的上限。也就是说如果满足条件的所有的Receiver均已经接收并处理完了这个Broadcast的时刻,不能超过规定的总时长,总时长跟满足条件的Receiver总个数有关系,如下面代码所示:
processNextBroadcast ()@ActivityManagerService.java
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
if (mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
Slog.w(TAG, "Hung broadcast discarded after timeout failure:"
+ " now=" + now
+ " dispatchTime=" + r.dispatchTime
+ " startTime=" + r.receiverTime
+ " intent=" + r.intent
+ " numReceivers=" + numReceivers
+ " nextReceiver=" + r.nextReceiver
+ " state=" + r.state);
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
除了设置针对一个BroadcastRecord的处理的总时长外,android针对每个Receiver的处理时长也做了一个时限设定,保证每一个的Receiver的处理时长不超过规定时长,具体如下面代码所示:
processNextBroadcast ()@ActivityManagerService.javaif (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT;
if (DEBUG_BROADCAST) Slog.v(TAG,
"Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " + timeoutTime);
setBroadcastTimeoutLocked(timeoutTime);
}
如果上述2种时长存在超时的话,AMS将会抛出ANR, 向user报告当前的Receiver在处理Broadcast时存在无响应状况或者响应时间过长等状况。
broadcastTimeoutLocked()@ActivityManagerService.java
if (anrMessage != null) {
// Post the ANR to the handler since we do not want to process ANRs while
// potentially holding our lock.
mHandler.post(new AppNotResponding(app, anrMessage));
}