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的内容。