最近一直在研究学习Android broadcast 。这里就主要讲解一下广播的发送和接受过程
。当通过send方法来发送广播时,AMS会查找出匹配的广播接收者并将广播发送给他们处理。广播的发送有几种类型:普通广播,有序广播和粘性广播。这里分析下普通广播的实现。
广播的发送和接收。其本质是一个过程的两个阶段。广播的发送仍然开始于ContextWrapper的sendBroadcast方法,之所以不是Context,那是因为Context的sendBroadcast是一个抽象方法。和广播的注册过程一样ContextWrapper的sendBroadcast方法仍然什么都不做,只是把事情交给ContextImpl去处理,ContextImpl的sendBroadcast方法源码如下:
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
getUserId());
} catch (RemoteException e) {
}
}
它直接向AMS发起了一个异步请求用于发送广播。那么AMS的broadcastIntent方法的源码如下:
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String requiredPermission, boolean serialized, boolean sticky, int userId) {
synchronized(this) {
intent = verifyBroadcastLocked(intent);
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo,
resultCode, resultData, map, requiredPermission, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
从代码上看,broadcastIntent调用了broadcastIntentLocked方法,但在AMS的broadcastIntentLocked方法里有这么一句:
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
这表示在Android5.0下,默认情况下广播不会发送给已经停止的应用。FLAG_EXCLUDE_STOPPED_PACKAGES的含义是表示 不包含已经停止的应用,这个时候广播不会发送给已经停止的应用。
在broadcastIntentLocked的内部,会根据intent-filter查找出匹配的广播接收者并经过一系列的条件过滤,最终会将满足条件的广播接收者添加到BroadcastQueue中,接着BroadcastQueue将会广播发送给相应的广播接收者。
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
receivers, resultTo, resultCode, resultData, map, ordered,
sticky, false);
if (DEBUG_BROADCAST) Slog.v(
TAG, "Enqueueing ordered broadcast " + r
+ ": prev had " + queue.mOrderedBroadcasts.size());
if (DEBUG_BROADCAST) {
int seq = r.intent.getIntExtra("seq", -1);
Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
}
boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
下面看下BroadcastQueue中广播的发送过程的实现。如下所示:
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;
}
BroadcastQueue的scheduleBroadcastsLocked方法并没有立即发送广播,而是发送了一个BROADCAST_INTENT_MSG类型的消息,BroadcastQueue收到消息后会调用processNextBroadcast方法,BroadcastQueue的processNextBroadcast方法对普通广播的处理方式如下:
// 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中,系统会遍历mParallelBroadcasts并将其中的广播发送给它们所有接收者,具体的发送过程是通过deliverToRegisteredReceiverLocked方法来实现的。
最终呢,会调用ApplicationThread的scheduleRegisteredReceiver的实现比较简单,它通过InnerReceiver来实现广播的接收。然后InnerReceiver的performReceive方法会调用LoadedApk.ReceiverDispatcher的PerformReceive方法。最终会回调到receiver.onReceive()这个方法。
很显然,这个时候BroadcastReceiver的onReceive方法被执行了,也就是说应用收到广播了,同时,onReceive方法是在广播接收者的主线程中被调用,所以不能做耗时操作,因为是在ApplicationThread的主线程上执行的。
文章来自:博客园/cryAllen