之前和同事讨论动态广播和静态广播差异性问题时,发现自己对广播的内部机制毫无了解(知识空白区 T/\T)
所以,要翻开代码看看里面到底啥子来头。
首先,先整理一波动态注册的鸟瞰图
从图中可以看到
1)代码中调用的egisterReceiver(BroadcastReceiver, IntentFilter),在ContextImpl.java中实现(关于Context和Activity的关联,可以翻看我的前一篇博文),实际真正是ActivityManagerService去注册广播。
2)再通过跨进程通讯(这里采用的是binder),来获取用注册广播的服务,该服务的实现类在ActivityServiceManager.java。
接下来就开始真正上源码噜~
在ContextImpl.java
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler, int flags) {
//从这里调进去
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext(), flags);
}
调用了ContextImpl .egisterReceiverInternal()
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
//mMainThread是ActivityThread的实例,获取Handler
}
//mPackageInfo是该context对象与当前进程关联的LoadedApk的实例
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//假如mPackageInfo或context为空,则直接新建ReceiverDispatcher对象
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
// 从这里调用AMS的registerReceiver方法
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
...
}
接下来看看Ams的registerReceiver方法:
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
...
synchronized(this) {
...
callerApp = getRecordForAppLocked(caller);//请求者的Activity所在的应用进程
...
//迭代IntentFilter获得此次注册的action列表
Iterator actions = filter.actionsIterator();
//此次注册没有action
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) };
//根据actions和userIds获得所有粘性广播的intent
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
ArrayMap> stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
ArrayList intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList();
}
//stickyIntent中加入所有粘性广播
stickyIntents.addAll(intents);
}
}
}
}
ArrayList allSticky = null;
if (stickyIntents != null) {
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);
// Don't provided intents that aren't available to instant apps.
if (instantApp &&
(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
continue;
}
// If intent has scheme "content", it will need to acccess
// provider that needs to lock mProviderMap in ActivityThread
// and also it may need to wait application response, so we
// cannot lock ActivityManagerService here.
// 匹配此次注册的广播中是否有粘性广播
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList();
}
//此次注册的广播里有粘性广播,加入到allSticky队列里
allSticky.add(intent);
}
}
}
...
//获取 接收者队列 ReceiverList
//mRegisteredReceivers是个map集合,可以根据IIntentReceiverd的IBinder来取出对应的ReveiverList
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
//如果rl为空则新建,用来存储广播接收者
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
...
//新创建的接收者队列,添加到已注册广播队列。
mRegisteredReceivers.put(receiver.asBinder(), rl);
...
//BroadcastFilter描述注册的广播接收者
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
//假如已存在于接收者队列中,则提示且不再重复加入
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
+ ", callerPackage is " + callerPackage);
} else {
rl.add(bf);//加入列表中
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);
//BroadcastFilter加入到ReceiverResolver,
//ams收到广播时,可以在mReceiverResolver在ReceiverList找到对应的接收者
}
//所有匹配该filter的sticky广播执行入队操作
//如果没有使用sendStickyBroadcast,则allSticky=null。
// Enqueue broadcasts for all existing stickies that match
// this filter.
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);
//根据intent返回前台或后台广播队列
BroadcastQueue queue = broadcastQueueForIntent(intent);
//创建BroadcastRecord
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, false, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
//该广播加入到并行广播队列
queue.enqueueParallelBroadcastLocked(r);
//调度广播,发送BROADCAST_INTENT_MSG消息,触发处理下一个广播。
queue.scheduleBroadcastsLocked();
}
}
...
}
...
}
在AMS的registerReceiver方法里可以对动态广播注册有个基本的了解,再来用文字理清晰一下,
1)把注册的粘性广播存放在allSticky队列中,
2)新建或获取此次注册广播进程的接收者队列对象rl(ReceiverList)
3)rl加入在AMS维护的mRegisteredReceivers队列中(RegisteredReceivers存放所有进程的广播接收者和对应进程信息)。
4) 新建一个BroadcastFilter对象bf描述注册的广播接收者(里面存有目的intentFilter,目的关联的接收者队列rl,注册广播的进程信息,监听广播所需要的权限等)。
5)判断rl内是否已经已经有加入过和这个bf包含的intentFilter(为了防止重复注册广播),若无,则将bf加入rl队列(ReceiverList)和 加入mReceiverResolver队列。
6)对于粘性广播,先根据intent的标识判断是前台广播还是后台广播,找到要加入的前台或后台广播队列
7)然后为注册的粘性广播新建一个BroadcastRecord(内存放该广播的前后台队列和intent)
8) 把注册的粘性广播加入并行广播队列
9)调度粘性广播,发送BROADCAST_INTENT_MSG消息,触发处理下一个广播。
至此广播的注册告一段落,接下来开始介绍广播的发送和接收~~~~
先以无序广播作为分析的案例进行走读
看看代码的主要时序图: