Android广播机制

framework

Posted by Cc1over on January 19, 2019

Android广播机制

广播机制对于我们Android开发者来说并不陌生,最近笔者听身边的小伙伴讲了一下EventBus的实现原理,发现原来EventBus的内部是基于反射实现的,所以对于Android原生的广播机制充满了兴趣,本文笔者将记录笔者学习广播机制的学习过程

上一篇Android中的Context也讲述了Android中四大组件的关系,所以本文将以ContextWrapper的registerReceiver()为入口,开始解析整个广播机制

广播注册流程

[-> ContextWrapper.registerReceiver]
public class ContextWrapper extends Context {
   @Override
	public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
		return mBase.registerReceiver(receiver, filter);
	}
}    
[-> ContextImp.registerReceiver]
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    return registerReceiver(receiver, filter, null, null);
}

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext());
}

参数解析:

  • broadcastPermission:广播的权限控制
  • scheduler:指定接收到广播时onRecive执行线程,当scheduler=null则默认代表在主线程中执行
[-> ContextImp.registerReceiverInternal]
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) {
    IIntentReceiver rd = null;
    if (receiver != null) {
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                //将主线程Handler赋予scheuler
                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, userId);
    } catch (RemoteException e) {
        return null;
    }
}

和之前解析过的startService启动过程很相似,这里通过ActivityManagerNative拿到的是ActivityManagerProxy对象,然后也是也是老套路了,传一个ApplicationThread过去,然后构成system_service进程与用户进程的相互通信

[-> ActivityManagerProxy.registerReceiver]
public Intent registerReceiver(IApplicationThread caller, String packageName, IIntentReceiver receiver, IntentFilter filter, String perm, int userId) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeString(packageName);
    data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
    filter.writeToParcel(data, 0);
    data.writeString(perm);
    data.writeInt(userId);

    //Command为REGISTER_RECEIVER_TRANSACTION
    mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
    reply.readException();
    Intent intent = null;
    int haveIntent = reply.readInt();
    if (haveIntent != 0) {
        intent = Intent.CREATOR.createFromParcel(reply);
    }
    reply.recycle();
    data.recycle();
    return intent;
}

这里和startService那个过程稍微有点不一样,它除了ApplicationThread之外还多传了一个receiver的Binder对象,所以我们现在回头留意一下这个receiver的构建过程,看看它到时是什么,然后等等进入AMS那边之后再重点关注

返回[-> ContextImp.registerReceiverInternal]
rd = new LoadedApk.ReceiverDispatcher(
                  receiver, context, scheduler, null, true).getIIntentReceiver();

LoadedApk的创建过程其实是在ContextImp中的中,而LoadedApk其实就是.apk在内存中的数据结构

[-> LoadedApk.ReceiverDispatcher.getIIntentReceiver]
  IIntentReceiver getIIntentReceiver() {
         return mIIntentReceiver;
  }
[-> ReceiverDispatcher]
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
        Handler activityThread, Instrumentation instrumentation,
        boolean registered) {
    mIIntentReceiver = new InnerReceiver(this, !registered);
    mReceiver = receiver;
    mContext = context;
    mActivityThread = activityThread;
    mInstrumentation = instrumentation;
    mRegistered = registered;
    mLocation = new IntentReceiverLeaked(null);
    mLocation.fillInStackTrace();
}
[->new InnerReceiver]
final static class InnerReceiver extends IIntentReceiver.Stub {
    final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
    final LoadedApk.ReceiverDispatcher mStrongRef;

    InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
        mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
        mStrongRef = strong ? rd : null;
    }
    ...
}

ReceiverDispatcher有一个内部类InnerReceiver,这个类继承自IIntentReceiver.Stub,这是一个Binder服务端,而这里显然是用于通信,而关于它和ApplicationThread之间有什么作用上的区别,这里暂时看不出来,我们把悬念留到后面,然后进入system_service端

