广播接收逻辑
结论
先说结论:动态注册,如果不是有序广播,循环发送完,不等待上一个广播的结果。
静态注册,每次都会重新生成一个receiver的实例,而且会被当成有序广播处理,必须等到上一个处理完成,才会继续下一个。因为静态注册,会涉及到进程创建。
粘性广播发送后,动态注册能收到之前发送的粘性广播,静态注册不能。猜测是因为静态注册如果需要接收,需要创建进程,不合法。
上代码
广播接收的处理逻辑是在发送的部分。入口是在AMS的broadcastIntentLocked这个最终开始的地方。
添加接收者
首先是粘性广播,需要留存。这部分先不看。
如果不是只发送动态注册
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
receivers = collectReceiverComponents(
intent, resolvedType, callingUid, users, broadcastWhitelist);
}
如果没有指定包名:
添加动态接收者。
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, userId);
无序广播
if (!ordered && NR > 0)不是有序广播 &动态接收有
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, 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();
}
这里涉及到replaced,先不关注这个属性,后续文章介绍。
这里就会发送到接受者,下面看怎么发送的。这里注意BroadcastRecord里面***只有动态注册的广播接收者***。
处理完成,会把 registeredReceivers = null;这样就不用处理动态注册的部分了。当然如果是有序广播,就不会,会添加到后续继续操作。
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;
}
}
静态和动态注册,根据优先级合并到列表。静态本身就是优先级排序的。
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, timeoutExempt);
//中间还有replace的操作
queue.enqueueOrderedBroadcastLocked(r);//跟上面的差距
queue.scheduleBroadcastsLocked();
处理广播 —BroadcastQueue
scheduleBroadcastsLocked发送一个handler的消息,然后processNextBroadcastLocked处理发送逻辑。不管有序还是无序,最后都是这里。
先处理无序的动态注册。
while (mParallelBroadcasts.size() > 0) {
....
deliverToRegisteredReceiverLocked//处理
.....
}
deliverToRegisteredReceiverLocked
performReceiveLocked
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
最后回到ActivityThread里面的ApplicationThread #scheduleRegisteredReceiver
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);
}
IIntentReceiver就是我们注册时候传入的。LoadedApk#ReceiverDispatcher#InnerReceiver.然后再转换到ReceiverDispatcher里面的performReceive方法。最后执行
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
}
if (receiver.getPendingResult() != null) {
finish(); }
注意这里,这里没有创建新的receiver。
注意上面的finish方法,有序和无序都会有这个部分。
public void sendFinished(IActivityManager am) {
synchronized (this) {
if (mFinished) {
throw new IllegalStateException("Broadcast already finished");
}
mFinished = true;
try {
if (mResultExtras != null) {
mResultExtras.setAllowFds(false);
}
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast, mFlags);
} else {
// This broadcast was sent to a component; it is not ordered,
// but we still need to tell the activity manager we are done.
am.finishReceiver(mToken, 0, null, null, false, mFlags);
}
} catch (RemoteException ex) {
}
}
}
注意看原版注释,不管是否有序,都会给ams发送一个结束消息,告诉ams完成。有序广播的下一个就是这里开始的。ams对应的实现这里不贴代码。
动态无序广播到此为止。
注意是动态无序。静态无序,上面已经描述了,系统会把它当成有序广播处理。
中间有处理时钟的部分,似乎还有有序广播的部分,应该是慢或者异常卡住的部分。不看,继续。
动态有序不描述,基本与上面一直,只不过需要等到结果。
下面主要看静态注册。
if (nextReceiver instanceof BroadcastFilter) {//这种就是动态注册
}
ResolveInfo info =
(ResolveInfo)nextReceiver;//这种就是静态注册
静态注册分两种:
1.进程存在
if (app != null && app.thread != null && !app.killed) {
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
maybeAddAllowBackgroundActivityStartsToken(app, r);
processCurBroadcastLocked(r, app, skipOomAdj);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when sending broadcast to "
+ r.curComponent, e);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Failed sending broadcast to "
+ r.curComponent + " with " + r.intent, e);
// If some unexpected exception happened, just skip
// this broadcast. At this point we are not in the call
// from a client, so throwing an exception out from here
// will crash the entire system instead of just whoever
// sent the broadcast.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
r.state = BroadcastRecord.IDLE;
return;
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
processCurBroadcastLocked就是把广播发射出去。
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.getReportedProcState());
执行最后还是到ActivityThread#ApplicationThread-》scheduleReceiver
注意与上面的不同。
2.进程不存在
if ((r.curApp=mService.startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
new HostingRecord("broadcast", r.curComponent),
isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
== null) {
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
Slog.w(TAG, "Unable to launch app "
+ info.activityInfo.applicationInfo.packageName + "/"
+ receiverUid + " for broadcast "
+ r.intent + ": process is bad");
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
进程不存在要创建进程,创建失败当作已完成,继续处理下一个。
创建进程传入的一个重要参数:new HostingRecord(“broadcast”, r.curComponent)这个就是表明,进程创建以后需要做什么的。在ams获取进程创建成功以后操作。后续系列操作也是跟进程已存在是一样的。
我们现在去看:ActivityThread#ApplicationThread-》scheduleReceiver
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
updateProcessState(processState, false);
ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
sync, false, mAppThread.asBinder(), sendingUser);
r.info = info;
r.compatInfo = compatInfo;
sendMessage(H.RECEIVER, r);
}
继续往下
private void handleReceiver(ReceiverData data) {
try {
app = packageInfo.makeApplication(false, mInstrumentation);
context = (ContextImpl) app.getBaseContext();
if (data.info.splitName != null) {
context = (ContextImpl) context.createContextForSplit(data.info.splitName);
}
java.lang.ClassLoader cl = context.getClassLoader();
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess();
data.setExtrasClassLoader(cl);
receiver = packageInfo.getAppFactory()
.instantiateReceiver(cl, data.info.name, data.intent);//创建实例
}
try {
if (localLOGV) Slog.v(
TAG, "Performing receive of " + data.intent
+ ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + packageInfo.getPackageName()
+ ", comp=" + data.intent.getComponent().toShortString()
+ ", dir=" + packageInfo.getAppDir());
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
receiver.onReceive(context.getReceiverRestrictedContext(),
data.intent);//广播接收
}
if (receiver.getPendingResult() != null) {
data.finish()//发送结束。
}
以上,完毕。