6.4.3 BROADCAST_INTENT_MSG消息处理函数
BROADCAST_INTENT_MSG消息将触发processNextBroadcast函数,下面分阶段来分析该函数。
1.processNextBroadcast分析之一
[—>ActivityManagerService.java:processNextBroadcast]
private final void processNextBroadcast(boolean fromMsg){
//如果是BROADCAST_INTENT_MSG消息触发该函数,则fromMsg为true
synchronized(this){
BroadcastRecord r;
updateCpuStats();//更新CPU使用情况
if(fromMsg)mBroadcastsScheduled=false;
//先处理mParallelBroadcasts中的成员。如前所述,AMS在一个循环中处理它们
while(mParallelBroadcasts.size()>0){
r=mParallelBroadcasts.remove(0);
r.dispatchTime=SystemClock.uptimeMillis();
r.dispatchClockTime=System.currentTimeMillis();
final int N=r.receivers.size();
for(int i=0;i<N;i++){
Object target=r.receivers.get(i);
//①mParallelBroadcasts中的成员全为BroadcastFilter类型,所以下面的函数
//将target直接转换成BroadcastFilter类型。注意,最后一个参数为false
deliverToRegisteredReceiverLocked(r,(BroadcastFilter)target,
false);
}
//将这条处理过的记录保存到mHistoryBroadcast中,供调试使用
addBroadcastToHistoryLocked(r);
}
deliverToRegisteredReceiverLocked函数的功能就是派发广播给接收者,其代码如下:
[—>ActivityManagerService.java:deliverToRegisteredReceiverLocked]
private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered){
boolean skip=false;
//检查发送进程是否有filter要求的权限
if(filter.requiredPermission!=null){
int perm=checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid,-1,true);
if(perm!=PackageManager.PERMISSION_GRANTED)skip=true;
}
//检查接收者是否有发送者要求的权限
if(r.requiredPermission!=null){
int perm=checkComponentPermission(r.requiredPermission,
filter.receiverList.pid, filter.receiverList.uid,-1,true);
if(perm!=PackageManager.PERMISSION_GRANTED)skip=true;
}
if(!skip){
if(ordered){
……//设置一些状态、成员变量等信息,不涉及广播发送
}
try{
//发送广播
performReceiveLocked(filter.receiverList.app,
filter.receiverList.receiver, new Intent(r.intent),r.resultCode,
r.resultData, r.resultExtras, r.ordered, r.initialSticky);
if(ordered)r.state=BroadcastRecord.CALL_DONE_RECEIVE;
}……
}
}
}
下面来看performReceiveLocked函数,其代码如下:
[—>ActivityManagerService.java:performReceiveLocked]
static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky)throws RemoteException{
if(app!=null&&app.thread!=null){
//如果app及app.thread不为null,则调度scheduleRegisteredReceiver,
//注意这个函数名为scheduleRegisteredReceiver,它只针对动态注册的广播接收者
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky);
}else{
//否则调用IIntentReceiver的performReceive函数
receiver.performReceive(intent, resultCode, data, extras,
ordered, sticky);
}
}
对于动态注册者而言,在大部分情况下会执行上述代码中的if分支,所以应用进程Application Thread的schedule Registered Receiver函数将被调用。稍后再分析应用进程的广播处理流程。
2.process Next Broadcast分析之二
至此,process Next Broadcast已经在一个while循环中处理完mParallel Broadcasts的所有成员了,实际上,这种处理方式也会造成惊群效应,但影响相对较少。这是因为对于动态注册者来说,它们所在的应用进程已经创建并初始化成功。此处的广播发送只是调用应用进程的一个函数而已。相比于创建进程,再初始化Android运行环境所需的工作量,调用schedule Registered Receiver的工作就比较轻松了。
下面来看process Next Broadcast第二阶段的工作,代码如下:
[—>Activity Manager Service.java:process Next Broadcast]
/*
现在要处理mOrderedBroadcasts中的成员。如前所述,它要处理一个接一个地接收者,如果
接收者所在进程还未启动,则需要等待。mPending Broadcast变量用于标志因为应用进程还未
启动而处于等待状态的Broadcast Record。
*/
if(mPending Broadcast!=null){
boolean isDead;
synchronized(mPids Self Locked){
isDead=(mPidsSelf Locked.get(mPending Broadcast.curApp.pid)==null);
}
/*重要说明
判断要等待的进程是否为dead进程,如果没有dead进程,则继续等待。仔细思考,此处直接
返回会有什么问题。
问题不小!假设有两个ordered广播A和B,有两个接收者,AR和BR,并且BR所
在进程已经启动并完成初始化Android运行环境工作。如果process Next Broadcast先处理A,再处理B,那么此处B的处理将因为mPending Broadcast不为空而被延后。虽然B和A
之间没有任何关系(例如完全是两个不同的广播消息)。
但是事实上,大多数开发人员理解的order是针对单个广播的,例如A有5个接收者,那么对这
5个接收者的广播的处理是串行的。通过此处的代码发现,系统竟然串行处理A和B广播,即
B广播要待到A的5个接收者都处理完了才能处理
*/
if(!isDead)return;
else{
mPending Broadcast.state=Broadcast Record.IDLE;
mPending Broadcast.next Receiver=mPending Broadcast RecvIndex;
mPendingBroadcast=null;
}
}
boolean looped=false;
do{
//mOrderedBroadcasts处理完毕
if(mOrdered Broadcasts.size()==0){
schedule App GcsLocked();
if(looped)update OomAdj Locked();
return;
}
r=mOrdered Broadcasts.get(0);
boolean force Receive=false;
//下面这段代码用于判断此条广播是否处理时间过长
//先得到该条广播的所有接收者
int numReceivers=(r.receivers!=null)?r.receivers.size():0;
if(mProcesses Ready&&r.dispatchTime>0){
long now=System Clock.uptime Millis();
//如果总耗时超过2倍的接收者个数*每个接收者最长处理时间(10秒),则
//强制结束这条广播的处理
if((numReceivers>0)&&
(now>r.dispatchTime+
(2BROADCAST_TIMEOUTnumReceivers))){
broadcastTimeoutLocked(false);//读者阅读完本节后可自行研究该函数
forceReceive=true;
r.state=Broadcast Record.IDLE;
}
}//if(mProcesses Ready……)判断结束
if(r.state!=Broadcast Record.IDLE)return;
//如果下面这个if条件满足,则表示该条广播要么已经全部被处理,要么被中途取消
if(r.receivers==null||r.nextReceiver>=numReceivers
||r.result Abort||force Receive){
if(r.resultTo!=null){
try{
//将该广播的处理结果传给设置了resultTo的接收者
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent),r.resultCode,
r.resultData, r.result Extras, false, false);
r.resultTo=null;
}……
}
cancel Broadcast Timeout Locked();
addBroadcast To History Locked(r);
mOrdered Broadcasts.remove(0);
r=null;
looped=true;
continue;
}
}while(r==null);
processNextBroadcast第二阶段的工作比较简单:
首先根据是否处于pending状态(mPendingBroadcast不为null)进行相关操作。读者要认真体会代码中的重要说明。
处理超时的广播记录。这个超时时间是2BROADCAST_TIMEOUTnumReceivers。BROADCAST_TIMEOUT默认为10秒。由于涉及创建进程,初始化Android运行环境等“重体力活”,故此处超时时间还乘以一个固定倍数2。
3.processNextBroadcast分析之三
下面来看processNextBroadcast第三阶段的工作,代码如下:
[—>ActivityManagerService.java:processNextBroadcast]
int recIdx=r.nextReceiver++;
r.receiverTime=SystemClock.uptimeMillis();
if(recIdx==0){
r.dispatchTime=r.receiverTime;//记录本广播第一次处理开始的时间
r.dispatchClockTime=System.currentTimeMillis();
}
//设置广播处理超时时间,BROADCAST_TIMEOUT为10秒
if(!mPendingBroadcastTimeoutMessage){
long timeoutTime=r.receiverTime+BROADCAST_TIMEOUT;
setBroadcastTimeoutLocked(timeoutTime);
}
//取该条广播下一个接收者
Object nextReceiver=r.receivers.get(recIdx);
if(nextReceiver instanceof BroadcastFilter){
//如果是动态接收者,则直接调用deliver To Registered ReceiverLocked处理
BroadcastFilter filter=(BroadcastFilter)next Receiver;
deliver To Registered Receiver Locked(r, filter, r.ordered);
if(r.receiver==null||!r.ordered){
r.state=Broadcast Record.IDLE;
schedule Broadcasts Locked();
}
return;//已经通知一个接收者去处理该广播,需要等它的处理结果,所以此处直接返回
}
//如果是静态接收者,则它的真实类型是ResolveInfo
ResolveInfo info=(ResolveInfo)nextReceiver;
boolean skip=false;
//检查权限
int perm=checkComponentPermission(info.activityInfo.permission,
r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
info.activityInfo.exported);
if(perm!=PackageManager.PERMISSION_GRANTED)skip=true;
if(info.activityInfo.applicationInfo.uid!=Process.SYSTEM_UID&&
r.requiredPermission!=null){
……
}
//设置skip为true
if(r.curApp!=null&&r.curApp.crashing)skip=true;
if(skip){
r.receiver=null;
r.curFilter=null;
r.state=BroadcastRecord.IDLE;
scheduleBroadcastsLocked();//再调度一次广播处理
return;
}
r.state=BroadcastRecord.APP_RECEIVE;
String targetProcess=info.activityInfo.processName;
r.curComponent=new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
r.curReceiver=info.activityInfo;
try{
//设置Package stopped的状态为false
AppGlobals.getPackageManager().setPackageStoppedState(
r.curComponent.getPackageName(),false);
}……
ProcessRecord app=getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid);
//如果该接收者对应的进程已经存在
if(app!=null&&app.thread!=null){
try{
app.addPackage(info.activityInfo.packageName);
//该函数内部调用应用进程的scheduleReceiver函数,读者可自行分析
processCurBroadcastLocked(r, app);
return;//已经触发该接收者处理本广播,需要等待处理结果
}……
}
//最糟的情况就是该进程还没有启动
if((r.curApp=startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,……)!=0))==null){
……//进程启动失败的处理
return;
}
mPendingBroadcast=r;//设置mPendingBroadcast
mPendingBroadcastRecvIndex=recIdx;
}
对processNextBroadcast第三阶段的工作总结如下:
如果广播接收者为动态注册对象,则直接调用deliverToRegisteredReceiverLocked处理它。
如果广播接收者为静态注册对象,并且该对象对应的进程已经存在,则调用processCurBroadcastLocked处理它。
如果广播接收者为静态注册对象,并且该对象对应的进程还不存在,则需要创建该进程。这是最糟糕的情况。
此处,不再讨论新进程创建及与Android运行环境初始化相关的逻辑,读者可返回阅读“attachApplicationLocked分析之三”,其中有处理mPendingBroadcast的内容。