Android廣播管理三--廣播發送(sendBroadcast)流程分析
前面我們分析了Android應用程式註冊廣播接收器的過程,接下來它還要等待ActivityManagerService將廣播分發過來。ActivityManagerService是如何得到廣播並把它分發出去的呢?
廣播的傳送者將廣播發送到ActivityManagerService,ActivityManagerService接收到這個廣播以後,就會在自己的註冊中心檢視有哪些廣播接收器訂閱了該廣播,然後把這個廣播逐一發送到這些廣播接收器中,但是ActivityManagerService並不等待廣播接收器處理這些廣播就返回了,因此,廣播的傳送和處理是非同步的。概括來說,廣播的傳送路徑就是從傳送者到ActivityManagerService,再從ActivityManagerService到接收者,這中間的兩個過程都是通過Binder程序間通訊機制來完成的
傳送廣播
ContextWrapper.sendBroadcast
這個函式定義在frameworks/base/core/java/android/content/ContextWrapper.java檔案中:
我們上文介紹了ContextWrapper類是Context類的封裝類,ContextImpl是Context類的實現類。這裡的成員變數mBase是一個ContextImpl例項,這裡只簡單地呼叫ContextImpl.sendBroadcast進一行操作。public class ContextWrapper extends Context { Context mBase; ...... @Override public void sendBroadcast(Intent intent) { mBase.sendBroadcast(intent); } ...... }
ContextImpl.sendBroadcast
這個函式定義在frameworks/base/core/java/android/app/ContextImpl.java檔案中:
這裡的resolvedType表示這個Intent的MIME型別,如果沒有設定這個Intent的MIME型別,resolvedType為null。接下來就呼叫ActivityManagerService的遠端介面ActivityManagerProxy把這個廣播發送給ActivityManagerService了。public void sendBroadcast(Intent intent) { ............ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { //StrictMode下,對一些Action需要進行檢查 intent.prepareToLeaveProcess(this); //呼叫AMS中的介面 ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } catch(RemoteException e) { .............. } }
ActivityManagerProxy.broadcastIntent
這個函式定義在frameworks/base/core/java/android/app/ActivityManagerNative.java檔案中:
class ActivityManagerProxy implements IActivityManager
{
......
public int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String requiredPermission, boolean serialized,
boolean sticky) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
......
mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
reply.recycle();
data.recycle();
return res;
}
......
}
這裡主要是把要傳遞的引數封裝好,然後通過Binder驅動程式進入到ActivityManagerService的broadcastIntent()方法中。
ActivityManagerService.broadcastIntent
這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java檔案中: public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
......
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String requiredPermission, boolean serialized, boolean sticky) {
synchronized(this) {//verifyBroadcastLocked方法檢查Broadcast中intent攜帶的資訊是否有問題(不能攜帶檔案描述符,避免安全隱患)
intent = verifyBroadcastLocked(intent);//同時檢查intent的flag
final ProcessRecord callerApp = getRecordForAppLocked(caller);//獲取呼叫方(傳送廣播)的ProcessRecord
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);
Binder.restoreCallingIdentity(origId);
return res;
}
}
......
}
這裡注意幾個引數:
serialized:表示當前廣播是否是order廣播,true代表order廣播(有序廣播);
sticky:表示當前廣播是否是sticky廣播,true代表sticky廣播(粘性廣播);
broadcastIntent中對Broadcast對應的Intent進行一些檢查後,呼叫broadcastIntentLocked進行實際的處理。
ActivityManagerService.broadcastIntentLocked
這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java檔案中,程式碼量較大,分段分析。
Part I
final int broadcastIntentLocked(.....) {
intent = new Intent(intent);
// By default broadcasts do not go to stopped apps.
// Android系統對所有app的執行狀態進行了跟蹤
// 當應用第一次安裝但未使用過,或從程式管理器被強行關閉後,將處於停止狀態
// 在傳送廣播時,不管是什麼廣播型別,系統預設增加了FLAG_EXCLUDE_STOPPED_PACKAGES的flag
// 使得對於所有BroadcastReceiver而言,如果其所在程序的處於停止狀態,該BroadcastReceiver將無法接收到廣播
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
//大量條件檢查,例如:
//有些Action只能由系統來發送;
//有些Action需要傳送方申明瞭對應許可權
...................
//某些Action,例如Package增加或移除、時區或時間改變、清除DNS、代理變化等,需要AMS來處理
//AMS需要根據Action,進行對應的操作
..................
}
1、排除Stopped狀態的應用
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
所有的廣播Intent在這裡都會預設加上這個標記,表示所有的廣播都不會發送到Stopped狀態的應用,應該在傳送的時候會檢查應用當前的狀態。
2、系統升級廣播
// If we have not finished booting, don't allow this to launch new processes.
if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
Intent.FLAG_RECEIVER_BOOT_UPGRADE是系統升級的flag,允許在系統啟動前傳送。只有註冊了的接收者被呼叫,所有的BroadcastReceiver元件不會被載入。
3、處理受保護廣播
// Verify that protected broadcasts are only being sent by system code,受保護的廣播只能有系統傳送
// and that system code is only sending protected broadcasts.
final String action = intent.getAction();
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
return ActivityManager.BROADCAST_SUCCESS;
}
受保護廣播是通過查詢PMS得到的,如果是受保護廣播,丟擲異常後直接返回ActivityManager.BROADCAST_SUCCESS,不會進行下面的動作。
4、判斷髮送者是否是系統程序
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {//如果是root、system、phone、bluetooth、nfc等的UID,則廣播不受限制
case Process.ROOT_UID:
case Process.SYSTEM_UID:
case Process.PHONE_UID:
case Process.BLUETOOTH_UID:
case Process.NFC_UID:
isCallerSystem = true;
break;
default:
isCallerSystem = (callerApp != null) && callerApp.persistent;
break;
}
isCallerSystem表示系統級使用者傳送的廣播,這部分廣播不受限制。5、處理特定系統廣播
if (action != null) {
switch (action) {
case Intent.ACTION_UID_REMOVED:
case Intent.ACTION_PACKAGE_REMOVED:
case Intent.ACTION_PACKAGE_CHANGED:
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
case Intent.ACTION_PACKAGES_SUSPENDED:
case Intent.ACTION_PACKAGES_UNSUSPENDED:
// Handle special intents: if this broadcast is from the package
// manager about a package being removed, we need to remove all of
// its activities from the history stack.
對於一些來自PMS的包狀態的變化,AMS需要及時的處理相關的Activity,這裡是因為AMS兼顧了所有的4大元件,當包的狀態發生變化,AMS作為總管需要第一時間內處理完總管要做的事情,然後將對應的廣播再轉發給對應的應用。
傳送廣播的第一階段主要工作有:
(1).根據廣播對應的Intent中的資訊,判斷髮送方是否有傳送該廣播的許可權;
(2).檢查傳送的廣播是否是一些特殊的系統廣播,特別是從PackageManagerService中發出的有個安裝的應用移除的廣播,如果檢測到,需要將這些包中的Activity從AMS的Activity棧中移除。
Part II
..............
// Add to the sticky list if requested.
// 處理粘性廣播相關的內容
if (sticky) {
//檢查是否有傳送許可權,在AndroidManifest.xml中必須宣告android.permission.BROADCAST_STICKY許可權
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
callingPid, callingUid)
!= PackageManager.PERMISSION_GRANTED) {
..................//丟擲SecurityException異常
}
//粘性廣播不能指定接收許可權,即傳送時不能有requiredPermission許可權資訊
if (requiredPermissions != null && requiredPermissions.length > 0) {
..............
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
if (intent.getComponent() != null) {
//傳送的intent裡面不能指定接收者,即粘性廣播不能指定接收方
............
}
// We use userId directly here, since the "all" target is maintained
// as a separate set of sticky broadcasts.
//當粘性廣播是針對特定userId時,判斷該粘性廣播與系統儲存的是否衝突
if (userId != UserHandle.USER_ALL) {
//取出傳送給所有user的粘性廣播,關於mStickyBroadcasts的介紹可參考上一篇部落格
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
UserHandle.USER_ALL);
if (stickies != null) {
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list != null) {
int N = list.size();
int i;
for (i=0; i<N; i++) {
//傳送給特定user的粘性廣播,與傳送給所有user的粘性廣播,action一致時,發生衝突
if (intent.filterEquals(list.get(i))) {
//丟擲異常
.............
}
}
}
}
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
if (stickies == null) {
stickies = new ArrayMap<>();
//按userId儲存粘性廣播
//即一個user,可能有多個粘性廣播
mStickyBroadcasts.put(userId, stickies);
}
//按照Action儲存粘性廣播
//即一個Action,可能對應中多個廣播
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list == null) {
//list為null時,直接加入
list = new ArrayList<>();
stickies.put(intent.getAction(), list);
}
final int stickiesCount = list.size();
int i;
for (i = 0; i < stickiesCount; i++) {
//新的粘性廣播與之前的重複,則保留新的
//即當傳送多個相同的粘性廣播時,系統僅會保留最新的
if (intent.filterEquals(list.get(i))) {
// This sticky already exists, replace it.
list.set(i, new Intent(intent));
break;
}
}
if (i >= stickiesCount) {
//不重複時,直接加入
list.add(new Intent(intent));
}
}
}
...............
broadcastIntentLocked方法第二部分主要是處理粘性廣播的,判斷髮送粘性廣播的條件是否滿足,然後就粘性廣播儲存起來,將其儲存到AMS的mStickyBroadcasts變數裡面,上一篇部落格中分析了mStickyBroadcasts是以使用者id作為key儲存的,首先取出當前使用者的所有sticky廣播,然後根據當前廣播的action儲存到action對應的List裡面即可。裡面還有一個細節,就是如果當前intent和list中的某個intent用filterEquals()比較相等,就直接替換掉以前的,否則直接新增到list末尾。
Part III
.............
// Figure out who all will receive this broadcast.弄清楚誰會接收這個廣播
//receivers主要用於儲存匹配當前廣播的靜態註冊的BroadcastReceiver
//若當前廣播是有序廣播時,還會插入動態註冊的BroadcastReceiver
List receivers = null;
//registeredReceivers用於儲存匹配當前廣播的動態註冊的BroadcastReceiver
//BroadcastFilter中有對應的BroadcastReceiver的引用
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
// 若設定了FLAG_RECEIVER_REGISTERED_ONLY,那麼只有此時完成了註冊的BroadcastReceiver才會收到資訊
// 簡單講就是,有FLAG_RECEIVER_REGISTERED_ONLY時,不通知靜態註冊的BroadcastReceiver
// 此處處理未設定該標記的場景
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
//利用PKMS的queryIntentReceivers介面,查詢滿足條件的靜態BroadcastReceiver
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
//廣播沒有指定特定接收者時
if (intent.getComponent() == null) {
//這裡的要求比較特殊,針對所有user,且從shell傳送的廣播
//即處理除錯用的廣播
if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
// Query one target user at a time, excluding shell-restricted users
for (int i = 0; i < users.length; i++) {
//user不允許除錯時,跳過
if (mUserController.hasUserRestriction(
UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
continue;
}
//得到當前user對應的滿足Intent要求的BroadcastReceiver
//mReceiverResolver中儲存的都是動態註冊的BroadcastReceiver對應的BroadcastFilter
List<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
//一般沒有指定接收者的廣播,都會走到這裡,這是通常的處理流程
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false, userId);
}
}
//檢查廣播中是否有REPLACE_PENDING標籤
//如果設定了這個標籤,那麼新的廣播可以替換掉AMS廣播佇列中,與之匹配的且還未被處理的舊有廣播
//這麼做的目的是:儘可能的減少重複廣播的傳送
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
.....................
//先處理動態註冊的BroadcastReceiver對應的廣播
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.
//根據Intent的Flag決定BroadcastQueue,獲取前臺或後臺的廣播佇列
final BroadcastQueue queue = broadcastQueueForIntent(intent);
//構造廣播對應的BroadcastRecord
//BroadcastRecord中包含了該廣播的所有接收者
BroadcastRecord r = new BroadcastRecord(........);
................
//設定了REPLACE_PENDING標籤,同時與舊有廣播匹配時,才會進行替換
//若能夠替換,replaceParallelBroadcastLocked方法中就會將新的廣播替換到佇列中
final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
if (!replaced) {
//沒有替換時,才需要將新的廣播加入到BroadcastQueue.mParallelBroadcasts佇列中
queue.enqueueParallelBroadcastLocked(r);//這裡非常重要,也就是說動態廣播都放在了BroadcastQueue.mParallelBroadcasts中
//觸發廣播發送流程
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
.....................
broadcastIntentLocke第三部分的工作主要包括:
1、查詢與當前廣播匹配的靜態和動態BroadcastReceiver;
2、若當前待發送的廣播是無序的,那麼為動態註冊的BroadcastReceiver,構造該廣播對應的BroadcastRecord加入到傳送佇列中,並觸發廣播發送流程;最後將動態廣播接收器置為null。
從這部分程式碼可以看出,對於無序廣播而言,動態註冊的BroadcastReceiver接收廣播的優先順序,高於靜態註冊的BroadcastReceiver。
Part IV
.................
// Merge into one list.將receivers和registerReceiver合併到一個列表(receivers)中。
int ir = 0;
if (receivers != null) {//靜態BroadcastReceiver
// A special case for PACKAGE_ADDED: do not allow the package
// being added to see this broadcast. This prevents them from
// using this as a back door to get run as soon as they are
// installed. Maybe in the future we want to have a special install
// broadcast or such for apps, but we'd like to deliberately make
// this decision.
//處理特殊的Action,例如PACKAGE_ADDED,系統不希望有些應用一安裝就能啟動
//APP安裝後,PKMS將傳送PACKAGE_ADDED廣播
//若沒有這個限制,在剛安裝的APP內部靜態註冊監聽該訊息的BroadcastReceiver,新安裝的APP就能直接啟動
String skipPackages[] = null;
if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
|| Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
|| Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
Uri data = intent.getData();
if (data != null) {
String pkgName = data.getSchemeSpecificPart();
if (pkgName != null) {
skipPackages = new String[] { pkgName };//將廣播對應的包名新增到skipPackages中
}
}
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {//移動app之後發出的廣播(APP2SD)
skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
if (skipPackages != null && (skipPackages.length > 0)) {
for (String skipPackage : skipPackages) {
if (skipPackage != null) {
int NT = receivers.size();
for (int it=0; it<NT; it++) {
ResolveInfo curt = (ResolveInfo)receivers.get(it);
if (curt.activityInfo.packageName.equals(skipPackage)) {
//將skipPackages對應的BroadcastReceiver移出receivers;這就是上面說的限制,因此,應用不能接收到自己的PACKAGE_ADDED廣播
receivers.remove(it);
it--;
NT--;
}
}
}
}
}
int NT = receivers != null ? receivers.size() : 0;
int it = 0;
ResolveInfo curt = null;
BroadcastFilter curr = null;
//NT對應的是靜態BroadcastReceiver的數量
//NR對應的是動態BroadcastReceiver的數量
//若傳送的是無序廣播,此時NR為0
//若是有序廣播,才會進入下面兩個while迴圈
//下面兩個while迴圈就是將靜態註冊的BroadcastReceiver和動態註冊的BroadcastReceiver
//按照優先順序合併到一起(有序廣播才會合併)
while (it < NT && ir < NR) {
if (curt == null) {
curt = (ResolveInfo)receivers.get(it);
}
if (curr == null) {
curr = registeredReceivers.get(ir);
}
//動態優先順序大於靜態時,將動態插入到receivers中
if (curr.getPriority() >= curt.priority) {
// Insert this broadcast record into the final list.
receivers.add(it, curr);
ir++;
curr = null;
it++;
NT++;
} else {
// Skip to the next ResolveInfo in the final list.
it++;
curt = null;
}
}
}
while (ir < NR) {
if (receivers == null) {
receivers = new ArrayList();
}
//插入剩下的動態BroadcastReceiver
receivers.add(registeredReceivers.get(ir));
ir++;
}
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);//根據intent的FLAG獲取前臺或後臺廣播佇列
//構造對應的BroadcastRecord
BroadcastRecord r = new BroadcastRecord(........);
............
//同樣判斷是否需要替換,這裡是Ordered Queue
boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
//沒替換時,就加入Ordered Queue
queue.enqueueOrderedBroadcastLocked(r);
//觸發傳送流程
queue.scheduleBroadcastsLocked();
}
} else {
// There was nobody interested in the broadcast, but we still want to record
// that it happened.
if (intent.getComponent() == null && intent.getPackage() == null
&& (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
//沒有處理的靜態或有序廣播,儲存起來
//感覺儲存起來也沒什麼用啊
addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
}
}
...............
走到這裡的話,registerReceivers不為null說明當前傳送的是一個order廣播。如果是order廣播,動態BroadcastReceiver和靜態BroadcastReceiver合併到一個佇列中進行處理,也就是說order廣播下,所有的BroadcastReceiver(靜態和動態)處理方式都是一樣的(序列化處理)。另外,對於靜態BroadcastReceiver而言,始終是和order廣播的處理方式是一樣的,也就是說靜態的BroadcastReceiver只有order模式。
簡單來說,broadcastIntentLocked()的第四部分工作就是有序廣播,把靜態BroadcastReceiver和動態BroadcastReceiver按照優先順序合併到receivers中,構造對於的BroadcastRecord,然後將BroadcastRecord加入到Ordered Queue中,並觸發廣播發送流程。
至此,整個broadcastIntentLocked函式分析完畢,除去一些條件判斷的細節外,整個工作流程如下圖所示:
1、處理粘性廣播。
由於粘性廣播的特性(BroadcastReceiver註冊即可接收),系統必須首先儲存粘性廣播。
2、處理普通動態廣播。
普通廣播是併發的,系統優先為動態註冊的BroadcastReceiver傳送廣播。動態廣播對應的BroadcastRecord加入到Parallel Queue中。
3、處理靜態廣播和有序廣播。
這一步主要是為靜態註冊BroadcastReceiver傳送廣播,對應的BroadcastRecord加入到Ordered Queue中。
此外,需要注意的是:如果廣播是有序的,那麼第2步不會為動態註冊的BroadcastReceiver傳送廣播,而是在第三步統一發送。傳送有序廣播時,AMS將按照BroadcastReceiver的優先順序,依次構造BroadcastRecord加入到Ordered Queue中。
BroadcastQueue.scheduleBroadcastsLocked
從上面的程式碼,我們知道廣播發送方呼叫sendBroadcast後,AMS會構造對應的BroadcastRecord加入到BroadcastQueue中,返回呼叫BroadcastQueue的scheduleBroadcastsLocked()方法。現在我們看下這個方法。
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {//避免短時間內重複傳送BROADCAST_INTENT_MSG
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
/**
* Set when we current have a BROADCAST_INTENT_MSG in flight.
*/
boolean mBroadcastsScheduled = false;
上面的程式碼將傳送BROADCAST_INTENT_MSG,觸發BroadcastQueue呼叫processNextBroadcast()方法進行處理。
BroadcastQueue.processNextBroadcast
processNextBroadcast方法較長,分段進行分析。
Part I
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
BroadcastRecord r;
..............
//更新CPU的使用情況
//處理靜態廣播時,可能需要拉起對應程序,因此在這裡先記錄一下CPU情況
mService.updateCpuStats();
if (fromMsg) {
//處理BROADCAST_INTENT_MSG後,將mBroadcastsScheduled置為false
//scheduleBroadcastsLocked就可以再次被呼叫了
mBroadcastsScheduled = false;
}
// First, deliver any non-serialized broadcasts right away.
//先處理“併發”傳送的普通廣播(無序廣播),mParallelBroadcasts中儲存動態註冊的廣播接收器
while (mParallelBroadcasts.size() > 0) {
//依次取出BroadcastRecord
r = mParallelBroadcasts.remove(0);
//記錄傳送的時間
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
................
for (int i=0; i<N; i++) {
//mParallelBroadcasts中的每個成員均為BroadcastFilter型別
Object target = r.receivers.get(i);
............
//為該BroadcastRecord對應的每個Receiver傳送廣播
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
//將這裡處理過的資訊加入到歷史記錄中
addBroadcastToHistoryLocked(r);
}
........................
}
}
從上面的程式碼可以看出,processNextBroadcast方法第一部分主要是為動態註冊的BroadcastReceiver傳送普通廣播。傳送普通廣播的方法為deliverToRegisteredReceiverLocked方法。
1.deliverToRegisteredReceiverLocked
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
boolean skip = false;
//檢查廣播發送方是否有BroadcastReceiver指定的許可權
if (filter.requiredPermission != null) {
int perm = mService.checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
............
skip = true;
} else {
//進一步檢查許可權的合理性
final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
if (opCode != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(opCode, r.callingUid,
r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
............
skip = true;
}
}
}
//檢查BroadcastReceiver是否有Broadcast要求的許可權
if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
String requiredPermission = r.requiredPermissions[i];
int perm = mService.checkComponentPermission(requiredPermission,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
.................
//只要一條許可權不滿足,就結束
skip = true;
break;
}
//進一步檢查許可權的合理性
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
&& mService.mAppOpsService.noteOperation(appOp,
filter.receiverList.uid, filter.packageName)
!= AppOpsManager.MODE_ALLOWED) {
...........
skip = true;
break;
}
}
}
//這段程式碼我看的有些懵逼,傳送方沒要求許可權,還檢查啥?
if (!skip && (r.requiredPermissions == null || r.requiredPermissions.length == 0)) {
int perm = mService.checkComponentPermission(null,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
............
skip = true;
}
}
//還有一些其它的檢查,不再分析程式碼了。。。。。
//包括是否允許以background的方式傳送、IntentFirewall是否允許廣播中的Intent傳送
...............................
if (skip) {
//不滿足傳送條件的話,標記一下,結束髮送
r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
return;
}
// If permissions need a review before any of the app components can run, we drop
// the broadcast and if the calling app is in the foreground and the broadcast is
// explicit we launch the review UI passing it a pending intent to send the skipped
// broadcast.
//特殊情況,還需要再次檢查許可權,中斷廣播發送
//再次滿足傳送條件後,會重新進入到後續的傳送流程
if (Build.PERMISSIONS_REVIEW_REQUIRED) {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
filter.owningUserId)) {
r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
return;
}
}
//可以傳送了,標記一下
r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;
// If this is not being sent as an ordered broadcast, then we
// don't want to touch the fields that keep track of the current
// state of ordered broadcasts.
if (ordered) {
//如果傳送的是有序廣播,則記錄一些狀態資訊等,不涉及廣播發送的過程
.............
}
try {
..............
//若BroadcastReceiver對應的程序處於fullBackup狀態(備份和恢復),則不傳送廣播
if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
if (ordered) {
//有序廣播必須處理完一個,才能處理下一個,因此這裡主動觸發一下
skipReceiverLocked(r);
}
} else {
//執行傳送工作
performReceiveLocked(.............);
}
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
.............
}
}
deliverToRegisteredReceiverLocked方法看起來很長,但大部分內容都是進行許可權檢查等操作,實際的傳送工作交給了performReceiveLocked方法。廣播是一種可以攜帶資料的跨程序、跨APP通訊機制,為了避免安全洩露的問題,Android才在此處使用了大量的篇幅進行許可權檢查的工作。
2.BroadcastQueue.performReceiveLocked
void performReceiveLocked(.........) {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) {
if (app.thread != null) {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
//通過Binder通訊,將廣播資訊發往BroadcastReceiver處在的程序
app.thread.scheduleRegisteredReceiver(.......);
} catch (RemoteException ex) {
// Failed to call into the process. It's either dying or wedged. Kill it gently.
.......
app.scheduleCrash("can't deliver broadcast");
}
throw ex;
} else {
// Application has died. Receiver doesn't exist.
throw new RemoteException("app.thread must not be null");
}
} else {
//直接通過Binder通訊,將訊息發往BroadcastReceiver的IIntentReceiver介面
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
對於動態註冊的BroadcastReceiver而言,傳送廣播的流程應該進入到上述程式碼的If分支。程序的ApplicationThread呼叫scheduleRegisteredReceiver函式的流程,我們放在後面單獨分析。這一部分整體的流程如下圖所示:
Part II
至此,processNextBroadcast函式已經發送完所有的動態普通廣播,我們看看該函式後續的流程:
..........
// Now take care of the next serialized one...
// If we are waiting for a process to come up to handle the next
// broadcast, then do nothing at this point. Just in case, we
// check that the process we're waiting for still exists.
// 對於有序或靜態廣播而言,需要依次向每個BroadcastReceiver傳送廣播,前一個處理完畢後才能傳送下一個廣播
// 如果BroadcastReceiver對應的程序還未啟動,則需要等待
// mPendingBroadcast就是用於儲存,因為對應程序還未啟動,而處於等待狀態的BroadcastRecord
if (mPendingBroadcast != null) {
................
boolean isDead;
synchronized (mService.mPidsSelfLocked) {
//通過AMS得到對應程序的資訊
//BroadRecord對應多個BroadcastReceiver,即對應多個程序
//此處curApp儲存當前正在等待的程序
ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.crashing;
}
if (!isDead) {
// It's still alive, so keep waiting
// 注意到有序和靜態廣播必須依次處理
// 因此,若前一個BroadcastRecord對應的某個程序啟動較慢,不僅會影響該BroadcastRecord中後續程序接收廣播
// 還會影響到後續所有BroadcastRecord對應程序接收廣播
return;
} else {
............
mPendingBroadcast.state = BroadcastRecord.IDLE;
mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
mPendingBroadcast = null;
}
}
boolean looped = false;
//處理之前傳送BroadcastRecord的狀態
do {
if (mOrderedBroadcasts.size() == 0) {
// No more broadcasts pending, so all done!
mService.scheduleAppGcsLocked();
//當至少一個BroadcastRecord被處理完畢後,looped才會被置變為true
if (looped) {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
// adjustments.
// 因為靜態廣播和有序廣播,可能拉起程序
// 因此這些廣播處理完畢後,AMS需要釋放掉一些不需要的程序
mService.updateOomAdjLocked();
}
return;
}
//每次均處理當前的第一個
r = mOrderedBroadcasts.get(0);
boolean forceReceive = false;
// 這裡用於判斷此廣播是否處理超時
// 僅在系統啟動完畢後,才進行該判斷,因為PRE_BOOT_COMPLETED廣播可能由於系統升級需要等待較長時間
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
if (mService.mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&
//單個廣播處理的超時時間,定義為2 * 每個接收者處理的最長時間(10s)* 接收者的數量
(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
...............
//如果超時,則強制結束這條廣播的處理
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
if (r.state != BroadcastRecord.IDLE) {
//BroadcastRecord還未處理或處理完畢後,狀態為IDLE態
............
return;
}
//如果廣播處理完畢,或中途被取消
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
// No more receivers for this broadcast! Send the final
// result if requested...
if (r.resultTo != null) {
try {
..........
//廣播處理完畢,將該廣播的處理結果傳送給resultTo對應BroadcastReceiver
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
} catch (RemoteException e) {
.............
}
}
.................
cancelBroadcastTimeoutLocked();
addBroadcastToHistoryLocked(r);
//作一下記錄
if (r.intent.getComponent() == null && r.intent.getPackage() == null
&& (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
}
mOrderedBroadcasts.remove(0);
//一個BroadcastRecord處理完畢後,將r置為null
r = null;
//如果一個廣播處理完畢,說明可能拉起過程序,於是looped置為true
looped = true;
continue;
}
//r == null時,可以處理下一個BroadcastRecord
//r != null, 繼續處理當前BroadcastRecord的下一個BroadReceiver
} while (r == null);
....................
這部分程式碼看起來有點亂,其實主要做了兩個工作:
1、判斷是否有PendingBroadcast。
當存在PendingBroadcast,且當前正在等待啟動的程序並沒有死亡,那麼不能處理下一個BroadcastRecord,必須等待PendingBroadcast處理完畢。
2、處理mOrderedBroadcasts中的BroadcastRecord。
由於有序廣播和靜態廣播,必須一個接一個的處理。因此每傳送完一個廣播後,均會重新呼叫processNextBroadcast方法。
在傳送新的BroadcastRecord時,需要先處理舊有BroadcastRecord的狀態。於是,這段程式碼後續部分,主要進行了以下操作:
若所有BroadcastRecord均處理完畢,利用AMS釋放掉無用程序;
更新超時BroadcastRecord的狀態,同時越過此BroadcastRecord;
當一個BroadcastRecord處理完畢後,將結果傳送給指定BroadcastReceiver(指定了接收者,才進行此操作),同時將該BroadcastRecord從mOrderedBroadcasts中移除。
這一系列動作的最終目的,就是選出下一個處理的BroadcastRecord,然後就可以開始向該BroadcastRecord中下一個BroadcastReceiver傳送廣播了。
這一部分整體的判斷邏輯大致上如下圖所示:
Part III
..............
// Get the next receiver...
// 開始處理當前BroadcastRecord的下一個BroadcastReceiver
int recIdx = r.nextReceiver++;
// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
// 記錄單個廣播的起始時間
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
//記錄整個BroadcastRecord的起始時間
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
................
}
if (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
....................
//設定廣播處理的超時時間為10s
setBroadcastTimeoutLocked(timeoutTime);
}
final BroadcastOptions brOptions = r.options;
//取出下一個廣播接收者
final Object nextReceiver = r.receivers.get(recIdx);
if (nextReceiver instanceof BroadcastFilter) {
// Simple case: this is a registered receiver who gets
// a direct call.
//動態註冊的BroadcastReceiver,即處理的是有序廣播
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
............
//與處理普通廣播一樣,呼叫deliverToRegisteredReceiverLocked
//將廣播發送給BroadcastReceiver對應程序的ApplicationThread
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
//從程式碼流程來看,deliverToRegisteredReceiverLocked傳送廣播出現問題時,r.receiver才可能是null
//程式碼執行到這個位置,加入到Ordered Queue的Broadcast一定是order的
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
...............
//因此這裡應該是有序廣播發送錯誤,因此重新發送BROADCAST_INTENT_MSG,觸發下一次傳送廣播的流程
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
} else {
//處理特殊的選項
//向DeviceIdleController傳送訊息,賦予白名單內的應用,
//在Doze模式的啟用視窗中,額外的可以訪問網路和持鎖的時間
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
scheduleTempWhitelistLocked(filter.owningUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
}
//對於有序廣播而言,已經通知了一個BroadcastReceiver,需要等待處理結果,因此返回
return;
}
.......................
processNextBroadcast的第3部分,主要是處理有序廣播發往動態BroadcastReceiver的場景。從程式碼可以看出,有序廣播具體的方法流程與普通廣播一致,均是呼叫deliverToRegisteredReceiverLocked函式。唯一不同的是,有序廣播發往一個BroadcastReceiver後,必須等待處理結果,才能進行下一次傳送過程。
Part IV
...................
// Hard case: need to instantiate the receiver, possibly
// starting its application process to host it.
// 開始處理靜態廣播
ResolveInfo info = (ResolveInfo)nextReceiver;
//得到靜態廣播對應的元件名
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
boolean skip = false;
//以下與deliverToRegisteredReceiverLocked中類似,進行傳送廣播前的檢查工作
//判斷髮送方和接收方要求的許可權,是否互相滿足
//判斷Intent是否滿足AMS的IntentFirewall要求
...................
boolean isSingleton = false;
try {
//判斷BroadcastReceiver是否是單例的
isSingleton = mService.isSingleton(info.activityInfo.processName,
info.activityInfo.applicationInfo,
info.activityInfo.name, info.activityInfo.flags);
} catch (SecurityException e) {
.................
}
//BroadcastReceiver要求SINGLE_USER
//那麼必須申明INTERACT_ACROSS_USERS許可權
if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
if (ActivityManager.checkUidPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS,
info.activityInfo.applicationInfo.uid)
!= PackageManager.PERMISSION_GRANTED) {
..............
skip = true;
}
}
if (!skip) {
r.manifestCount++;
} else {
r.manifestSkipCount++;
}
if (r.curApp != null && r.curApp.crashing) {
.........
skip = true;
}
if (!skip) {
boolean isAvailable = false;
try {
isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
info.activityInfo.packageName,
UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
} catch (Exception e) {
..........
}
if (!isAvailable) {
.........
skip = true;
}
}
//判斷BroadcastReceiver對應程序是否允許後臺啟動
//不允許也會skip
..............
if (skip) {
..................
r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
r.receiver = null;
r.curFilter = null;
r.state = BroadcastRecord.IDLE;
//跳過該廣播,傳送下一個廣播
scheduleBroadcastsLocked();
return;
}
r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
r.state = BroadcastRecord.APP_RECEIVE;
r.curComponent = component;
r.curReceiver = info.activityInfo;
................
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
//與處理有序普通廣播一樣,在此處理特殊的選項
scheduleTempWhitelistLocked(receiverUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
// Broadcast is being executed, its package can't be stopped.
try {
//傳送靜態廣播前,修改BroadcastReceiver對應的Package狀態
AppGlobals.getPackageManager().setPackageStoppedState(
r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
...............
}
// Is this receiver's application already running?
if (app != null && app.thread != null) {
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
//BroadcastReceiver對應程序啟動時,呼叫ApplicationThread的scheduleReceiver
processCurBroadcastLocked(r, app);
//等待結果,故return
return;
} catch (RemoteException e) {
//這可能是對應程序死亡,可以重新拉起程序傳送
..........
} catch (RuntimeException e) {
.........
//傳送失敗,結束本次傳送
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
//繼續傳送後續的廣播
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
r.state = BroadcastRecord.IDLE;
return;
}
}
.............
//啟動程序處理廣播
if ((r.curApp=mService.startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
"broadcast", r.curComponent,
(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
== null) {
//建立程序失敗
...............
//傳送失敗,結束本次傳送
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
//繼續傳送後續的廣播
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
//程序啟動成功時,mPendingBroadcast儲存當前的BroadcastRecord,及待發送廣播的下標
//當程序啟動後,將根據這兩個值處理廣播
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
.............
processNextBroadcast第四部分主要是處理靜態廣播,除了檢查是否滿足傳送條件外,主要進行了以下工作: 1、若BroadcastReceiver對應的程序已經啟動,那麼將直接呼叫程序對應ApplicationThread的scheduleReceiver傳送廣播;
2、若BroadcastReceiver對應的程序沒有啟動,那麼AMS將啟動對應的程序。
當對應的程序啟動,同時完成Android環境的建立後,AMS在attachApplicationLocked函式中重新處理等待發送的廣播,對應程式碼如下:
...............
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
try {
//傳送因目標程序還未啟動,而處於等待狀態的廣播
//sendPendingBroadcastsLocked將呼叫BroadcastQueue中的sendPendingBroadcastsLocked函式
//sendPendingBroadcastsLocked最後仍會呼叫程序對應ApplicationThread的scheduleReceiver函式
didSomething |= sendPendingBroadcastsLocked(app);
} catch (Exception e) {
// If the app died trying to launch the receiver we declare it 'bad'
Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
badApp = true;
}
}
.............
這一部分整體的流程大致如下圖所示:
應用程序處理廣播
最後,我們看看應用程序收到廣播處理請求後的流程。
1.動態廣播的處理流程
在上面的performReceiveLocked方法中,呼叫了app.thread.scheduleRegisteredReceiver方法,最後通過Binder通訊呼叫的是程序對應ApplicationThread的scheduleRegisteredReceiver介面。
ActivityThread.ApplicationThread.scheduleRegisteredReceiver
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
..............
//呼叫的是LoadedApk中ReceiverDispatcher的內部類InnerReceiver的介面
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
這裡的receiver的具體型別是LoadedApk.ReceiverDispatcher.InnerReceiver,即定義在LoadedApk類的內部類ReceiverDispatcher裡面的一個內部類InnerReceiver,這裡呼叫它的performReceive方法。
InnerReceiver.performReceive()
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
mStrongRef = strong ? rd : null;
}
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
........
rd = null;
} else {
rd = mDispatcher.get();
}
.......
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);//呼叫ReceiverDispatcher的performReceive方法
} else {
// The activity manager dispatched a broadcast to a registered
// receiver in this process, but before it could be delivered the
// receiver was unregistered. Acknowledge the broadcast on its
// behalf so that the system's broadcast sequence can continue.
//處理特殊情況,在收到廣播前,BroadcastReceiver已經unregister了。
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());//通知AMS結束
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
這裡只是簡單地呼叫ReceiverDispatcher的performReceive方法來進一步處理,這裡的ReceiverDispatcher是LoadedApk類裡面的一個內部類。
ReceiverDispatcher.performReceive()
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);//建立Args物件
..........
//mActivityThread是一個Handler物件,若建立BroadcastReceiver時沒有指定Handler物件,則預設時ActivityThread主執行緒對應的Handler
if (intent == null || !mActivityThread.post(args)) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
...........
args.sendFinished(mgr);
}
}
}
這裡mActivityThread成員變數的型別是Handler,它是Activity在註冊廣播接收器時,從ActivityThread取得的。這裡ReceiverDispatcher藉助這個Handler,把這個廣播以訊息的形式放到Activity所在的ActivityThread的訊息佇列中去,因此,ReceiverDispatcher不等這個廣播被Activity處理就返回了,這裡也體現了廣播的傳送和處理是非同步進行的。
注意這裡處理訊息的方式是通過Handler.post方法進行的,post方法的引數是Runnable型別的,這個訊息最終會呼叫這個引數的run方法來處理。這裡的Args類是LoadedApk類的內部類ReceiverDispatcher的一個內部類,Args類實現了Runnable介面,因此,可以作為mActivityThread.post方法的引數,代表這個廣播的intent也儲存在這個Args例項中。
Args.run()
final class Args extends BroadcastReceiver.PendingResult implements Runnable {
private Intent mCurIntent;
private final boolean mOrdered;
private boolean mDispatched;
public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, int sendingUser) {
super(resultCode, resultData, resultExtras,
mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
mCurIntent = intent;
mOrdered = ordered;
}
public void run() {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
...........
final IActivityManager mgr = ActivityManagerNative.getDefault();
final Intent intent = mCurIntent;
..........
mCurIntent = null;
mDispatched = true;
if (receiver == null || intent == null || mForgotten) {
if (mRegistered && ordered) {
...........
sendFinished(mgr);
}
return;
}
..........
try {//這裡處理的是動態廣播的註冊,預設認為BroadcastReceiver已經存在
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);//設定BroadcastReceiver的PendingResult
receiver.onReceive(mContext, intent);//呼叫BroadcastReceiver的onReceive方法
} catch (Exception e) {
......
}
//當呼叫BroadcastReceiver的goAsync方法時,會把mPendingResult設為null;於是不會結束髮送流程,直到呼叫PendingResult的finish方法
if (receiver.getPendingResult() != null) {
finish();//Args繼承PendingResult,此處也是呼叫PendingResult的finish方法。
}
..........
}
}
這裡的mReceiver是ReceiverDispatcher類的成員變數,型別是BroadcastReceiver,就是Activity註冊廣播接收器時建立的BroadcastReceiver例項了,有了這個ReceiverDispatcher例項之後,就可以呼叫它的onReceive方法把這個廣播發給它處理了。我們寫的廣播接收器繼承了BroadcastReceiver,並且重寫onReceive方法,因此這裡就呼叫到我們自己寫的onReceive方法中了。之後呼叫了BroadcastReceiver.PendingResult.finish()方法,來結束處理流程。
BroadcastReceiver.PendingResult.finish()
/**
* Finish the broadcast. The current result will be sent and the
* next broadcast will proceed.傳送當前結果,下一個廣播將會被處理。
*/
public final void finish() {
if (mType == TYPE_COMPONENT) {//對於動態廣播而言,mType為TYPE_REGISTERED或TYPE_UNREGISTERED
final IActivityManager mgr = ActivityManagerNative.getDefault();
if (QueuedWork.hasPendingWork()) {
QueuedWork.singleThreadExecutor().execute( new Runnable() {
@Override public void run() {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast after work to component " + mToken);
sendFinished(mgr);
}
});
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to component " + mToken);
sendFinished(mgr);
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {//有序廣播才返回結果
...........
final IActivityManager mgr = ActivityManagerNative.getDefault();
sendFinished(mgr);//Binder通訊,呼叫AMS的finishReceiver方法。
}
}
這裡的mType是在建立Args物件的時候傳進來的,在Args的建構函式中,對於動態註冊的廣播接收器,引數mRegistered為true,mType就是TYPE_REGISTERED,對於非order廣播而言,ordered變數是false,這樣BroadcastReceiver.PendingResult中的mOrderedHint為false,mType是TYPE_REGISTERED;根據finish方