Android 7.0 ActivityManagerService(5) 广播(Broadcast)相关流程分析(1)

发布时间 : 星期五 文章Android 7.0 ActivityManagerService(5) 广播(Broadcast)相关流程分析(1)更新完毕开始阅读

需要注意的是:

在onReceive函数中执行异步操作,主要目的是避免一些操作阻塞了主线程,

但整个操作仍然需要保证在10s内返回结果,尤其是处理有序广播和静态广播时。 毕竟AMS必须要收到返回结果后,才能向下一个BroadcastReceiver发送广播。

2 AMS中的registerReceiver

AMS的registerReceiver函数被调用时,将会保存BroadcastReceiver对应的Binder通信端,我们一起来看看这部分的代码:

public Intent registerReceiver(IApplicationThread caller, String callerPackage,

IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { ...............

//保存系统内已有的sticky广播

ArrayList stickyIntents = null; ...............

synchronized(this) { if (caller != null) {

//根据IApplicationThread得到对应的进程信息 callerApp = getRecordForAppLocked(caller);

if (callerApp == null) {

//抛出异常,即不允许未登记的进程注册BroadcastReceiver ............... }

if (callerApp.info.uid != Process.SYSTEM_UID &&

!callerApp.pkgList.containsKey(callerPackage) && !\

//抛出异常,即注册进程必须携带Package名称 .................. } } else {

............. }

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

//为了得到IntentFilter中定义的Action信息,先取出其Iterator Iterator actions = filter.actionsIterator(); if (actions == null) {

ArrayList noAction = new ArrayList(1); noAction.add(null);

actions = noAction.iterator(); }

// Collect stickies of users

int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) }; while (actions.hasNext()) {

//依次比较BroadcastReceiver关注的Action与Stick广播是否一致 String action = actions.next(); for (int id : userIds) {

ArrayMap> stickies = mStickyBroadcasts.get(id); if (stickies != null) {

//Sticky广播中,有BroadcastReceiver关注的

//可能有多个Intent,对应的Action相似,在此先做一个初步筛选 ArrayList intents = stickies.get(action); if (intents != null) {

if (stickyIntents == null) {

stickyIntents = new ArrayList(); }

//将这些广播保存到stickyIntents中 stickyIntents.addAll(intents); } } } } }

ArrayList allSticky = null;

//stickyIntents中保存的是action匹配的 if (stickyIntents != null) { //用于解析intent的type

final ContentResolver resolver = mContext.getContentResolver();

// Look for any matching sticky broadcasts...

for (int i = 0, N = stickyIntents.size(); i < N; i++) { Intent intent = stickyIntents.get(i);

//此时进一步判断Intent与BroadcastReceiver的IntentFilter是否匹配 if (filter.match(resowww.sm136.comlver, intent, true, TAG) >= 0) { if (allSticky == null) {

allSticky = new ArrayList(); }

allSticky.add(intent); } } }

// The first sticky in the list is returned directly back to the client. Intent sticky = allSticky != null ? allSticky.get(0) : null; ................

synchronized (this) { ..............

//一个Receiver可能监听多个广播,多个广播对应的BroadcastFilter组成ReceiverList ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) {

//首次注册,rl为null,进入此分支

//新建BroadcastReceiver对应的ReceiverList

rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver); if (rl.app != null) {

rl.app.receivers.add(rl); } else { try {

//rl监听receiver所在进程的死亡消息 receiver.asBinder().linkToDeath(rl, 0); } catch (RemoteException e) { return sticky; }

rl.linkedToDeath = true; }

//保存到AMS上

mRegisteredReceivers.put(receiver.asBinder(), rl); } .......... ............

//创建当前IntentFilter对应的BroadcastFilter

//AMS收到广播后,将根据BroadcastFilter决定是否将广播递交给对应的BroadcastReceiver

//一个BroadcastReceiver可以对应多个IntentFilter

//这些IntentFilter对应的BroadcastFilter共用一个ReceiverList BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); rl.add(bf); ................

mReceiverResolver.addFilter(bf);

// Enqueue broadcasts for all existing stickies that match // this filter.

//allSticky不为空,说明有粘性广播需要发送给刚注册的BroadcastReceiver if (allSticky != null) {

ArrayList receivers = new ArrayList(); //receivers记录bf receivers.add(bf);

final int stickyCount = allSticky.size(); for (int i = 0; i < stickyCount; i++) { Intent intent = allSticky.get(i);

//根据intent的flag (FLAG_RECEIVER_FOREGROUND)决定是使用gBroadcastQueue还是BgBroadcastQueue

BroadcastQueue queue = broadcastQueueForIntent(intent);

//创建广播对应的BroadcastRecord

//BroadcastRecord中包含了Intent,即知道要发送什么广播;

//同时其中含有receivers,内部包含bf,即知道需要将广播发送给哪个BroadcastReceiver

BroadcastRecord r = new BroadcastRecord(queue, intent, null,

null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers, null, 0, null, null, false, true, true, -1);

//加入到BroadcastQueue中,存入的是并发广播对应的队列 queue.enqueueParallelBroadcastLocked(r);

//将发送BROADCAST_INTENT_MSG,触发AMS发送广播 queue.scheduleBroadcastsLocked(); } } } }

至此,AMS中registerReceiver的流程结束。

这个函数看起来很长,但主要工作还是比较清晰的,一共可以分为两个部分:

1、将BroadcastReceiver对应的信息保存到AMS中,同时为当前使用的IntentFilter生成对应的BroadcastFilter。 当AMS发送广播时,将根据广播和BroadcastFilter的匹配情况,决定是否为BroadcastReceiver发送消息。

2、单独对粘性广播进行处理。

由于粘性广播有立即发送的特点,因此当有新的BroadcastReceiver注册到AMS后, AMS需要判断系统中保存的粘性广播中,是否有与该BroadcastReceiver匹配的。

若有与新注册BroadcastReceiver匹配的粘性广播,那么AMS为这些广播构造BroadcastRecord,

并将其加入到发送队列中,同时发送消息触发AMS的广播发送流程。

上述代码的整个过程,还是比较好理解的,唯一麻烦一点的就是涉及到了一些数据结构,需

联系合同范文客服:xxxxx#qq.com(#替换为@)