[-> ActivityManagerService.registerReceiver]
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
    ArrayList<Intent> stickyIntents = null;
    ProcessRecord callerApp = null;
    ...
    synchronized(this) {
        if (caller != null) {
            callerApp = getRecordForAppLocked(caller);
            ...
            callingUid = callerApp.info.uid;
            callingPid = callerApp.pid;
        } else {
            callerPackage = null;
            callingUid = Binder.getCallingUid();
            callingPid = Binder.getCallingPid();
        }

        userId = handleIncomingUser(callingPid, callingUid, userId,
                true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

        //获取IntentFilter中的actions. 这就是平时所加需要监听的广播action
        Iterator<String> actions = filter.actionsIterator();
        if (actions == null) {
            ArrayList<String> noAction = new ArrayList<String>(1);
            noAction.add(null);
            actions = noAction.iterator();
        }

        int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
        while (actions.hasNext()) {
            String action = actions.next();
            for (int id : userIds) {
                //从mStickyBroadcasts中查看用户的sticky Intent
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                if (stickies != null) {
                    ArrayList<Intent> intents = stickies.get(action);
                    if (intents != null) {
                        if (stickyIntents == null) {
                            stickyIntents = new ArrayList<Intent>();
                        }
                        //将sticky Intent加入到队列
                        stickyIntents.addAll(intents);
                    }
                }
            }
        }
    }
    ArrayList<Intent> allSticky = null;
    if (stickyIntents != null) {
        final ContentResolver resolver = mContext.getContentResolver();
        for (int i = 0, N = stickyIntents.size(); i < N; i++) {
            Intent intent = stickyIntents.get(i);
            if (filter.match(resolver, intent, true, TAG) >= 0) {
                if (allSticky == null) {
                    allSticky = new ArrayList<Intent>();
                }
                //匹配成功,则将给intent添加到allSticky队列
                allSticky.add(intent);
            }
        }
    }

    //当IIntentReceiver为空,则直接返回第一个sticky Intent,
    Intent sticky = allSticky != null ? allSticky.get(0) : null;
    if (receiver == null) {
        return sticky;
    }

    synchronized (this) {
        if (callerApp != null && (callerApp.thread == null
                || callerApp.thread.asBinder() != caller.asBinder())) {
            return null; //调用者已经死亡
        }
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
            //对于没有注册的广播,则创建接收者队列
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            if (rl.app != null) {
                rl.app.receivers.add(rl);
            } else {
                receiver.asBinder().linkToDeath(rl, 0); //注册死亡通知
                ...
                rl.linkedToDeath = true;
            }
            //新创建的接收者队列,添加到已注册广播队列。
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        }
        ...
        //创建BroadcastFilter对象,并添加到接收者队列
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId);
        rl.add(bf);
        //新创建的广播过滤者,添加到ReceiverResolver队列
        mReceiverResolver.addFilter(bf);

        //所有匹配该filter的sticky广播执行入队操作
        //如果没有使用sendStickyBroadcast,则allSticky=null。
        if (allSticky != null) {
            ArrayList receivers = new ArrayList();
            receivers.add(bf);

            final int stickyCount = allSticky.size();
            for (int i = 0; i < stickyCount; i++) {
                Intent intent = allSticky.get(i);
                BroadcastQueue queue = broadcastQueueForIntent(intent);
                //创建BroadcastRecord
                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);
                //该广播加入到并行广播队列
                queue.enqueueParallelBroadcastLocked(r);
                //调度广播,发送BROADCAST_INTENT_MSG消息,触发处理下一个广播。
                queue.scheduleBroadcastsLocked();
            }
        }
        return sticky;
    }
}

在解析这个方法前,这个方法有点长,但是没有关系,我们一步一步去分析:

  • 获取调用程序的进程信息ProcessRecord及PID和Uid,这里的ProcessRecord就是AMS中用来描述应用进程的数据结构
  • 查询所有的Action相关的粘性广播,保存到allSticky列表中,该Action就是即将要注册的广播的Action,而这里所谓的粘性广播其实也和EventBus如出一辙,都是在注册的时候把保存起来的粘性广播发送出去(ps:下面会有这部分逻辑的分析)
  • 然后往下看到ReceiverList,mRegisteredReceivers这里,mRegisteredReceivers就很好理解了,就是字面上的意思,保存了注册接受者的Map,而mRegisteredReceivers是以receiver.asBinder为key,ReceiverList为value的Map,其实这里的ReceiverList就是一个ArrayList的子类,而且它除了添加的成员像PID,UID之外并没覆盖过多的逻辑,但是笔者觉得这样的小细节很值得我们学习,因为平时我们写项目的时候都是List满天飞然后把这些信息可能就耦合在bean类中了,而像这样封一层,其实笔者觉得挺不错的
  • 而从下面的逻辑上也可以看得到其实ReceiverList中存的BroadcastFilter,而用一个列表来存的目的也是因为一个Broadcast可以对应多个不同的Filter,除此之外,这个BroadcastFilter还在被缓存在AMS中的ReceiverResolver队列中
  • 这里可以看到通过broadcastQueueForIntent获得一个BroadcastQueue,这个方法其实就是判断Intent中的lag,区分前台还是后台,在AMS中前台和后台的两个队列,广播默认都是后台优先级,如果广播中添加了这个标签就会以前台优先级运行,发送到接收到广播的时间间隔会更短,这里就是获取一个队列而已,这个BroadcastQueue其实它里面是通过ArrayList实现的队列,和上面第三点讲到的容器封装思想如出一辙,它通过维护两个ArrayList去区分广播的并行和有序
    • mParallelBroadcasts:并行广播队列,可以立刻执行,而无需等待另一个广播运行完成,该队列只允许动态已注册的广播,从而避免发生同时拉起大量进程来执行广播,前台的和后台的广播分别位于独立的队列
    • mOrderedBroadcasts:有序广播队列,同一时间只允许执行一个广播,该队列顶部的广播便是活动广播,其他广播必须等待该广播结束才能运行,也是独立区别前台的和后台的广播
  • 然后就是创建一个BroadcastRecord对象,将该对象入队,然后通过Handler发送一个消息调度广播,触发处理下一个广播,而关于BroadcasetRecord的结构这里我们大致列举一下
