廣播的註冊過程
靜態註冊:在應用的安裝時由系統自動完成註冊,具體來說是PMS(PackageManagerServer)來完成整個註冊過程。其他三大組件也是。
動態註冊:從ContentWrapper的registerReceiver方法開始, 調用了自己的registerReceiverInternal方法。
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
}
系統首先從mPackageInfo獲取IIntentReceiver對象,然後採用跨進程的方式向AMS發送廣播註冊的請求。所以採用IIntentReceiver而不是直接採用BroadCastReceiver是因爲這個過程是一個進程間通信的過程,他BroadCastReceiver是一個Android的組件是不能跨進程的,所以需要IIntentReceiver來中轉一下,毫無疑問,IIntentReceiver必然是一個Binder接口,他的具體實現是LoadedApk.ReceiverDispatcher.IIntentReceiver,ReceiverDispatcher內部同時保存了BoradcastReceiver和IIntentReceiver。
ReceiverDispatcher的getIIntentReceiver的實現:
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
getReceiverDispatcher方法重新創建了一個ReceiverDispatcher對象並將球保持的InnerReceiver對象返回,其中InnerReceiver對象和BroadcastReceiver都是在ReceiverDispatcher的構造方法中被保存起來的。
註冊廣播的真正實現是在AMS,AMS的registerReceiver方法:
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
...
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadast");
}
mReceiverResolver.addFilter(bf);
...
}
}
廣播的發送和接收過程
當send發送之後,AMS會查找出匹配的廣播接收器並且將廣播交給他去處理,關閉的發送有幾種:普通廣播,有序廣播 和 粘性廣播,他們的實現方式有一些不一樣,但是過程都是一樣的。
廣播的發送和接收,可以說是兩個階段。這裏從發射的廣播說起,廣播的發送仍然開始於ContextWrapper的sendBroadcast,之所以不是Context,那是因爲Context的sendBroadcast是一個抽象的方法,和廣播的註冊過程一樣,他也什麼都沒有做,也是ContextImpl去處理的。
@Override
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發送一個broadcastIntent
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
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, appOp, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
這裏隨即又調用了一個broadcastIntentLocked,這個方法就有點複雜了。在這個方法裏最開始有這麼一行
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
在Android5.0中,默認情況下廣播不會發送給已經停止的應用,其實在3.1就已經有這種特性,在broadcastIntentLocked內部,會根據intent-filter來匹配並且進行廣播過濾,最終將滿足的廣播添加到BrocastQueue中,接着就發送給對應的廣播接收者了。源碼如下:
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.
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
appOp, registeredReceivers, resultTo, resultCode, resultData, map,
ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(
TAG, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
下面我們看一下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;
}
就是發了一個Handler
// 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);
}
在這段代碼中,會創建一個Args對象並且通過post方式執行Args的邏輯,而Args實現了Runnable的接口,在這裏面有這麼一段代碼
final BroadcastReceiver receiver = mReceiver;
receiver.setPendingResult(this);
receiver.onReceiver(mContext,intent);
這個時候onReceiver被執行了,應用也就收到了廣播了,這就是整個廣播的工作過程。