Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx

上传人:b****3 文档编号:27027506 上传时间:2023-06-25 格式:DOCX 页数:43 大小:355.01KB
下载 相关 举报
Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx_第1页
第1页 / 共43页
Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx_第2页
第2页 / 共43页
Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx_第3页
第3页 / 共43页
Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx_第4页
第4页 / 共43页
Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx_第5页
第5页 / 共43页
点击查看更多>>
下载资源
资源描述

Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx

《Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx》由会员分享,可在线阅读,更多相关《Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx(43页珍藏版)》请在冰豆网上搜索。

Android 70 ActivityManagerService5 广播Broadcast相关流程分析2.docx

Android70ActivityManagerService5广播Broadcast相关流程分析2

Android7.0ActivityManagerService(5)广播(Broadcast)相关流程分析

(2)

4broadcastIntentLocked函数PartIV

.................

//Mergeintoonelist.

intir=0;

if(receivers!

=null){

//AspecialcaseforPACKAGE_ADDED:

donotallowthepackage

//beingaddedtoseethisbroadcast.Thispreventsthemfrom

//usingthisasabackdoortogetrunassoonastheyare

//installed.Maybeinthefuturewewanttohaveaspecialinstall

//broadcastorsuchforapps,butwe'dliketodeliberatelymake

//thisdecision.

//处理特殊的Action,例如PACKAGE_ADDED,系统不希望有些应用一安装就能启动

//APP安装后,PKMS将发送PACKAGE_ADDED广播

//若没有这个限制,在刚安装的APP内部静态注册监听该消息的BroadcastReceiver,新安装的APP就能直接启动

StringskipPackages[]=null;

if(Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())

||Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())

||Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())){

Uridata=intent.getData();

if(data!

=null){

StringpkgName=data.getSchemeSpecificPart();

if(pkgName!

=null){

skipPackages=newString[]{pkgName};

}

}

}elseif(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())){

skipPackages=intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);

}

if(skipPackages!

=null&&(skipPackages.length>0)){

for(StringskipPackage:

skipPackages){

if(skipPackage!

=null){

intNT=receivers.size();

for(intit=0;it

ResolveInfocurt=(ResolveInfo)receivers.get(it);

if(curt.activityInfo.packageName.equals(skipPackage)){

//将skipPackages对应的BroadcastReceiver移出receivers

receivers.remove(it);

it--;

NT--;

}

}

}

}

}

intNT=receivers!

=null?

receivers.size():

0;

intit=0;

ResolveInfocurt=null;

BroadcastFiltercurr=null;

//NT对应的是静态BroadcastReceiver的数量

//NR对应的是动态BroadcastReceiver的数量

//若发送的是无序广播,此时NR为0

//若是有序广播,才会进入下面两个while循环

//下面两个while循环就是将静态注册的BroadcastReceiver和动态注册的BroadcastReceiver

//按照优先级合并到一起(有序广播才会合并)

while(it

if(curt==null){

curt=(ResolveInfo)receivers.get(it);

}

if(curr==null){

curr=registeredReceivers.get(ir);

}

//动态优先级大于静态时,将动态插入到receivers中

if(curr.getPriority()>=curt.priority){

//Insertthisbroadcastrecordintothefinallist.

receivers.add(it,curr);

ir++;

curr=null;

it++;

NT++;

}else{

//SkiptothenextResolveInfointhefinallist.

it++;

curt=null;

}

}

}

while(ir

if(receivers==null){

receivers=newArrayList();

}

//插入剩下的动态BroadcastReceiver

receivers.add(registeredReceivers.get(ir));

ir++;

}

if((receivers!

=null&&receivers.size()>0)

||resultTo!

=null){

BroadcastQueuequeue=broadcastQueueForIntent(intent);

//构造对应的BroadcastRecord

BroadcastRecordr=newBroadcastRecord(........);

............

//同样判断是否需要替换,这里是OrderedQueue

booleanreplaced=replacePending&&queue.replaceOrderedBroadcastLocked(r);

if(!

replaced){

//没替换时,就加入OrderedQueue

queue.enqueueOrderedBroadcastLocked(r);

//触发发送流程

queue.scheduleBroadcastsLocked();

}

}else{

//Therewasnobodyinterestedinthebroadcast,butwestillwanttorecord

//thatithappened.

if(intent.getComponent()==null&&intent.getPackage()==null

&&(intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)==0){

//Thiswasanimplicitbroadcast...let'srecorditforposterity.

//没有处理的静态或有序广播,保存起来

//感觉保存起来也没什么用啊

addBroadcastStatLocked(intent.getAction(),callerPackage,0,0,0);

}

}

...............

简单来说,broadcastIntentLocked的第四部分工作就是为有序广播和静态广播,构造对应的BroadcastRecord(按优先级顺序),

然后将BroadcastRecord加入到OrderedQueue中,并触发广播发送流程。

至此,整个broadcastIntentLocked函数分析完毕,除去一些条件判断的细节外,整个工作流程如下图所示:

1、处理粘性广播。

由于粘性广播的特性(BroadcastReceiver注册即可接收),系统必须首先保存粘性广播。

2、处理普通动态广播。

普通广播是并发的,系统优先为动态注册的BroadcastReceiver发送广播。

动态广播对应的BroadcastRecord加入到ParallelQueue中。

3、处理静态广播和有序广播。

这一步主要是为静态注册的BroadcastReceiver发送广播,对应的BroadcastRecord加入到OrderedQueue中。

此外,需要注意的是:

如果广播是有序的,那么第2步不会为动态注册的BroadcastReceiver发送广播,而是在第3步统一发送。

发送有序广播时,AMS将按照BroadcastReceiver的优先级,依次构造BroadcastRecord加入到OrderedQueue中。

四、BroadcastQueue的scheduleBroadcastsLocked函数流程分析

从上面的代码,我们知道广播发送方调用sendBroadcast后,AMS会构造对应的BroadcastRecord加入到BroadcastQueue中,

然后调用BroadcastQueue的scheduleBroadcastsLocked函数。

现在,我们就来看一下scheduleBroadcastsLocked相关的流程。

publicvoidscheduleBroadcastsLocked(){

...........

//避免短时间内重复发送BROADCAST_INTENT_MSG

if(mBroadcastsScheduled){

return;

}

mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG,this));

mBroadcastsScheduled=true;

}

上面的代码将发送BROADCAST_INTENT_MSG,触发BroadcastQueue调用processNextBroadcast进行处理。

processNextBroadcast函数同样非常的长,大概有500多行。

我们还是分段进行分析。

1processNextBroadcast函数PartI

finalvoidprocessNextBroadcast(booleanfromMsg){

synchronized(mService){

BroadcastRecordr;

..............

//更新CPU的使用情况

//处理静态广播时,可能需要拉起对应进程,因此在这里先记录一下CPU情况

mService.updateCpuStats();

if(fromMsg){

//处理BROADCAST_INTENT_MSG后,将mBroadcastsScheduled置为false

//scheduleBroadcastsLocked就可以再次被调用了

mBroadcastsScheduled=false;

}

//First,deliveranynon-serializedbroadcastsrightaway.

//先处理“并发”发送的普通广播

while(mParallelBroadcasts.size()>0){

//依次取出BroadcastRecord

r=mParallelBroadcasts.remove(0);

//记录发送的时间

r.dispatchTime=SystemClock.uptimeMillis();

r.dispatchClockTime=System.currentTimeMillis();

finalintN=r.receivers.size();

................

for(inti=0;i

//mParallelBroadcasts中的每个成员均为BroadcastFilter类型

Objecttarget=r.receivers.get(i);

............

//为该BroadcastRecord对应的每个Receiver发送广播

deliverToRegisteredReceiverLocked(r,(BroadcastFilter)target,false,i);

}

//将这里处理过的信息加入到历史记录中

addBroadcastToHistoryLocked(r);

}

........................

}

}

从上面的代码可以看出,processNextBroadcast函数的第一部分主要是为动态注册的BroadcastReceiver发送普通广播。

发送普通广播的函数为deliverToRegisteredReceiverLocked:

privatevoiddeliverToRegisteredReceiverLocked(BroadcastRecordr,

BroadcastFilterfilter,booleanordered,intindex){

booleanskip=false;

//检查广播发送方是否有BroadcastReceiver指定的权限

if(filter.requiredPermission!

=null){

intperm=mService.checkComponentPermission(filter.requiredPermission,

r.callingPid,r.callingUid,-1,true);

if(perm!

=PackageManager.PERMISSION_GRANTED){

............

skip=true;

}else{

//进一步检查权限的合理性

finalintopCode=AppOpsManager.permissionToOpCode(filter.requiredPermission);

if(opCode!

=AppOpsManager.OP_NONE

&&mService.mAppOpsService.noteOperation(opCode,r.callingUid,

r.callerPackage)!

=AppOpsManager.MODE_ALLOWED){

............

skip=true;

}

}

}

//检查BroadcastReceiver是否有Broadcast要求的权限

if(!

skip&&r.requiredPermissions!

=null&&r.requiredPermissions.length>0){

for(inti=0;i

StringrequiredPermission=r.requiredPermissions[i];

intperm=mService.checkComponentPermission(requiredPermission,

filter.receiverList.pid,filter.receiverList.uid,-1,true);

if(perm!

=PackageManager.PERMISSION_GRANTED){

.................

//只要一条权限不满足,就结束

skip=true;

break;

}

//进一步检查权限的合理性

intappOp=AppOpsManager.permissionToOpCode(requiredPermission);

if(appOp!

=AppOpsManager.OP_NONE&&appOp!

=r.appOp

&&mService.mAppOpsService.noteOperation(appOp,

filter.receiverList.uid,filter.packageName)

!

=AppOpsManager.MODE_ALLOWED){

...........

skip=true;

break;

}

}

}

//这段代码我看的有些懵逼,发送方没要求权限,还检查啥?

if(!

skip&&(r.requiredPermissions==null||r.requiredPermissions.length==0)){

intperm=mService.checkComponentPermission(null,

filter.receiverList.pid,filter.receiverList.uid,-1,true);

if(perm!

=PackageManager.PERMISSION_GRANTED){

............

skip=true;

}

}

//还有一些其它的检查,不再分析代码了。

//包括是否允许以background的方式发送、IntentFirewall是否允许广播中的Intent发送

...............................

if(skip){

//不满足发送条件的话,标记一下,结束发送

r.delivery[index]=BroadcastRecord.DELIVERY_SKIPPED;

return;

}

//Ifpermissionsneedareviewbeforeanyoftheappcomponentscanrun,wedrop

//thebroadcastandifthecallingappisintheforegroundandthebroadcastis

//explicitwelaunchthereviewUIpassingitapendingintenttosendtheskipped

//broadcast.

//特殊情况,还需要再次检查权限,中断广播发送

//再次满足发送条件后,会重新进入到后续的发送流程

if(Build.PERMISSIONS_REVIEW_REQUIRED){

if(!

requestStartTargetPermissionsReviewIfNeededLocked(r,filter.packageName,

filter.owningUserId)){

r.delivery[index]=BroadcastRecord.DELIVERY_SKIPPED;

return;

}

}

//可以发送了,标记一下

r.delivery[index]=BroadcastRecord.DELIVERY_DELIVERED;

//Ifthisisnotbeingsentasanorderedbroadcast,thenwe

//don'twanttotouchthefieldsthatkeeptrackofthecurrent

//stateoforderedbroadcasts.

if(ordered){

//如果发送的是有序广播,则记录一些状态信息等,不涉及广播发送的过程

.............

}

try{

..............

//若BroadcastReceiver对应的进程处于fullBackup状态(备份和恢复),则不发送广播

if(filter.receiverList.app!

=null&&filter.receiverList.app.inFullBackup){

if(ordered){

//有序广播必须处理完一个,才能处理下一个,因此这里主动触发一下

skipReceiverLocked(r);

}

}else{

//执行发送工作

performReceiveLocked(.............);

}

if(ordered){

r.state=BroadcastRecord.CALL_DONE_RECEIVE;

}

}catch(RemoteExceptione){

.............

}

}

deliverToRegisteredReceiverLocked看起来很长,但大部分内容都是进行权限检查等操作,实际的发送工作交给了performReceiveLocked函数。

广播是一种可以携带数据的跨进程、跨APP通信机制,为了避免安全泄露的问题,Android才在此处使用了大量的篇幅进行权限检查的工作。

在这一部分的最后,我们跟进一下performReceiveLocked函数:

voidperformReceiveLocked(.........){

//Sendtheintenttothereceiverasynchronouslyusingone-waybindercalls.

if(app!

=null){

if(app.thread!

=null){

//Ifwehaveanappthread,dothecallthroughthatsoitis

//correctlyorderedwithotherone-waycalls.

try{

//通过Binder通信,将广播信息发往BroadcastReceiver处在的进程

app.thread.scheduleRegisteredReceiver(.......);

}catch(RemoteExceptionex){

//Failedtocallintothe

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1