final class BroadcastRecord extends Binder {
    final ProcessRecord callerApp; //广播发送者所在进程
    final String callerPackage; //广播发送者所在包名
    final List receivers;   // 包括动态注册的BroadcastFilter和静态注册的ResolveInfo

    final String callerPackage; //广播发送者
    final int callingPid;   // 广播发送者pid
    final List receivers;   // 广播接收者
    int nextReceiver;  // 下一个被执行的接收者
    IBinder receiver; // 当前正在处理的接收者
    int anrCount;   //广播ANR次数

    long enqueueClockTime;  //入队列时间
    long dispatchTime;      //分发时间
    long dispatchClockTime; //分发时间
    long receiverTime;      //接收时间(首次等于dispatchClockTime)
    long finishTime;        //广播完成时间
}
小结

梳理上面的方法流程:

  • 注册广播传递的参数为广播接收者BroadcastReceiver和Intent过滤条件IntentFilter
  • 创建对象LoadedApk.ReceiverDispatcher.InnerReceiver,该对象继承于IIntentReceiver.Stub
  • 通过AMS把当前进程的ApplicationThread和InnerReceiver对象的代理类,注册登记到system_server进程
  • 当广播receiver没有注册过,则创建广播接收者队列ReceiverList,该对象继承于ArrayList, 并添加到AMS.mRegisteredReceivers(已注册广播队列)
  • 创建BroadcastFilter,并添加到AMS.mReceiverResolver
  • 将BroadcastFilter添加到该广播接收者的ReceiverList

梳理上面的陌生的类之间的关系:

发送广播

发送广播的流程我们以ContextImp的sendBroadcast方法为如口,每次先看wrapper都是mBase.XXX,太没意思了,所以从ContextImp开始:

[-> ContextImp.sendBroadcast]
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess();
        ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        ...
    }
}

老规矩了,直接到ActivityManagerProxy,这里没啥好说的了

[-> ActivityManagerProxy.broadcastIntent]
public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String[] requiredPermissions, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    intent.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);
    data.writeInt(resultCode);
    data.writeString(resultData);
    data.writeBundle(map);
    data.writeStringArray(requiredPermissions);
    data.writeInt(appOp);
    data.writeBundle(options);
    data.writeInt(serialized ? 1 : 0);
    data.writeInt(sticky ? 1 : 0);
    data.writeInt(userId);

    //Command为BROADCAST_INTENT_TRANSACTION
    mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
    reply.readException();
    int res = reply.readInt();
    reply.recycle();
    data.recycle();
    return res;
}

写入参数然后IPC过程,这里都是些熟悉的参数了,然后我们就到system_service端的ActivityManagerService啦

[-> ActivityManagerService.broadcastIntent]
public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) {
    enforceNotIsolatedCaller("broadcastIntent");
    synchronized(this) {
        //验证广播intent是否有效
        intent = verifyBroadcastLocked(intent);
        //获取调用者进程记录对象
        final ProcessRecord callerApp = getRecordForAppLocked(caller);
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        int res = broadcastIntentLocked(callerApp,
                callerApp != null ? callerApp.info.packageName : null,
                intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                requiredPermissions, appOp, null, serialized, sticky,
                callingPid, callingUid, userId);
        Binder.restoreCallingIdentity(origId);
        return res;
    }
}

