上一篇文章我们主要梳理了广播的动态注册,发送,接收,主要的数据结构以及需要大家严重注意的几点内容,相信大家已经熟悉了。没看过的朋友传送门:BroadcastReceiver详细分析之主要流程
相信聪明的朋友已经发现,上篇基本没怎么介绍串行广播和静态注册器,基本介绍的是普通广播的动态注册器的流程。因此,本篇单独讲解串行广播以及静态注册器的相关调度以及超时机制,毕竟这块知识点还是很多的,值得单开一篇文章。
本篇代码仍然基于原生Android Q
一.有序广播的基本使用
BroadcastReceiver的注册、发送和接收的主要流程和核心数据结构都已经讲解完。本篇主要讲述有序广播的调度和超时,无序广播都是并行发送的,不存在优先级和回调机制,因此也不会存在超时机制。这个好理解吧?还是再提一下吧,无序广播的动态注册器接收在上篇中都是循环直接发送的,属于binder的one way调用,AMS不需要等待它们执行结果。而有序广播需要根据接收器的优先级一个个发送,优先级高的接收器可以拦截广播等等,既然有先来后到,那么咱就只能一个个发了,并且前面的接收器要是处理时间太长怎么办?这不是影响后面的接收器了嘛,因此肯定会有超时机制。OK,废话不多说,我们开始:
下面是有序广播的基本使用方法:
//定义广播
BroadcastReceiver receiver=new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(MainActivity.this,"这是xiaomiapp2",Toast.LENGTH_LONG).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter=new IntentFilter("a.b.c");
registerReceiver(receiver,intentFilter); //注册广播
......
Intent intent=new Intent(); //发送广播
intent.setAction("a.b.c");
sendOrderedBroadcast(intent,null);
平平无奇的代码,不需要过多说。
二.串行广播的调度过程
根据之前介绍,串行广播是将动态注册和静态注册的接收器根据优先级合并在一起,然后统一调度。无序广播都是one way binder call,因此发完就发完了,不存在通知AMS,而有序广播发完是需要通知AMS的,因此需要一个一个的来,让我们回到BroadcastQueue的processNextBroadcastLocked方法:
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
//......无序动态广播的处理,不再赘述
// Now take care of the next serialized one...
boolean looped = false;
do {
final long now = SystemClock.uptimeMillis();
//取出有序广播一个BroadcastRecord任务
r = mDispatcher.getNextBroadcastLocked(now);
if (r == null) { //没有更多任务了
// No more broadcasts are deliverable right now, so all done!
mDispatcher.scheduleDeferralCheckLocked(false);
mService.scheduleAppGcsLocked();
if (looped) {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
// adjustments.
mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
}
// when we have no more ordered broadcast on this queue, stop logging
if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {
mLogLatencyMetrics = false;
}
return;
}
boolean forceReceive = false;
// Ensure that even if something goes awry with the timeout
// detection, we catch "hung" broadcasts here, discard them,
// and continue to make progress.
//
// This is only done if the system is ready so that early-stage receivers
// don't get executed with timeouts; and of course other timeout-
// exempt broadcasts are ignored.
//取出广播任务包含的所有接收器数量
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
//......
// Get the next receiver...
int recIdx = r.nextReceiver++; //取出该任务中的下一个接收器
//......
final BroadcastOptions brOptions = r.options;
final Object nextReceiver = r.receivers.get(recIdx);
//有序广播中的动态注册的广播,动态注册的广播是BroadcastFilter实例,静态注册的是ResolveInfo实例
if (nextReceiver instanceof BroadcastFilter) {
// Simple case: this is a registered receiver who gets
// a direct call.
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
//同样调用deliverToRegisteredReceiverLocked方法
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
+ mQueueName + "]: ordered="
+ r.ordered + " receiver=" + r.receiver);
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
} else {
if (filter.receiverList != null) {
maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
// r is guaranteed ordered at this point, so we know finishReceiverLocked()
// will get a callback and handle the activity start token lifecycle.
}
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
scheduleTempWhitelistLocked(filter.owningUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
}
return;
}
// Hard case: need to instantiate the receiver, possibly
// starting its application process to host it.
ResolveInfo info =
(ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
boolean skip = false;
//......关于广播是否跳过的一系列判断
r.manifestCount++;
r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
r.state = BroadcastRecord.APP_RECEIVE;
r.curComponent = component;
r.curReceiver = info.activityInfo;
if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
+ info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
+ receiverUid);
}
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
scheduleTempWhitelistLocked(receiverUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
// Broadcast is being executed, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.curComponent.getPackageName(), false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.curComponent.getPackageName() + ": " + e);
}
// Is this receiver's application already running?
//判断接收器进程是否存在,存在才会执行,这里适用于静态注册的广播
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.
}
// Not runn