1. ContextImpl registerReceiver分析
registerReceiver函數用于注冊一個動態廣播接收者,該函數在Context.java中聲明。根據本章前面對Context家族的介紹(參考圖6-3),其功能最終將通過ContextImpl類的registerReceiver函數來完成,可直接去看ContextImpl是如何實現此函數的。在SDK中一共定義了兩個同名的registerReceiver函數,其代碼如下:
**ContextImpl.java::registerReceiver**
~~~
/*
在SDK中輸出該函數,這也是最常用的函數。當廣播到來時,BroadcastReceiver對象的onReceive
函數將在主線程中被調用
*/
public Intent registerReceiver(BroadcastReceiverreceiver, IntentFilter filter) {
returnregisterReceiver(receiver, filter, null, null);
}
/*
功能和前面類似,但增加了兩個參數,分別是broadcastPermission和scheduler,作用有
兩個:
其一:對廣播者的權限增加了控制,只有擁有相應權限的廣播者發出的廣播才能被此接收者接收
其二:BroadcastReceiver對象的onReceiver函數可調度到scheduler所在的線程中執行
*/
publicIntent registerReceiver(BroadcastReceiver receiver,
IntentFilterfilter, String broadcastPermission, Handler scheduler) {
/*
注意,下面所調用函數的最后一個參數為getOuterContext的返回值。前面曾說過,ContextImpl為Context家族中真正干活的對象,而它對外的代理人可以是Application和Activity等,
getOuterContext就返回這個對外代理人。一般在Activity中調用registerReceiver函數,故此處getOuterContext返回的對外代理人的類型就是Activity。
*/
returnregisterReceiverInternal(receiver, filter, broadcastPermission,
scheduler, getOuterContext());
}
~~~
殊途同歸,最終的功能由registerReceiverInternal來完成,其代碼如下:
**ContextImpl.java::registerReceiverInternal**
~~~
privateIntent registerReceiverInternal(BroadcastReceiver receiver,
IntentFilter filter, String broadcastPermission, Handler scheduler,
Context context) {
IIntentReceiver rd = null;
if(receiver != null) {
//①準備一個IIntentReceiver對象
if(mPackageInfo != null && context != null) {
//如果沒有設置scheduler,則默認使用主線程的Handler
if (scheduler == null) scheduler= mMainThread.getHandler();
//通過getReceiverDispatcher函數得到一個IIntentReceiver類型的對象
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler, mMainThread.getInstrumentation(),
true);
} else {
if (scheduler == null) scheduler= mMainThread.getHandler();
//直接創建LoadedApk.ReceiverDispatcher對象
rd = new LoadedApk.ReceiverDispatcher(receiver, context, scheduler,
null, true).getIIntentReceiver();
}//if (mPackageInfo != null && context != null)結束
}// if(receiver != null)結束
try {
//②調用AMS的registerReceiver函數
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(),mBasePackageName,
rd, filter,broadcastPermission);
} ......
}
~~~
以上代碼列出了兩個關鍵點:其一是準備一個IIntentReceiver對象;其二是調用AMS的registerReceiver函數。
先來看IIntentReceiver,它是一個Interface,圖6-17列出了和它相關的成員圖譜。
:-: 
圖6-17 IIntentReceiver相關成員示意圖
由圖6-17可知:
- BroadcastReceiver內部有一個PendingResult類。該類是Android 2.3以后新增的,用于異步處理廣播消息。例如,當BroadcastReceiver收到一個廣播時,其onReceive函數將被調用。一般都是在該函數中直接處理該廣播。不過,當該廣播處理比較耗時,還可采用異步的方式進行處理,即先調用BroadcastReceiver的goAsync函數得到一個PendingResult對象,然后將該對象放到工作線程中去處理,這樣onReceive就可以立即返回而不至于耽誤太長時間(這一點對于onReceive函數被主線程調用的情況尤為有用)。在工作線程處理完這條廣播后,需調用PendingResult的finish函數來完成整個廣播的處理流程。
- 廣播由AMS發出,而接收及處理工作卻在另外一個進程中進行,整個過程一定涉及進程間通信。在圖6-17中,雖然在BroadcastReceiver中定義了一個廣播接收者,但是它與Binder沒有有任何關系,故其并不直接參與進程間通信。與之相反,IIntentReceiver接口則和Binder有密切關系,故可推測廣播的接收是由IIntentReceiver接口來完成的。確實,在整個流程中,首先接收到來自AMS的廣播的將是該接口的Bn端,即LoadedApk.ReceiverDispather的內部類InnerReceiver。
接收廣播的處理將放到本節最后再來分析,下面先來看AMS 的registerReceiver函數。
2. AMS的registerReceiver分析
AMS的registerReceiver函數比較簡單,但是由于其中將出現一些新的變量類型和成員,因此接下來按分兩部分進行分析。
(1) registerReceiver分析之一
registerReceiver的返回值是一個Intent,它指向一個匹配過濾條件(由filter參數指明)的Sticky Intent。即使有多個符合條件的Intent,也只返回一個。
**ActivityManagerService.java::registerReceiver**
~~~
public Intent registerReceiver(IApplicationThreadcaller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission) {
synchronized(this) {
ProcessRecord callerApp = null;
if(caller != null) {
callerApp = getRecordForAppLocked(caller);
....... //如果callerApp為null,則拋出異常,即系統不允許未登記照冊的進程注冊
//動態廣播接收者
//檢查調用進程是否有callerPackage的信息,如果沒有,也拋異常
if(callerApp.info.uid != Process.SYSTEM_UID &&
!callerApp.pkgList.contains(callerPackage)){
throw new SecurityException(......);
}
}......//if(caller != null)判斷結束
List allSticky = null;
//下面這段代碼的功能是從系統中所有Sticky Intent中查詢匹配IntentFilter的Intent,
//匹配的Intent保存在allSticky中
Iterator actions = filter.actionsIterator();
if(actions != null) {
while (actions.hasNext()) {
String action = (String)actions.next();
allSticky = getStickiesLocked(action, filter, allSticky);
}
} ......
//如果存在sticky的Intent,則選取第一個Intent作為本函數的返回值
Intentsticky = allSticky != null ? (Intent)allSticky.get(0) : null;
//如果沒有設置接收者,則直接返回sticky 的intent
if(receiver == null) return sticky;
//新的數據類型ReceiverList及mRegisteredReceivers成員變量,見下文的解釋
//receiver.asBinder將返回IIntentReceiver的Bp端
ReceiverList rl
= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
//如果是首次調用,則此處rl的值將為null
if (rl== null) {
rl =new ReceiverList(this, callerApp, Binder.getCallingPid(),
Binder.getCallingUid(),receiver);
if (rl.app != null) {
rl.app.receivers.add(rl);
}else {
try {
//監聽廣播接收者所在進程的死亡消息
receiver.asBinder().linkToDeath(rl, 0);
}......
rl.linkedToDeath = true;
}// if(rl.app != null)判斷結束
//將rl保存到mRegisterReceivers中
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
//新建一個BroadcastFilter對象
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission);
rl.add(bf);//將其保存到rl中
// mReceiverResolver成員變量,見下文解釋
mReceiverResolver.addFilter(bf);
~~~
以上代碼的流程倒是很簡單,不過其中出現的幾個成員變量和數據類型卻嚴重阻礙了我們的思維活動。先解決它們,BroadcastFilter及相關成員變量如圖6-18所示。
:-: 
圖6-18 BroadcastFilter及相關成員變量
結合代碼,對圖6-18中各數據類型和成員變量的作用及關系的解釋如下:
- 在AMS中,BroadcastReceiver的過濾條件由BroadcastFilter表示,該類從IntentFilter派生。由于一個BroadcastReceiver可設置多個過濾條件(即多次為同一個BroadcastReceiver對象調用registerReceiver函數以設置不同的過濾條件),故AMS使用ReceiverList(從ArrayList<BroadcastFilter>派生)這種數據類型來表達這種一對多的關系。
- ReceiverList除了能存儲多個BroadcastFilter外,還應該有成員指向某一個具體BroadcastReceiver,否則如何知道到底是哪個BroadcastReceiver設置的過濾條件呢?前面說過,BroadcastReceiver接收廣播是通過IIntentReceiver接口進行的,故ReceiverList中有receiver成員變量指向IIntentReceiver。
- AMS提供mRegisterReceivers用于保存IIntentReceiver和對應ReceiverList的關系。此外,AMS還提供mReceiverResolver變量用于存儲所有動態注冊的BroadcastReceiver所設置的過濾條件。
清楚這些成員變量和數據類型之間的關系后,接著來分析registerReceiver第二階段的工作。
(2) registerReceiver分析之二
**ActivityManagerService.java::registerReceiver**
~~~
//如果allSticky不為空,則表示有Sticky的Intent,需要立即調度廣播發送
if(allSticky != null) {
ArrayList receivers = new ArrayList();
receivers.add(bf);
intN = allSticky.size();
for(int i=0; i<N; i++) {
Intent intent = (Intent)allSticky.get(i);
//為每一個需要發送的廣播創建一個BroadcastRecord(暫稱之為廣播記錄)對象
BroadcastRecord r = new BroadcastRecord(intent, null,
null, -1, -1, null,receivers, null, 0, null, null,
false, true, true);
//如果mParallelBroadcasts當前沒有成員,則需要觸發AMS發送廣播
if (mParallelBroadcasts.size() == 0)
scheduleBroadcastsLocked();//向AMS發送BROADCAST_INTENT_MSG消息
//所有非ordered廣播記錄都保存在mParallelBroadcasts中
mParallelBroadcasts.add(r);
}//for循環結束
}//if (allSticky != null)判斷結束
returnsticky;
}//synchronized結束
}
~~~
這一階段的工作用一句話就能說清楚:為每一個滿足IntentFilter的Sticky的intent創建一個BroadcastRecord對象,并將其保存到mParllelBroadcasts數組中,最后,根據情況調度AMS發送廣播。
從上邊的描述中可以看出,一旦存在滿足條件的Sticky的Intent,系統需要盡快調度廣播發送。說到這里,想和讀者分享一種在實際工作中碰到的情況。
我們注冊了一個BroadcastReceiver,用于接收USB的連接狀態。在注冊完后,它的onReceiver函數很快就會被調用。當時筆者的一些同事認為是注冊操作觸發USB模塊又發送了一次廣播,卻又感到有些困惑,USB模塊應該根據USB的狀態變化去觸發廣播發送,而不應理會廣播接收者的注冊操作,這到底是怎么一回事呢?
相信讀者現在應該輕松解決這種困惑了吧?對于Sticky的廣播,一旦有接收者注冊,系統會馬上將該廣播傳遞給它們。
和ProcessRecord及ActivityRecord類似,AMS定義了一個BroadcastRecord數據結構,用于存儲和廣播相關的信息,同時還有兩個成員變量,它們作用和關系如圖6-19所示。
:-: 
圖6-19 BroadcastReceiver及相關變量
圖6-19比較簡單,讀者可自行研究。
在代碼中,registerReceiver將調用scheduleBroadcastsLocked函數,通知AMS立即著手開展廣播發送工作,在其內部就發送BROADCAST_INTENT_MSG消息給AMS。相關的處理工作將放到本節最后再來討論。
- 前言
- 第1章 搭建Android源碼工作環境
- 1.1 Android系統架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.2.3 利用Eclipse調試system_process
- 1.3 本章小結
- 第2章 深入理解Java Binder和MessageQueue
- 2.1 概述
- 2.2 Java層中的Binder架構分析
- 2.2.1 Binder架構總覽
- 2.2.2 初始化Java層Binder框架
- 2.2.3 addService實例分析
- 2.2.4 Java層Binder架構總結
- 2.3 心系兩界的MessageQueue
- 2.3.1 MessageQueue的創建
- 2.3.2 提取消息
- 2.3.3 nativePollOnce函數分析
- 2.3.4 MessageQueue總結
- 2.4 本章小結
- 第3章 深入理解SystemServer
- 3.1 概述
- 3.2 SystemServer分析
- 3.2.1 main函數分析
- 3.2.2 Service群英會
- 3.3 EntropyService分析
- 3.4 DropBoxManagerService分析
- 3.4.1 DBMS構造函數分析
- 3.4.2 dropbox日志文件的添加
- 3.4.3 DBMS和settings數據庫
- 3.5 DiskStatsService和DeviceStorageMonitorService分析
- 3.5.1 DiskStatsService分析
- 3.5.2 DeviceStorageManagerService分析
- 3.6 SamplingProfilerService分析
- 3.6.1 SamplingProfilerService構造函數分析
- 3.6.2 SamplingProfilerIntegration分析
- 3.7 ClipboardService分析
- 3.7.1 復制數據到剪貼板
- 3.7.2 從剪切板粘貼數據
- 3.7.3 CBS中的權限管理
- 3.8 本章小結
- 第4章 深入理解PackageManagerService
- 4.1 概述
- 4.2 初識PackageManagerService
- 4.3 PKMS的main函數分析
- 4.3.1 構造函數分析之前期準備工作
- 4.3.2 構造函數分析之掃描Package
- 4.3.3 構造函數分析之掃尾工作
- 4.3.4 PKMS構造函數總結
- 4.4 APK Installation分析
- 4.4.1 adb install分析
- 4.4.2 pm分析
- 4.4.3 installPackageWithVerification函數分析
- 4.4.4 APK 安裝流程總結
- 4.4.5 Verification介紹
- 4.5 queryIntentActivities分析
- 4.5.1 Intent及IntentFilter介紹
- 4.5.2 Activity信息的管理
- 4.5.3 Intent 匹配查詢分析
- 4.5.4 queryIntentActivities總結
- 4.6 installd及UserManager介紹
- 4.6.1 installd介紹
- 4.6.2 UserManager介紹
- 4.7 本章學習指導
- 4.8 本章小結
- 第5章 深入理解PowerManagerService
- 5.1 概述
- 5.2 初識PowerManagerService
- 5.2.1 PMS構造函數分析
- 5.2.2 init分析
- 5.2.3 systemReady分析
- 5.2.4 BootComplete處理
- 5.2.5 初識PowerManagerService總結
- 5.3 PMS WakeLock分析
- 5.3.1 WakeLock客戶端分析
- 5.3.2 PMS acquireWakeLock分析
- 5.3.3 Power類及LightService類介紹
- 5.3.4 WakeLock總結
- 5.4 userActivity及Power按鍵處理分析
- 5.4.1 userActivity分析
- 5.4.2 Power按鍵處理分析
- 5.5 BatteryService及BatteryStatsService分析
- 5.5.1 BatteryService分析
- 5.5.2 BatteryStatsService分析
- 5.5.3 BatteryService及BatteryStatsService總結
- 5.6 本章學習指導
- 5.7 本章小結
- 第6章 深入理解ActivityManagerService
- 6.1 概述
- 6.2 初識ActivityManagerService
- 6.2.1 ActivityManagerService的main函數分析
- 6.2.2 AMS的 setSystemProcess分析
- 6.2.3 AMS的 installSystemProviders函數分析
- 6.2.4 AMS的 systemReady分析
- 6.2.5 初識ActivityManagerService總結
- 6.3 startActivity分析
- 6.3.1 從am說起
- 6.3.2 AMS的startActivityAndWait函數分析
- 6.3.3 startActivityLocked分析
- 6.4 Broadcast和BroadcastReceiver分析
- 6.4.1 registerReceiver流程分析
- 6.4.2 sendBroadcast流程分析
- 6.4.3 BROADCAST_INTENT_MSG消息處理函數
- 6.4.4 應用進程處理廣播分析
- 6.4.5 廣播處理總結
- 6.5 startService之按圖索驥
- 6.5.1 Service知識介紹
- 6.5.2 startService流程圖
- 6.6 AMS中的進程管理
- 6.6.1 Linux進程管理介紹
- 6.6.2 關于Android中的進程管理的介紹
- 6.6.3 AMS進程管理函數分析
- 6.6.4 AMS進程管理總結
- 6.7 App的 Crash處理
- 6.7.1 應用進程的Crash處理
- 6.7.2 AMS的handleApplicationCrash分析
- 6.7.3 AppDeathRecipient binderDied分析
- 6.7.4 App的Crash處理總結
- 6.8 本章學習指導
- 6.9 本章小結
- 第7章 深入理解ContentProvider
- 7.1 概述
- 7.2 MediaProvider的啟動及創建
- 7.2.1 Context的getContentResolver函數分析
- 7.2.2 MediaStore.Image.Media的query函數分析
- 7.2.3 MediaProvider的啟動及創建總結
- 7.3 SQLite創建數據庫分析
- 7.3.1 SQLite及SQLiteDatabase家族
- 7.3.2 MediaProvider創建數據庫分析
- 7.3.3 SQLiteDatabase創建數據庫的分析總結
- 7.4 Cursor 的query函數的實現分析
- 7.4.1 提取query關鍵點
- 7.4.2 MediaProvider 的query分析
- 7.4.3 query關鍵點分析
- 7.4.4 Cursor query實現分析總結
- 7.5 Cursor close函數實現分析
- 7.5.1 客戶端close的分析
- 7.5.2 服務端close的分析
- 7.5.3 finalize函數分析
- 7.5.4 Cursor close函數總結
- 7.6 ContentResolver openAssetFileDescriptor函數分析
- 7.6.1 openAssetFileDescriptor之客戶端調用分析
- 7.6.2 ContentProvider的 openTypedAssetFile函數分析
- 7.6.3 跨進程傳遞文件描述符的探討
- 7.6.4 openAssetFileDescriptor函數分析總結
- 7.7 本章學習指導
- 7.8 本章小結
- 第8章 深入理解ContentService和AccountManagerService
- 8.1 概述
- 8.2 數據更新通知機制分析
- 8.2.1 初識ContentService
- 8.2.2 ContentResovler 的registerContentObserver分析
- 8.2.3 ContentResolver的 notifyChange分析
- 8.2.4 數據更新通知機制總結和深入探討
- 8.3 AccountManagerService分析
- 8.3.1 初識AccountManagerService
- 8.3.2 AccountManager addAccount分析
- 8.3.3 AccountManagerService的分析總結
- 8.4 數據同步管理SyncManager分析
- 8.4.1 初識SyncManager
- 8.4.2 ContentResolver 的requestSync分析
- 8.4.3 數據同步管理SyncManager分析總結
- 8.5 本章學習指導
- 8.6 本章小結