broadcastIntent()方法有两个布尔参数serialized和sticky来共同决定是普通广播,有序广播,还是Sticky广播,参数如下:

类型 serialized sticky
sendBroadcast false false
sendOrderedBroadcast true false
sendStickyBroadcast false true
[-> ActivityManagerService.broadcastIntentLocked]

由于这个方法比较长,笔者就不再贴过多的源码,主要是梳理流程,总结源码中一些细致的点,以及关键关注一下,AMS给制定进程发送广播的源码分析:

  • 设置广播flag

    • 对广播增加一个flag,保证已停止app不会收到该广播
    • 当没有启动完成时,不允许启动新进程
    • 检查发送广播时用户状态,如果用户状态不处于Running状态的话,只能发送系统升级广播或关机广播
  • 广播权限验证

    • 对于某些只允许系统使用的广播,抛出异常
    • 限定某些涉及安全性的广播只能发给自己
  • 处理系统广播

    • 非系统广播略过
  • 增加sticky广播
    • 这个过程主要是将sticky广播增加到list,并放入mStickyBroadcasts里面,这样在接受者注册的时候就可以从容器中找到相应的粘性广播并发送
  • 查询和intent相关的广播接受者
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// 如果没有FLAG_RECEIVER_REGISTERED_ONLY标签,说明不是发送给动态注册的广播的,那么调用collectReceiverComponents,查找所有和该Intent相关的广播接收者
// 保存到receivers列表中
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
    if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
        ...
    } else {
        // 查询相应的动态注册的广播
        registeredReceivers = mReceiverResolver.queryIntent(intent,
                resolvedType, false, userId);
    }
}

这个过程的逻辑就是查找和intent相关的广播接收者,而在广播注册的方式又分为静态注册和动态注册,由于静态注册这种方式是在Manifest.xml中注册,这部分注册的广播就会通过上面collectReceiverComponents方法去查询并用receivers这个列表保存起来,而collectReceiverComponents这个方法的内部实现仅仅是去PMS服务中查询了感兴趣的静态注册的广播接收者,而动态注册的广播就保存在registeredReceivers这个列表中

  • 处理并行广播
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            //如果当前不是有序广播,且动态注册的感兴趣的广播不为0,将广播intent封装为一个BroadcastRecord
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
                    appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
                    resultExtras, ordered, sticky, false, userId);
           ……
            //发送该广播给动态注册的广播接收者
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
            //发送完成后,将registeredReceivers 置为 null
            registeredReceivers = null;
            NR = 0;
        }

上面的部分代码很眼熟,和广播注册的时候发送粘性广播流程相似,但是这里是单独处理并行切动态注册的广播,为什么这里不连同静态注册的广播一起处理呢?其实原因就是因为而静态注册的广播接收者只是在Manifest文件中注册,要想接收广播必须要等待要接收的组件启动起来才可,所以这边处理选择分开发送,优先发送动态注册的广播接收者,所以动态注册的广播优先级比静态注册的广播要高

  • 处理有序广播
int NT = receivers != null ? receivers.size() : 0;
            int it = 0;
            ResolveInfo curt = null;
            BroadcastFilter curr = null;
            //上面的无序广播处理后,把mRegisterReceivers列表置为null,并且把NR设置成了0
            //而此时要想满足此处条件,NR不为0,说明此处是有序广播的处理逻辑
            //遍历动态注册的广播和静态注册的广播,安priority值排序合并放到receivers列表中
            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;
                }
            }
        ……
        //有序广播接收者不为空,发送有序广播
        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, resolvedType,
                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                    resultData, resultExtras, ordered, sticky, false, userId);
 
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                    + ": prev had " + queue.mOrderedBroadcasts.size());
            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                    "Enqueueing broadcast " + r.intent.getAction());
 
            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
            if (!replaced) {
                queue.enqueueOrderedBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }

