Android广播机制采用类似于“发布-订阅”者的设计模式,基于Binder机制,实现了一对多的通信。
从整体的角度看,广播的使用主要设计两个“动作” ,“注册广播”和“发送广播”,以及三个“角色”,发送方,接收方和中间人。为什么需要中间人,因为有了中间人的存在,就可以减少发送方和接收方的工作而不用去关心具体的实现细节。三者关系可参考下图:
AMS就是上面提到的中介,也是最重要的角色。Receiver向AMS注册自己感兴趣的广播,AMS则必须将所有必要的信息记录下来,比如Receiver的一些必要信息以及注册的广播的信息,统统都以一定的方式保存起来。当Sender发送广播后,AMS需要根据广播的信息从数据容器中找到注册该广播的Receiver的相关信息。此外AMS还要对很多特殊情况进行处理,和广播是否被及时处理,如果超时会产生anr,这些工作都是由AMS去做的。
一、广播的注册
如上文所说,广播的注册最终是由AMS去完成的,接收方只需要准备好一些必要的信息,如接收者和感兴趣的广播等,并将这些信息提供给AMS,最终由AMS去维护这些信息。
这里列出AMS从Receiver接收到的参数或者说是信息:
IApplicationThread caller | Receiver所在的主线程的ApplicationThread |
String callerPackage | Receiver所在的包名 |
String callerFeatureId | app访问受保护数据的属性标签 |
String receiverId | Receiver的id |
IIntentReceiver receiver | InnerReceiver对象,ReceiverDispatcher的内部类 |
IntentFilter filter | Intent过滤器,用来匹配Intent的values |
String permission | 广播权限 |
int userId | mUser.getIdentifier,ContextImpl持有mUser |
int flags | 用来判断对InstantApp的可见性 |
接下来,看下AMS怎么进行注册的:
这里只关注核心逻辑,很多根据部分参数进行的特殊情况处理在这里不进行分析,粘性广播也不分析。
/*AMS*/
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
synchronized (this) {
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
//rl为空,说明当前调用端(客户端)还没有注册过广播
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
//ReceiverList持有ProcessRecord对象app,app持有ProcessReceiverRecord对象mReceivers,mReceivers内部维护一个
//里边存放着从当前应用注册的所有IIntentReceiver
final int totalReceiversForApp = rl.app.mReceivers.numberOfReceivers();
//当前应用可注册的广播数目超过了阈值,则抛出异常
if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
throw new IllegalStateException("Too many receivers, total of "
+ totalReceiversForApp + ", registered for pid: "
+ rl.pid + ", callerPackage: " + callerPackage);
}
//这个关系链是这样的:ReceiverList ---> ProcessRecord ---> ProcessReceiverRecord ---> ArraySet<Rec
rl.app.mReceivers.addReceiver(rl);
} else {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
//更新mRegisteredReceivers
mRegisteredReceivers.put(receiver.asBinder(), rl);
} else if (...) {
...
//这里省略多个else if
}
...
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
receiverId, 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);
}
这里要关注两个变量,mRegisteredReceivers和mReceiverResolver:
/**
* Keeps track of all IIntentReceivers that have been registered for broadcasts.
* Hash keys are the receiver IBinder, hash value is a ReceiverList.
*/
@GuardedBy("this")
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
可以看出,mRegisterReceivers是AMS持有的一个HashMap,key是IIntentReceiver,value是ReceiverList,ReceiverList继承自ArrayList并封装了一些关于Receiver的属性。
/**
* Resolver for broadcast intents to registered receivers.
* Holds BroadcastFilter (subclass of IntentFilter).
*/
final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
= new IntentResolver<BroadcastFilter, BroadcastFilter>() {
@Override
protected boolean allowFilterResult(
BroadcastFilter filter, List<BroadcastFilter> dest) {
IBinder target = filter.receiverList.receiver.asBinder();
for (int i = dest.size() - 1; i >= 0; i--) {
if (dest.get(i).receiverList.receiver.asBinder() == target) {
return false;
}
}
return true;
}
@Override
protected BroadcastFilter newResult(BroadcastFilter filter, int match, int userId) {
if (userId == UserHandle.USER_ALL || filter.owningUserId == UserHandle.USER_ALL
|| userId == filter.owningUserId) {
return super.newResult(filter, match, userId);
}
return null;
}
@Override
protected IntentFilter getIntentFilter(@NonNull BroadcastFilter input) {
return input;
}
@Override
protected BroadcastFilter[] newArray(int size) {
return new BroadcastFilter[size];
}
@Override
protected boolean isPackageForFilter(String packageName, BroadcastFilter filter) {
return packageName.equals(filter.packageName);
}
};
IntentResolver是一个抽象类,是一个对Intent的解析器,它持有一个ArraySet用来存放filters,mReceiverResolver.addFilter(bf); 就是将bf放到了mReceiverResolver持有的ArraySet中。
二、广播的发送
同样的,广播的发送的重头戏也是在AMS,由于AMS的方法动辄近千行,这里还是把AMS收到的参数都列出来,然后看看AMS要做什么。
下面是sendBroadcast(Intent intent),也就是说普通广播,传给AMS的参数:
IApplicationThread caller | 发送方主线程的ApplicationThread |
String callingFeatureId | app访问受保护数据的属性标签 |
Intent intent | 用于发送广播的intent |
String resolvedType | intent的MIME数据类型(不用太关注) |
IIntentReceiver resultTo | null,IntentReceiver的接口 |
int resultCode | Activity.RESULT_OK(-1) |
String resultData | null |
Bundle resultExtras | null |
String[] requiredPermissions | null |
String[] excludedPermissions | null |
int appOp | AppOpsManager.OP_NONE() |
Bundle bOptions | null,携带的一些数据 |
boolean serialized | fasle,是否是有序广播 |
boolean sticky | false,是否是粘性广播 |
int userId | getUserId() |
下面开始分析AMS的代码,同样的,跳过粘性广播。
...
List<BroadcastFilter> registeredReceivers = null;
...
registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
这里可以注意到mReceiverResolver这个变量,在广播注册时就碰见过。当时是把BroadcastFilter放到了mReceiverResolver持有的ArraySet中,我们现在大胆猜测现在要把BroadcastFilter取出来,看看queryIntent方法验证下!
public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
int userId) {
...
ArrayList<R> finalList = new ArrayList<R>();
...
FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
if (firstTypeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
scheme, firstTypeCut, finalList, userId);
}
if (secondTypeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
scheme, secondTypeCut, finalList, userId);
}
if (thirdTypeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
scheme, thirdTypeCut, finalList, userId);
}
if (schemeCut != null) {
buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
scheme, schemeCut, finalList, userId);
}
filterResults(finalList);
sortResults(finalList);
if (debug) {
Slog.v(TAG, "Final result list:");
for (int i=0; i<finalList.size(); i++) {
Slog.v(TAG, " " + finalList.get(i));
}
}
return finalList;
}
这里根据intent拿到匹配到的BroadcastFilter的List,接下来就开始处理这些BroadcastFilter。
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
// registered receivers separately so they don't wait for the
// components to be launched.
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
}
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, backgroundActivityStartsToken,
timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
// Note: We assume resultTo is null for non-ordered broadcasts.
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
大家自己看吧,这里再看下enqueueParallelBroadcastLocked(r)和scheduleBroadcastsLocked()
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
mParallelBroadcasts.add(r);
enqueueBroadcastHelper(r);
}
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
final BroadcastHandler mHandler;
private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
+ mQueueName + "]");
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
}
private void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
...
// First, deliver any non-serialized broadcasts right away.
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
System.identityHashCode(r));
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
System.identityHashCode(r));
}
final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r,
(BroadcastFilter) target, false, i);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast [" + mQueueName + "] " + r);
}
...
}
到这吧,如果有观众看到这,自己往下看吧。
三、总结
本文试图从源码分析广播的注册和发送的原理,奈何源码实在有点庞大,讲的太细根本不可能。我自己也意识到,可能自己阅读源码的方式有问题。不能为了看源码而去看源码,而应该带着自己的问题去阅读源码,只要阅读之后能回答自己的问题就是值得的,就是有收获的。以后就这么看。