廣播機(jī)制是Android系統(tǒng)中的一種消息傳播機(jī)制,通過觀察者模式實(shí)現(xiàn)了消息發(fā)送者與消息接收者之間的解耦吵冒。BroadcastReceiver
的使用方式有兩種招盲,一種是靜態(tài)注冊(cè),即在Manifest文件中注冊(cè)堪旧,然后在需要發(fā)送廣播時(shí)調(diào)用context.sendBroadcast(intent);
奖亚;第二種是動(dòng)態(tài)注冊(cè)淳梦。BroadcastReceiver
的使用不是本文的重點(diǎn),本文將著重講解廣播的注冊(cè)過程和消息發(fā)送及接收過程昔字。
1 廣播注冊(cè)過程
廣播的靜態(tài)注冊(cè)是通過PMS(PackageManagerService)來完成的爆袍,其余三大組件也是通過PMS來完成注冊(cè)的。這里重點(diǎn)講一下BroadcastReceiver
的動(dòng)態(tài)啟動(dòng)方法。和Activity
以及Service
一樣螃宙,其啟動(dòng)過程也是通過ContextWrapper-->ContextImpl
來完成的蛮瞄。其主要的啟動(dòng)函數(shù)是ContextImpl.registerReceiver
:
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) {
IIntentReceiver rd = null;
......
rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler, mMainThread.getInstrumentation, true);
......
return ActivityManagerNatvice.getDefault().registerReceiver(mMainThread.getApplicationThread(), mBasePackageName, rd, filter, boradcastPermission, userId);
......
}
從上面的代碼可以看出主要做了兩件事:
從
mPackageInfo
獲取IIntentReceiver
對(duì)象,之所以這樣和bindService
是一樣的谆扎,因?yàn)樯鲜龅淖?cè)過程是一個(gè)跨進(jìn)程的通信方式挂捅,而BroadcastReceiver
作為Android的一個(gè)組件是不能直接跨進(jìn)程傳遞的,所以需要使用IIntentReceiver
來中轉(zhuǎn)堂湖。其具體是由LoadedApk.ReceiverDispatcher.InnerReceiver
闲先,ReceiverDispatcher
內(nèi)部同時(shí)保存了BroadcastReceiver
和InnerReceiver
,所以當(dāng)接收到廣播時(shí)无蜂,ReceiverDispatcher
可以很方便地調(diào)用BroadcastReceiver.onReceive()
方法伺糠。通過
ActivityManagerNative.getDefault()
獲取ActivityManagerService
,然后通過AMS來完成廣播的注冊(cè)過程。
接下來具體看一下AMS的registerReceiver
具體的實(shí)現(xiàn):
public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
......
mRegisterReceivers.put(receiver.asBinder(), rl);
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId);
rl.add(bf);
mReceiverResolver.addFilter(bf);
}
2 廣播的發(fā)送和接收過程
廣播的發(fā)送通過ContextImpl.sendBroadcast
方法:
public void sendBroadcast(Intent intent) {
......
ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false, getUserId());
......
}
不出意料斥季,任務(wù)又轉(zhuǎn)到了AMS中训桶,AMS在接收到這個(gè)指令會(huì)調(diào)用內(nèi)部的broadcastIntentLocked
方法,在該方法中酣倾,AMS會(huì)根據(jù)intent-filter查找出匹配的廣播接收者舵揭,并通過一系列的條件過濾,并將最終滿足條件的廣播接收者添加到BroadcastQueue
中躁锡,然后BroadcastQueue
會(huì)將廣播發(fā)送到相應(yīng)的廣播接收者,核心代碼如下:
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermission, appOp, receivers, resultTo, resultCode, resultData, map, ordered, sticky, false, userId);
......
queue.enqueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
下面再看一下在BroadcastQueue
中發(fā)送廣播scheduleBroadcastsLocked
的實(shí)現(xiàn):
public void scheduleBroadcastsLocked(){
......
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
......
}
實(shí)際上BroadcastQueue
的scheduleBroadcastsLocked
方法沒有立即發(fā)送廣播午绳,而是發(fā)送了一個(gè)BROADCAST_INTENT_MSG類型的消息,BroadcastQueue收到該消息后會(huì)調(diào)用processNestBroadcast
方法:
while(mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.recivers.size();
for(int i = 0; i < N; i++) {
Object target = r.receivers.get(i);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
addBroadcastToHistoryLocked(r);
}
可以看到無序廣播存儲(chǔ)在mParallelBroadcasts中映之,系統(tǒng)遍歷該隊(duì)列拦焚,并將廣播發(fā)送給它所有的接收者。具體的發(fā)送工作通過deliverToRegisteredReceiverLocked
完成杠输,在該函數(shù)內(nèi)部通過performReceivedLocked
來完成:
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
......
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky, sendingUser, app.repProcState);
......
}
ApplicationThread的scheduleRegisteredReceiver會(huì)調(diào)用InnerReceiver.performReceive來實(shí)現(xiàn)廣播的接收赎败。而在這個(gè)方法中會(huì)調(diào)用LoadedApk.ReceiverDispatcher.performReceive方法:
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
......
Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser);
if(!mActivityThread.post(args)) {
if(mRistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
args.sendFinished(mgr);
}
}
}
在上面的代碼中,會(huì)創(chuàng)建一個(gè)Args對(duì)象抬伺,并通過mActivityThread的post方法來執(zhí)行Args的邏輯螟够,Args實(shí)際上是一個(gè)Runnable接口。mActivityThread是一個(gè)Handler峡钓,其實(shí)就是ActivityThread中的mH,類型是H若河。Args中的run方法有如下幾行代碼:
final BroadcastReceiver receiver = mReceiver;
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
這個(gè)時(shí)候BroadcastReceiver的onReceive方法才被執(zhí)行能岩,也就接收到廣播了。