紧接着上篇的分析,我们现在来分析一下处理广播的代码流程,也就是在方法queue.scheduleBroadcastsLocked();之后的操作
这些方法在BroadcastQueue.java中。在这里能看到我们常说的广播超时,以及我们重写onReceive什么时候执行。
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
final Handler mHandler = new Handler() {
//public Handler() {
// if (localLOGV) Slog.v(TAG, "Handler started!");
//}
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG, "Received BROADCAST_INTENT_MSG");
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
};
可以看到这里在分发广播时直接post一个消息到队列中,不影响后面的此过程的后续操作,这说明发送和处理广播是一个异步操作,后面才是真正的处理过程。
final void processNextBroadcast(boolean fromMsg) {
……
// First, deliver any non-serialized broadcasts right away.
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Slog.v(TAG,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}
……
}
这里的先处理的是mParallelBroadcasts中的接收器,前文的分析中得知这个里面的接收器全部都是无序广播接收器中动态注册的,而静态注册的以及有序广播的都是在mOrderedBroadcasts中,本文先对无序动态的流程进行说明。
<pre name="code" class="html">private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered) {
……
try {
if (DEBUG_BROADCAST_LIGHT) {
int seq = r.intent.getIntExtra("seq", -1);
Slog.i(TAG, "Delivering to " + filter
+ " (seq=" + seq + "): " + r);
}
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
if (ordered) {
r.receiver = null;
r.curFilter = null;
filter.receiverList.curBroadcast = null;
if (filter.receiverList.app != null) {
filter.receiverList.app.curReceiver = null;
}
}
}
}
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null && app.thread != null) {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser);
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
这里的app.thread就是发送广播应用的ApplicationThreadProxy,这里用到了跨进程通信的知识,
简要说一下,所有的应用进程在创建时就新建了一个activitythread和一个appliacationthread,前者用于处理主线程的用户交互操作和界面刷新操作。后者主要用户和system service进行跨进程的调用。
ApplicationThread是ActivityThread的一个内部类,所以接下来看文件ActivityThread.java中的
<pre name="code" class="html">public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) throws RemoteException {
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
这里的receiver就是在广播注册过程中关联上的,它的实现是Loadedapk. ReceiverDispatcher. InnerReceiver,这个在动态注册广播时ContextImpl中的registerReceiverInternal方法中有体现,继续往下:
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
……
If (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
}
……..
}
}
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
+ " to " + mReceiver);
}
Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
if (!mActivityThread.post(args)) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
final class Args extends BroadcastReceiver.PendingResult implements Runnable {
public void run() {
………
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
}
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}
if (receiver.getPendingResult() != null) {
finish();
}
……………
}
}
}
这里mActivityThread成员变量的类型为Handler,它是前面动态注册广播接收器时,从ActivityThread取得的应用主线程的Handler,并把消息post到消息队列中去,因此,ReceiverDispatcher不等这个广播被应用处理就返回了,这里也体现了广播的发送和处理是异步进行的。 最终执行的是Args里面的run方法,在这里执行了注册时保存的BroadcastReceiver实例的onReceive方法。这样就完成了一次广播处理过程。
说到这里我们分析了一个动态注册广播接收器处理非有序广播的过程,也留下了两个疑问,一个是静态广播以及有序广播的处理过程,还有一个就是前面提到的广播超时问题没有说明,下篇将对这两个问题进行继续分析。