在先前处理动态广播的过程中,就把动态注册的广播处理掉了,所以在有序广播的时候就不会有动态注册的广播接收者合并进来,而这个时候就会把静态注册的广播放到mOrderedBroadcasts中发送,而为什么静态广播要当成有序广播来发送原因就是因为态注册的广播接收者的进程不一定已经运行起来了,在发送的过程中可能需要先启动进程,这样很消耗资源,所以一个一个发送会好一点

  • 至此,这个这么长的方法broadcastIntentLocked()的执行流程就已经分析完了,而其实粘性广播也好,并行广播也好,有序广播也好,最终它们都是添加进队列中,由队列去统一处理,而总结下的处理流程主要为以下几点:
    • 根据广播的Intent找到对应的广播队列
    • 将Intent和广播接收者封装成一个BroadcastRecord对象
    • 将BroadcastRecord对象添加拿到queue队列中
    • 调用queue的scheduleBroadcastsLocked方法发送广播
[BroadcastQueue.scheduleBroadcastsLocked]
public void scheduleBroadcastsLocked() {
    // 正在处理BROADCAST_INTENT_MSG消息
    if (mBroadcastsScheduled) {
        return;
    }
    //发送BROADCAST_INTENT_MSG消息
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}
[-> mHandler.handleMessage]
private final class BroadcastHandler extends Handler {

    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BROADCAST_INTENT_MSG: {
                processNextBroadcast(true); 
            } break;
            ...
    }
}
[->BroadcastQueue.processNextBroadcast]

上面的处理逻辑也是分并行广播和有序广播处理,所以在BroadcastQueue对广播的处理在这里也区分为有序广播处理与并行广播处理,以这种方式来细分逻辑:

  • 并行广播的处理
BroadcastRecord r;
//更新CPU统计信息
mService.updateCpuStats(); 
if (fromMsg)  mBroadcastsScheduled = false;

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);
        //分发广播给已注册的receiver 
        deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
    }
    //将广播添加历史统计
    addBroadcastToHistoryLocked(r);
}

其实在处理并行广播的这个流程并不复杂,其实就是去遍历前面提到的这个mParallelBroadcasts列表,从列表开始位置一次拿到保存的BroadcastRecord对象,每个BroadcastRecord中可能对应多个广播接收者,依次遍历广播接收者,然后调用deliverToRegisteredReceiverLocked方法发送广播

  • 有序广播的处理

有序广播的处理这块就没有上面的并行广播处理那么简单了,这里的主要流程是:

1.设置广播超时时间

2.获取下一个接受者

3.这里会根据广播接受者的类型以及进程的状态去走不相同的逻辑,主要分为以下三种情况:

如果是动态广播接收者,则调用deliverToRegisteredReceiverLocked处理

if (nextReceiver instanceof BroadcastFilter) {
    //对于动态注册的广播接收者,deliverToRegisteredReceiverLocked处理广播
    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
    deliverToRegisteredReceiverLocked(r, filter, r.ordered);
    if (r.receiver == null || !r.ordered) {
        r.state = BroadcastRecord.IDLE;
        scheduleBroadcastsLocked();
    } else {
        ...
    }
    return;
}

如果是静态广播接收者,且对应进程已经创建,则调用processCurBroadcastLocked处理

ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
        info.activityInfo.applicationInfo.uid, false);
if (app != null && app.thread != null) {
    try {
        app.addPackage(info.activityInfo.packageName,
                info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
        processCurBroadcastLocked(r, app);
        return;
    } catch (RemoteException e) {
    } catch (RuntimeException e) {
        finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false);
        scheduleBroadcastsLocked();
        r.state = BroadcastRecord.IDLE; //启动receiver失败则重置状态
        return;
    }
}

如果是静态广播接收者,且对应进程尚未创建,则调用startProcessLocked创建进程

