#### **參考文章**
[Android應用程序注冊廣播接收器(registerReceiver)的過程分析](http://www.hmoore.net/alex_wsc/androids/477750)
#### **觀察者模式的深入探討**
BroadcastReceiver是Android 的四大組件之一,它作為應用內、進程間的一種重要通信手段,能夠將某個消息通過廣播的形式傳遞給它注冊的對應廣播接收器的對象,接收對象需要通過Context的registerReceiver函數注冊到AMS中,當通過sendBroadcast發送廣播時,所有注冊了對應的lntentfilter的BroadcastReceiver對象就會接收到這個消息,BroadcastReceiver 的onReceive方法就會被調用,這就是一個典型的發布——訂閱模式,也就是我們的觀察者模式。廣播接收器的注冊調用時序圖如圖1所示。
:-: 
圖1 注冊廣播接收器(registerReceiver)的過程
#### **實例**:
例:我們在MainActivity中注冊一個廣播接收器。
~~~
public class MainActivity extends Activity{
......
@Override
public void onResume() {
super.onResume();
IntentFilter updateFilter = new IntentFilter("info.update");
registerReceiver(updateReceiver, updateFilter);
}
BrocastReceiver updateReceiver=new BrocastReceiver(){
@Override
public void onReceive(Context context,Intent intent) {
Toast.makeText(getApplicationContext,"update",Toast.LENGTH_SHORT).show();
}
};
......
}
~~~
我們在MainActivity的onResume里注冊了一個只接收Action為“info.update”的廣播接收器,應用內的其他地方發布一個Action為“info.update”的廣播時,就會觸發updateReceiver的onReceive函數。下面我們就來一步一步分析廣播接收器的基本原理。
我們發現registerReceiver函數并不是在Activity中實現,因此,我們把目標移向Activity的父類ContextWrapper, registerReceiver 函數如下:
**Step 1. [ContextWrapper](https://www.androidos.net.cn/android/2.3.7_r1/xref/frameworks/base/core/java/android/content/ContextWrapper.java).registerReceiver**
這個函數實現在frameworks/base/core/java/android/content/ContextWrapper.java文件中:
~~~
public class ContextWrapper extends Context {
Context mBase;
......
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
......
}
~~~
這里的成員變量mBase是一個ContextImpl實例,繼續轉移到Contextlmpl 的registerReceiver 函數, 具體代碼如下:
**Step 2. [ContextImpl](https://www.androidos.net.cn/android/2.3.7_r1/xref/frameworks/base/core/java/android/app/ContextImpl.java).registerReceiver**
這個函數實現在frameworks/base/core/java/android/app/ContextImpl.java文件中:
~~~
class ContextImpl extends Context {
......
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, filter, broadcastPermission,
scheduler, getOuterContext());
}
private Intent registerReceiverInternal(BroadcastReceiver receiver,
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(); //獲取Handler 來投遞消息
}
//獲取 IIntentReceiver 對象,通過它與AMS交互,并且通過Handler傳遞消息
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
......
}
}
try {
//調用ActivityManagerNative 的registerReceiver
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(),
rd, filter, broadcastPermission);
} catch (RemoteException e) {
return null;
}
}
......
}
~~~
注冊廣播接收器的函數調用最終就進入到ContextImpl.registerReceiverInternal這個函數來了。這里的成員變量mPackageInfo是一個LoadedApk實例,它是用來負責處理廣播的接收,參數broadcastPermission和scheduler都為null,而參數context是上面的函數通過調用函數getOuterContext得到的,這里它就是指向MainActivity了,因為MainActivity是繼承于Context類的,因此,這里用Context類型來引用。
由于條件mPackageInfo != null和context != null都成立,而且條件scheduler == null也成立,于是就調用mMainThread.getHandler來獲得一個Handler了,這個Hanlder是后面用來分發ActivityManagerService發送過的廣播用的。這里的成員變量mMainThread是一個ActivityThread實例,我們先來看看ActivityThread.getHandler函數的實現,然后再回過頭來繼續分析ContextImpl.registerReceiverInternal函數。
**Step 3. [ActivityThread](https://www.androidos.net.cn/android/2.3.7_r1/xref/frameworks/base/core/java/android/app/ActivityThread.java).getHandler**
這個函數實現在frameworks/base/core/java/android/app/ActivityThread.java文件中:
~~~
public final class ActivityThread {
......
final H mH = new H();
private final class H extends Handler {
......
public void handleMessage(Message msg) {
......
switch (msg.what) {
......
}
......
}
......
}
......
final Handler getHandler() {
return mH;
}
......
}
~~~
有了這個Handler之后,就可以分發消息給應用程序處理了。
再回到上一步的ContextImpl.registerReceiverInternal函數中,它通過mPackageInfo.getReceiverDispatcher函數獲得一個IIntentReceiver接口對象rd,這是一個Binder對象,接下來會把它傳給ActivityManagerService,ActivityManagerService在收到相應的廣播時,就是通過這個Binder對象來通知MainActivity來接收的。
我們也是先來看一下mPackageInfo.getReceiverDispatcher函數的實現,然后再回過頭來繼續分析ContextImpl.registerReceiverInternal函數。
**Step 4. [LoadedApk](https://www.androidos.net.cn/android/2.3.7_r1/xref/frameworks/base/core/java/android/app/LoadedApk.java).getReceiverDispatcher**
這個函數實現在frameworks/base/core/java/android/app/LoadedApk.java文件中:
~~~
final class LoadedApk {
......
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
HashMap<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) {
// BroadcastReceiver 為key , ReceiverDispatcher 為value
map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
return rd.getIIntentReceiver();
}
}
......
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
......
InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
......
}
......
}
......
final IIntentReceiver.Stub mIIntentReceiver;
final Handler mActivityThread;
......
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
......
mIIntentReceiver = new InnerReceiver(this, !registered);
mActivityThread = activityThread;
......
}
......
IIntentReceiver getIIntentReceiver() {
return mIIntentReceiver;
}
}
......
}
~~~
在LoadedApk.getReceiverDispatcher函數中,首先看一下參數r是不是已經有相應的ReceiverDispatcher存在了,如果有,就直接返回了,否則就新建一個ReceiverDispatcher,并且以r為Key值保在一個HashMap中,而這個HashMap以Context,這里即為MainActivity為Key值保存在LoadedApk的成員變量mReceivers中,這樣,只要給定一個Activity和BroadcastReceiver,就可以查看LoadedApk里面是否已經存在相應的廣播接收發布器ReceiverDispatcher了。
在新建廣播接收發布器ReceiverDispatcher時,會在構造函數里面創建一個InnerReceiver實例,這是一個Binder對象,實現了IIntentReceiver接口,可以通過ReceiverDispatcher.getIIntentReceiver函數來獲得,獲得后就會把它傳給ActivityManagerService,以便接收廣播。在ReceiverDispatcher類的構造函數中,還會把傳進來的Handle類型的參數activityThread保存下來,以便后面在分發廣播的時候使用。
現在,再回到ContextImpl.registerReceiverInternal函數,在獲得了IIntentReceiver類型的Binder對象后,就開始要把它注冊到ActivityManagerService中去了。
**Step 5. [ActivityManagerProxy](https://www.androidos.net.cn/android/2.3.7_r1/xref/frameworks/base/core/java/android/app/ActivityManagerNative.java).registerReceiver**
這個函數實現在frameworks/base/core/java/android/app/ActivityManagerNative.java-ActivityManagerProxy.java文件中:
~~~
class ActivityManagerProxy implements IActivityManager
{
......
public Intent registerReceiver(IApplicationThread caller,
IIntentReceiver receiver,
IntentFilter filter, String perm) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
filter.writeToParcel(data, 0);
data.writeString(perm);
// 向AMS 提交注冊廣播接收器的請求
mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
reply.readException();
Intent intent = null;
int haveIntent = reply.readInt();
if (haveIntent != 0) {
intent = Intent.CREATOR.createFromParcel(reply);
}
reply.recycle();
data.recycle();
return intent;
}
......
}
~~~
這個函數通過Binder驅動程序就進入到ActivityManagerService中的registerReceiver函數中去了。
**Step 6. [ActivityManagerService](https://www.androidos.net.cn/android/2.3.7_r1/xref/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java).registerReceiver**
這個函數實現在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
~~~
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
......
public Intent registerReceiver(IApplicationThread caller,
IIntentReceiver receiver, IntentFilter filter, String permission) {
synchronized(this) {
// 1 . 獲取ProcessRecord
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = getRecordForAppLocked(caller);
if (callerApp == null) {
......
}
}
List allSticky = null;
// 2. 根據Action 查找匹配的sticky 接收器
Iterator actions = filter.actionsIterator();
if (actions != null) {
while (actions.hasNext()) {
String action = (String)actions.next();
allSticky = getStickiesLocked(action, filter, allSticky);
}
} else {
......
}
// The first sticky in the list is returned directly back to
// the client.
Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
......
if (receiver == null) {
return sticky;
}
// 3 . 獲取ReceiverList
ReceiverList rl
= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp,
Binder.getCallingPid(),
Binder.getCallingUid(), receiver);
if (rl.app != null) {
rl.app.receivers.add(rl);
} else {
......
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
// 4 . 構建BroadcastFilter 對象,并且添加到ReceiverList 中
BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
rl.add(bf);
......
mReceiverResolver.addFilter(bf);
// Enqueue broadcasts for all existing stickies that match
// this filter.
if (allSticky != null) {
......
}
return sticky;
}
}
......
}
~~~
函數首先是獲得調用registerReceiver函數的應用程序進程記錄塊,即注釋1 處,然后獲取這個進程對應的pid、uida。注釋2 處獲取到IntentFilter的所有Action,在MainActivity 中構建的filter只有一個Action,就是前面描述的“info.update”,這里先通過getStickiesLocked函數查找一下有沒有對應的sticky intent 列表存在。什么是Sticky Intent 呢?我們在最后一次調用sendStickyBroadcast函數來發送某個Action類型的廣播時,系統會把代表這個廣播的Intent保存下來,這樣,后來調用registerReceiver來注冊相同Action類型的廣播接收器,就會得到這個最后發出的廣播,這就是為什么叫做Sticky Intent了。這個最后發出的廣播雖然被處理完了,但是仍然被粘在ActivityManagerService 中,以便下一個注冊相應Action類型的廣播接收器還能繼承處理。
這里,假設不使用sendStickyBroadcast來發送“info.update”類型的廣播,于是,得到的allSticky和sticky都為null。
繼續往下看,這里傳進來的receiver不為null,于是,繼續往下執行到注釋3處。這里其實就是把廣播接收器receiver保存到一個ReceiverList 列表中,這個列表的宿主進程是rl.app,這里就是MainActivity所在的進程,在ActivityManagerService 中,用一個進程記錄塊來表示這個應用程序進程,它里面有一個列表receivers,專門用來保存這個進程注冊的廣播接收器。接著,又把這個ReceiverList 列表以receiver 為Key 值保存在ActivityManagerService的成員變量mRegistered Receivers中,這些都是為了方便在收到廣播時,快速找到對應的廣播接收器。
再往下看注釋4,只是把廣播接收器receiver保存起來,但是還沒有把它和filter關聯起來,這里就創建一個BroadcastFilter來把廣播接收器列表rl 和filter 關聯起來,然后保存在ActivityManagerService的成員變量mReceiverResolver中,這樣,就將廣播接收器receiver 及其要接收的廣播類型filter保存在ActivityManagerService 中,以便以后能夠接收到相應的廣播并進行處理。
### **廣播的發送過程**
廣播的發送過程比廣播接收器的注冊過程要復雜得多,不過這個過程仍然是以ActivityManagerService 為中心。具體詳情可參考[Android應用程序發送廣播(sendBroadcast)的過程分析](http://www.hmoore.net/alex_wsc/androids/477751)
這里,我們簡單總結一下Android 應用程序發送廣播的過程。
(1)通過send.Broadcast 把一個廣播通過Binder 發送給ActivityManagerService,ActivityManagerService根據這個廣播的Action 類型找到相應的廣播接收器,然后把這個廣播放進自己的消息隊列中,就完成第一階段對這個廣播的異步分發:
~~~
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
............
private final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle map, String requiredPermission,
boolean ordered, boolean sticky, int callingPid, int callingUid) {
intent = new Intent(intent);
............
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
try {
if (intent.getComponent() != null) {
.........
} else {
............
// 查詢到該Intent 對應的BroadcastFilter,也就是接收器列表
registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
}
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
.........
if (!ordered && NR > 0) {
..........
if (!replaced) {
mParallelBroadcasts.add(r);
scheduleBroadcastsLocked();// 處理廣播的異步分發
}
registeredReceivers = null;
NR = 0;
}
.........
}
.........
}
~~~
(2)ActivityManagerService 在消息循環中處理這個廣播, 并通過Binder 機制把這個廣播分發給注冊的ReceiverDispatcher, ReceiverDispatcher 把這個廣播放進MainActivity 所在線程的消息隊列中,就完成第二階段對這個廣播的異步分發:
~~~
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
.............
private final void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
// mHandler 發送一個空消息
mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
mBroadcastsScheduled = true;
}
............
//mHandler的類型為Handler,是AMS的內部類
final Handler mHandler = new Handler() {
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;
..........
}
}
};
...........
}
~~~
(3)ReceiverDispatcher 的內部類Args 在MainActivity 所在的線程消息循環中處理這個廣播,最終是將這個廣播分發給所注冊的BroadcastReceiver 實例的onReceive 函數進行處理:
~~~
final class LoadedApk {
.........
static final class ReceiverDispatcher {
...........
final class Args implements Runnable {
.........
public void run() {
BroadcastReceiver receiver = mReceiver;
.........
Intent intent = mCurIntent;
.........
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
if (mCurMap != null) {
mCurMap.setClassLoader(cl);
}
receiver.setOrderedHint(true);
receiver.setResult(mCurCode, mCurData, mCurMap);
receiver.clearAbortBroadcast();
receiver.setOrderedHint(mCurOrdered);
receiver.setInitialStickyHint(mCurSticky);
// 調用接收器的onReceive方法
receiver.onReceive(mContext, intent);
} catch (Exception e) {
.........
}
...........
}
}
..........
}
.........
}
~~~
簡單來說, 廣播這就是一個訂閱一一發布的過程,通過一些map 存儲BroadcastReceiver, key就是封裝了這些廣播的信息類,如Action 之類的。當發布一個廣播時通過AMS 到這個map 中查詢注冊了這個廣播的IntentFilter 的BroadcastReceiver,然后通過ReceiverDispatcher 將廣播分發給各個訂閱對象,從而完成這個發布一一訂閱過程。