if ((r.curApp=mService.startProcessLocked(targetProcess,
        info.activityInfo.applicationInfo, true,
        r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
        "broadcast", r.curComponent,
        (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                == null) {
    //创建失败,则结束该receiver
    finishReceiverLocked(r, r.resultCode, r.resultData,
            r.resultExtras, r.resultAbort, false);
    scheduleBroadcastsLocked();
    r.state = BroadcastRecord.IDLE;
    return;
}

上面这三种情况都根据不同的情况去调用了不同的方法,先来总结一下:

  • 如果是动态广播接收者,则调用deliverToRegisteredReceiverLocked处理
  • 如果是静态广播接收者,且对应进程已经创建,则调用processCurBroadcastLocked处理
  • 如果是静态广播接收者,且对应进程尚未创建,则调用startProcessLocked创建进程

虽然貌似调用了三个不同的方法,但最后都会调用performReceiveLocked或者 applicationThread.scheduleRegisteredReceiver方法,这里就不贴代码出来啦呀,而performReceiveLocked其实也只是调用applicationThread.scheduleRegisteredReceiver方法,说白了就是一个IPC的过程,但是笔者关注到了一个细节,performReceiveLocked这个方法里多了一点处理,分析前我们先看看源码

private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        if (app != null) {
            if (app.thread != null) {
                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser, app.repProcState);
            }
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }

我们之前在注册广播的时候会传进来两个Binder,一个是ApplicationThread一个是Receiver,而在AMS与注册端通信的时候,在performReceiveLocked就判断ProcessRecord这个对象是否为空,为空就以receiver这个Binder实现IPC过程,不为空就直接用ApplicationThread进行进程通信,而关于这个ProcessRecord对象其实是广播注册的时候就已经初始化出来,而且ProcessRecord其实是AMS用来描述进程的数据结构,而在这里看到了receiver调用了performReceiver方法,其实呢,用ApplicationThread进行IPC回到接收者进程后,也会调用receiver的performReceiver方法

[-> ApplicationThreadProxy.scheduleRegisteredReceiver]
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky, int sendingUser, int processState) throws RemoteException {
    Parcel data = Parcel.obtain();
    data.writeInterfaceToken(IApplicationThread.descriptor);
    data.writeStrongBinder(receiver.asBinder());
    intent.writeToParcel(data, 0);
    data.writeInt(resultCode);
    data.writeString(dataStr);
    data.writeBundle(extras);
    data.writeInt(ordered ? 1 : 0);
    data.writeInt(sticky ? 1 : 0);
    data.writeInt(sendingUser);
    data.writeInt(processState);

    //command=SCHEDULE_REGISTERED_RECEIVER_TRANSACTION
    mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,
            IBinder.FLAG_ONEWAY);
    data.recycle();
}

其实这个方法就是一个简单的IPC调用,接下来的流程我们就要脱离AMS回到接收端了

public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky, int sendingUser, int processState) throws RemoteException {
    updateProcessState(processState, false);
    receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
            sticky, sendingUser);
}

和我们上面说的一样,就是回到了接收端进程后再次调用receiver的performReceive方法,我们最后的谜团就在这个方法里面了

[-> InnerReceiver.performReceive]
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
    if (rd != null) {
        rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser);
    } else {
       ...
    }
}

这个的逻辑就比较简单了,就是调用拿到相应的ReceiverDispatcher这个类,其实和刚刚好是注册的时候构建的顺序倒转,然后调用ReceiverDispatcher的performReceive方法

[-> ReceiverDispatcher. performReceive]
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    Args args = new Args(intent, resultCode, data, extras, ordered,
            sticky, sendingUser);
    //通过handler消息机制发送args.
    if (!mActivityThread.post(args)) {
        //消息成功post到主线程,则不会走此处。
        if (mRegistered && ordered) {
            IActivityManager mgr = ActivityManagerNative.getDefault();
            args.sendFinished(mgr);
        }
    }
}

Args是继承自BroadcastReceiver.PendingResult,实现了接口Runnable接口,这里其实就是把args对象post到MessageQueue中然后执行run方法

public final class LoadedApk {
  static final class ReceiverDispatcher {
    final class Args extends BroadcastReceiver.PendingResult implements Runnable {
        public void run() {
              ...
            try {
                //获取mReceiver的类加载器
                ClassLoader cl =  mReceiver.getClass().getClassLoader();
                intent.setExtrasClassLoader(cl);
                setExtrasClassLoader(cl);
                receiver.setPendingResult(this);
                //回调广播onReceive方法
                receiver.onReceive(mContext, intent);
            } catch (Exception e) {
                ...
            }
        }
    }

至此,整个广播发送的流程就到这里结束了

总结

由于笔者是一个Android的应用开发者,对于Android底层的一些细节没有太多深入,只是重点关注它的流程,但是其实结合上一篇startService分析笔者觉得其实大体的流程有相似,只是广播这里的处理多了一些队列以及一些调度的过程,整个IPC的过程其实大同小异,而IPC过程不一样的我觉得就是广播机制除了进程通信的ApplicationThread之外还需要多一个Binder那就是receiver,这个Binder主要是用来做缓存key以及在ApplicationThread不在的时候预留的IPC方式,这可能就是笔者觉得IPC过程中稍微有点不一样的地方

感谢以下作者的努力:

  • http://gityuan.com/2016/06/04/broadcast-receiver/
  • https://www.jianshu.com/p/dd04e6d97de0?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation