Android系統(tǒng)的廣播機制是一種基于消息發(fā)布和訂閱的事件驅(qū)動模型,即廣播發(fā)送者負責(zé)發(fā)布消息奄抽,而接收者需要先訂閱消息,才能接收到消息,Android系統(tǒng)中的廣播機制是BroadcastReceiver組件糯累。
廣播接收者需要首先將自己注冊,最終他們是將自己注冊到了AMS服務(wù)中册踩,當(dāng)廣播發(fā)送者發(fā)送一個廣播的時候泳姐,首先發(fā)送到AMS服務(wù)中,然后由AMS服務(wù)發(fā)送給對應(yīng)的接收者棍好。
BroadCastReceiver注冊分析
首先我們來分析廣播接收者的注冊過程仗岸。我們知道,在Activity或者Service中注冊一個廣播接收者調(diào)用registerReceiver方法來接收借笙,該方法最終調(diào)用ContextImpl方法來實現(xiàn)扒怖。
1. ContextImpl.registerReceiver
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
}
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);
}
}
注冊的時候registerReceiver方法直接調(diào)用了registerReceiverInternal方法來實現(xiàn)具體的邏輯,這個方法比較簡單业稼,mPackageInfo是一個LoadedApk類型的對象盗痒,如果mPackageInfo不為空,則根據(jù)receiver到LoadedApk中查找這個Receiver關(guān)聯(lián)的Binder對象低散,如果mPackageInfo為空著直接創(chuàng)建一個Binder對象和receiver關(guān)聯(lián)起來俯邓。最后通過進程間請求,調(diào)用AMS服務(wù)的registerReceiver方法來注冊該廣播
我們知道LoadedApk這個類代表了一個加載到內(nèi)存中的應(yīng)用程序熔号,它里邊保存了一個應(yīng)用程序的基本資源信息稽鞭,包括ActivityThread,ApplicationInfo,包名引镊,資源路徑朦蕴,Lib路徑等信息篮条,它同時還保存了所有注冊的廣播的信息。
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
這個mReceivers中以Context為鍵值保存了一個Map類型的信息ArrayMap<BroadcastReceiver, ReceiverDispatcher>吩抓,一個Context代表了一個Activity或者一個Service涉茧,因為Activity和Service最終都實現(xiàn)了Context。以Context為鍵值查找的時候可以直接找到某個Activity或者Service中注冊的所有廣播接收者疹娶。
接著看ArrayMap<BroadcastReceiver, ReceiverDispatcher>伴栓,這個是以BroadCastReceiver為鍵值保存了一個ReceiverDispatcher的值,主要是為了將BroadcastReceiver和一個ReceiverDispatcher關(guān)聯(lián)起來雨饺。
首先我們來看下LoadedApk.ReceiverDispatcher這個類具體是什么作用钳垮。
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;
}
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
……
}
}
//一個Binder類型的對象,實現(xiàn)了Binder的服務(wù)端
final IIntentReceiver.Stub mIIntentReceiver;
//指向一個BoradCastReceiver
final BroadcastReceiver mReceiver;
//指向發(fā)送者的Context上下文信息
final Context mContext;
//指向發(fā)送者進程主線程的Hander對象沛膳,通過它可以向主線程發(fā)送消息
final Handler mActivityThread;
final Instrumentation mInstrumentation;
……
Receiver這個類中保存了一些變量扔枫,分別指向了發(fā)送者的一些信息,其中InnerReceiver類型的變量最重要锹安,它實現(xiàn)了IIntentReceiver.Stub短荐,是一個Binder類型的本地對象,屬于Binder服務(wù)端叹哭。
這個類的主要作用就是忍宋,把Binder對象通過進程間傳遞出去,其他進程要和這邊的Receiver通信的時候风罩,直接調(diào)用該Binder的代理端糠排,這邊的InnerReceiver就可以接收到消息,然后在通過主線程的Handler對象發(fā)送個主線程來處理這個消息超升。
接著看LoadedAPk.getReceiverDispatcher方法的實現(xiàn)入宦。
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) {
//根據(jù)當(dāng)前的Context,查找關(guān)于這個Activity或者Service注冊的所有廣播接收者信息
map = mReceivers.get(context);
if (map != null) {
//找到這個廣播接收者關(guān)聯(lián)的一個Binder服務(wù)端對象
rd = map.get(r);
}
}
if (rd == null) {
//如果LoadedApk中沒有保存的話室琢,就先創(chuàng)建一個乾闰,然后保存的LoadedAPk的mReceivers集合中
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();
}
}
根據(jù)前面方法的分析看出,這個方法的作用是用來在LoadedApk中查找這個廣播接收者關(guān)聯(lián)的Binder對象的盈滴。如果有則直接返回涯肩,如果找不到則new一個ReceiverDispatcher對象,保存到mReceivers集合中巢钓,然后再返回Receiver關(guān)聯(lián)的Binder對象病苗。
2. AMS.registerReceiver
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
int callingUid;
int callingPid;
synchronized(this) {
if (caller != null) {
//獲取調(diào)用注冊程序的進程信息和Uid,Pid
callerApp = getRecordForAppLocked(caller);
……
callingUid = callerApp.info.uid;
callingPid = callerApp.pid;
}
userId = handleIncomingUser(callingPid, callingUid, userId,
true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
Iterator<String> actions = filter.actionsIterator();
……
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
//查詢所有的Action相關(guān)的粘性廣播症汹,并保存到stickyIntents中
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
ArrayList<Intent> intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList<Intent>();
}
stickyIntents.addAll(intents);
}
}
}
}
}
……
synchronized (this) {
//根據(jù)注冊進程傳入的binder對象從mRegisteredReceivers查找對應(yīng)的ReceiverList
//mRegisteredReceivers列表硫朦,以注冊進程傳入的receiver.asBinder為key,保存了ReceiverList
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
//如果第一次調(diào)用則new一個ReceiverList,并添加到mRegisteredReceivers列表中
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
rl.app.receivers.add(rl);
} else {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
……
//創(chuàng)建一個BroadCastReceiver對象并保存到ReceiverList中,BroadcastFilter表示廣播的過濾條件背镇,一個廣播接收者可以有多個過濾條件
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
//同時也保存到mReceiverResolve列表中阵幸,這個列表保存了系統(tǒng)中所有動態(tài)注冊的廣播接收者所對應(yīng)的BroadCastFilter
mReceiverResolver.addFilter(bf);
// Enqueue broadcasts for all existing stickies that match
// this filter.
if (allSticky != null) {
……
final int stickyCount = allSticky.size();
for (int i = 0; i < stickyCount; i++) {
//遍歷所有符合條件的stick廣播Intent花履,然后把它封裝成一個BroadcastRecord并添加到BroadcastQueue的ParallelBroadcastLocked列表
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
該方法的主要工作:
- 獲取調(diào)用程序的進程信息ProcessRecord及PID和Uid
- 從AMS的mStickyBroadcasts列表中查詢所有和action匹配的sticky廣播芽世,并保存到allSticky列表中挚赊,該Action就是即將要注冊的廣播的Action。
- 我們知道參數(shù)receiver是一個IIntentReceiver類型的變量济瓢,是binder代理端荠割,指向了應(yīng)用進程要注冊的廣播Receiver,registerdReceivers是一個map類型的變量旺矾,它以receiver.asBInder為key保存了ReceiverList蔑鹦。這樣應(yīng)用進程的一個Receiver就和AMS服務(wù)中的一個ReceiverList關(guān)聯(lián)起來了。
ReceiverList又是什么呢箕宙? 它繼承自ArrayList<BroadCastFilter>嚎朽,同時它內(nèi)部有一個IntentReceiver類型的變量指向一個Receiver,這樣一個Receiver就和多個BroadcastFilter關(guān)聯(lián)起來了柬帕。因為一個廣播可以有多個過濾條件哟忍。
第三步的主要工作就是從mRegisterReceivers中查找receiver對應(yīng)的ReceiverList信息,如果為空陷寝,就表示該廣播沒有注冊锅很,需要新創(chuàng)建一個ReceiverList并添加到mRegisterReceivers列表中。
- 創(chuàng)建一個BroadcastFilter凤跑,添加到上面的ReceiverList中爆安,同時也添加到mReceiverResolver集合中,mReceiverResolver集合存儲了所有動態(tài)注冊的廣播的過濾條件BroadcastFilter仔引,便于廣播發(fā)送的時候查找Receiver扔仓。
- 將第二步找到的和此接收者Action相關(guān)的sticky廣播遍歷,封裝成一個BroadcastRecord咖耘,加入隊列準(zhǔn)備發(fā)送翘簇。
3. BroadCastQueue. scheduleBroadcastsLocked
public void scheduleBroadcastsLocked() {
//發(fā)送Handler消息個AMS服務(wù),通知AMS服務(wù)發(fā)送廣播
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
最終調(diào)用scheduleBroadcastsLocked方法鲤看,發(fā)送一個Hander消息給AMS服務(wù)缘揪,由AMS服務(wù)來發(fā)送廣播。
同時也了解了sticky廣播的實現(xiàn)原理义桂,發(fā)送完的sticky廣播會保存到mStickyBraodcasts集合中找筝,在注冊的時候根據(jù)action查找對應(yīng)的sticky廣播,如有有相關(guān)的sticky廣播的話慷吊,注冊完成后袖裕,立刻發(fā)送出去,這樣剛注冊的Receiver就可以立刻受到sticky的廣播了
這樣廣播的動態(tài)注冊就完成了溉瓶。經(jīng)過分析可以看出急鳄,AMS服務(wù)是廣播的注冊中心谤民,廣播接收者要想接收廣播消息需要將自己注冊到AMS服務(wù)中去,指定要接收的廣播類型疾宏,發(fā)送廣播也是首先發(fā)送給AMS服務(wù)张足,由AMS服務(wù)來找到對應(yīng)的廣播接收者,然后在調(diào)用對應(yīng)的廣播接收者來處理坎藐。
Broadcast的發(fā)送過程分析
廣播的發(fā)送方式分為有序廣播和無序廣播为牍,在注冊廣播的時候可以指定廣播的優(yōu)先級,這樣廣播就會優(yōu)先發(fā)送給優(yōu)先級比較高的廣播岩馍,然后才會發(fā)送給優(yōu)先級比較低的廣播碉咆。而無序廣播則不管廣播接收者的優(yōu)先級。
同樣要分析廣播的發(fā)送過程需要從ContextImpl類開始分析蛀恩,因為它最終實現(xiàn)了sendBroadcast的接口和方法疫铜,service和activity發(fā)送廣播的過程都是調(diào)用ContextImpl的方法來實現(xiàn)的。
1. ContextImpl.sendBroadcast
public void sendBroadcast(Intent intent) {
……
try {
intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
}
}
ContextImpl的發(fā)送廣播的方法最終通過進程間通信請求双谆,調(diào)用AMS服務(wù)的broadcastIntent方法壳咕。同時在參數(shù)中將發(fā)送者的ApplicationThread和廣播的intent傳遞給了AMS服務(wù)。
這個方法比較簡單佃乘,進程間通信方式不再解釋囱井,我們直接看AMS服務(wù)的broadcastIntent方法
2. AMS.broascastIntent
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle options,
boolean serialized, boolean sticky, int userId) {
……
synchronized(this) {
//驗證Intent信息
intent = verifyBroadcastLocked(intent);
//獲取調(diào)用進程的信息ProcessRecord
final ProcessRecord callerApp = getRecordForAppLocked(caller);
//獲取調(diào)用應(yīng)用的uid和pid
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
//通過broadcastIntentLocked方法來繼續(xù)處理發(fā)送廣播的邏輯
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, null, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
這個方式實現(xiàn)也是比較簡單,獲取調(diào)用進程的ProcessRecord信息和調(diào)用程序的UID和PID趣避,然后直接調(diào)用broadcastIntentLocked方法來繼續(xù)處理發(fā)送廣播的邏輯
3. AMS.broadcastIntentLocked
這個方法比較長庞呕,我們一部分一部分的來看
intent = new Intent(intent);
//確保要接收的廣播的用戶仍然存在,否則的話直接返回錯誤信息
if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
if ((callingUid != Process.SYSTEM_UID
|| (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
Slog.w(TAG, "Skipping broadcast of " + intent
+ ": user " + userId + " is stopped");
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}
//如果當(dāng)前的廣播類型是sticky廣播程帕,則把廣播添加到List列表中去
if (sticky) {
//首先檢查相關(guān)的權(quán)限信息
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
callingPid, callingUid)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
+ callingPid + ", uid=" + callingUid
+ " requires " + android.Manifest.permission.BROADCAST_STICKY;
……
if (userId != UserHandle.USER_ALL) {
//如果這個廣播不是發(fā)送給所有用戶的住练,則檢查發(fā)送給所有用戶的廣播中是否包含這個廣播,如果包含則和發(fā)送給所有用戶的廣播有沖突愁拭,拋出異常信息
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++) {
if (intent.filterEquals(list.get(i))) {
throw new IllegalArgumentException(
"Sticky broadcast " + intent + " for user "
+ userId + " conflicts with existing global broadcast");
}
}
}
}
}
//找到和這個用戶相關(guān)的所有的sticky廣播的信息
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
if (stickies == null) {
stickies = new ArrayMap<>();
mStickyBroadcasts.put(userId, stickies);
}
//從得到的廣播信息中讲逛,找到和當(dāng)前要發(fā)送廣播action相同的sticky廣播
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list == null) {
list = new ArrayList<>();
stickies.put(intent.getAction(), list);
}
//遍歷拿到的stick廣播信息,如果已經(jīng)存在岭埠,則更新替換掉他
//如果不存在盏混,則添加進去
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));
}
}
參數(shù)sticky用來描述要發(fā)送的廣播是否是一個sticky類型的廣播,如果是惜论,就需要對sticky廣播進行一些處理许赃,在前面我們分析過,在注冊廣播的時候馆类,如果AMS中保存了對應(yīng)action類型的sticky廣播混聊,則直接將保存的sticky廣播發(fā)送出去。那些sticky廣播是如何保存到AMS服務(wù)中去的呢乾巧?
代碼邏輯就是在這邊處理的句喜,在注冊一個廣播的時候预愤,如果它是sticky類型的廣播,就直接將它保存在AMS服務(wù)的mStickyBroadcasts集合中咳胃。
首先從AMS系統(tǒng)服務(wù)中查詢Action相關(guān)的sticky廣播植康,然后遍歷,如果該sticky廣播已經(jīng)在AMS中注冊保存了拙绊,則用新的Sticky廣播替換掉它向图,否則直接添加到列表中去。
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
//如果沒有FLAG_RECEIVER_REGISTERED_ONLY標(biāo)簽标沪,說明不是發(fā)送給動態(tài)注冊的廣播的,那么調(diào)用collectReceiverComponents嗜傅,查找所有和該Intent相關(guān)的廣播接收者
//保存到receivers列表中
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
//如果沒有指定特定的廣播接收者金句,則查找所用的動態(tài)注冊的廣播接收者的信息
if (intent.getComponent() == null) {
……
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false, userId);
}
}
第二部分的主要處理邏輯就是查找和intent相關(guān)的廣播接收者。我們知道廣播注冊的時候有兩種注冊方法吕嘀,一種是靜態(tài)注冊方法违寞,在Manifest文件中注冊,另一種是動態(tài)注冊方法偶房,在代碼中調(diào)用registerBroadcast方法來注冊廣播趁曼。
這個地方進行了兩次查找,判斷發(fā)送廣播的intent的標(biāo)簽棕洋,如果不是僅僅發(fā)送給動態(tài)注冊的廣播的時候挡闰,就調(diào)用collectReceiverComponents方法查詢所有Intent感興趣的廣播接收者,這里僅僅去PMS服務(wù)中查詢了感興趣的靜態(tài)注冊的廣播接收者掰盘,保存在receivers列表中摄悯。
然后判斷這個廣播是否指定了值發(fā)送給特定的廣播接收者,如果沒有指定的話愧捕,默認發(fā)送給所有感興趣的廣播接收者奢驯,這時候再去查詢一次,這次查詢的是所有對這個Intent感興趣的動態(tài)注冊的廣播接收者次绘,保存在registeredReceivers列表中瘪阁。
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
//如果當(dāng)前不是有序廣播,且動態(tài)注冊的感興趣的廣播不為0邮偎,將廣播intent封裝為一個BroadcastRecord
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
resultExtras, ordered, sticky, false, userId);
……
//發(fā)送該廣播給動態(tài)注冊的廣播接收者
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
//發(fā)送完成后管跺,將registeredReceivers 置為 null
registeredReceivers = null;
NR = 0;
}
第三部分的處理工作:
如果當(dāng)前發(fā)送的廣播不是有序廣播,且動態(tài)注冊的廣播接收者>0钢猛,此時則需要把這個廣播優(yōu)先發(fā)送給動態(tài)注冊的廣播接收者伙菜,為什么不和靜態(tài)注冊的廣播一起發(fā)送,卻要分開發(fā)送呢命迈?這樣做是因為贩绕,動態(tài)注冊的廣播接收者一般情況下都已經(jīng)運行起來了火的,而靜態(tài)注冊的廣播接收者只是在Manifest文件中注冊,要想接收廣播必須要等待要接收的組件啟動起來才可淑倾,所以這邊處理選擇分開發(fā)送馏鹤,優(yōu)先發(fā)送動態(tài)注冊的廣播接收者。
發(fā)送的廣播的時候娇哆,無序廣播都添加到了mParallelBroadcats隊列中湃累,具體發(fā)送的處理邏輯后邊在詳細分析。
下一步處理發(fā)送給靜態(tài)注冊的廣播接收者的邏輯碍讨。
int ir = 0;
//感興趣的靜態(tài)注冊廣播接收者不為空
if (receivers != null) {
//首先對于特殊的ACTION_PACKAGE_ADDED的廣播需要特殊處理
//這樣是為了防止一些應(yīng)用則安裝完成之后監(jiān)聽到package_add的廣播就立刻運行
//所以要把它已標(biāo)記起來治力,以后從廣播接收者信息中移除
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 };
}
}
//同樣,如果Intenty有ACTION_EXTERNAL_APPLICATIONS_AVAILABLE標(biāo)簽勃黍,則同樣移除
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
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)) {
receivers.remove(it);
it--;
NT--;
}
}
}
}
處理靜態(tài)注冊的廣播接收者邏輯的時候宵统,首先判斷該廣播事件是否是Package_add的廣播事件,如果是的話覆获,需要從廣播接收者列表中移除马澈,這樣為了防止一些毒瘤應(yīng)用在安裝完成后接收到package_add廣播就立刻運行。
int NT = receivers != null ? receivers.size() : 0;
int it = 0;
ResolveInfo curt = null;
BroadcastFilter curr = null;
//上面的無序廣播處理后弄息,把mRegisterReceivers列表置為null痊班,并且把NR設(shè)置成了0
//而此時要想滿足此處條件,NR不為0摹量,說明此處是有序廣播的處理邏輯
//遍歷動態(tài)注冊的廣播和靜態(tài)注冊的廣播涤伐,安priority值排序合并放到receivers列表中
while (it < NT && ir < NR) {
if (curt == null) {
curt = (ResolveInfo)receivers.get(it);
}
if (curr == null) {
curr = registeredReceivers.get(ir);
}
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;
}
}
……
//有序廣播接收者不為空,發(fā)送有序廣播
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
+ ": prev had " + queue.mOrderedBroadcasts.size());
if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
"Enqueueing broadcast " + r.intent.getAction());
boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
此處處理邏輯主要為有序廣播的處理邏輯荆永。
在前面的分析中知道废亭,如果是無序廣播的時候,動態(tài)注冊的廣播接收者就直接處理了具钥,然后把mRegisteredReceivers列表置為了null豆村,所以在有序廣播的時候就不會有動態(tài)注冊的廣播接收者合并進來。此時就會把靜態(tài)廣播放到有序廣播類別mOrderedBroadcasts隊列中發(fā)送骂删。為什么會把靜態(tài)注冊的廣播接收和按照有廣播的邏輯來發(fā)送呢掌动?有序廣播發(fā)送的處理邏輯是發(fā)送完成一個在發(fā)送另一個,而無序廣播是直接循環(huán)發(fā)送出去宁玫,靜態(tài)注冊的廣播接收者的進程不一定已經(jīng)運行起來了粗恢,在發(fā)送的過程中可能需要先啟動進程,這樣很消耗資源欧瘪,所以一個一個發(fā)送會好一點眷射。
如果發(fā)送的是有序廣播,動態(tài)注冊的廣播在前面邏輯中則不會處理,此處就會把動態(tài)注冊的廣播和靜態(tài)注冊的廣播按照priority值排序妖碉,然后合并到receivers列表中涌庭。
最終把receiver列表中的廣播接收者封裝成一個BroadcastRecord對象放到mOrderedBroadcasts隊列中進行發(fā)送。
此處邏輯可以總結(jié)出來欧宜,如果是無序廣播的話坐榆。動態(tài)注冊的廣播接收者會比靜態(tài)注冊的廣播者優(yōu)先收到廣播
下面我們來分析具體的廣播發(fā)送處理邏輯:
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId);
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
對于BroadCast的發(fā)送的處理邏輯大體上分為以上幾個步驟
- 根據(jù)廣播的Intent找到對應(yīng)的廣播隊列
- 將Intent和廣播接收者封裝成一個BroadcastRecord對象
- 將BroadcastRecord對象添加拿到queue隊列中
- 調(diào)用queue的scheduleBroadcastsLocked方法發(fā)送廣播
4. AMS. broadcastQueueForIntent
BroadcastQueue broadcastQueueForIntent(Intent intent) {
final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}
這個方法很簡單,就是根據(jù)Intent中是否有Flag_Receiver_foreground標(biāo)簽冗茸,來決定添加到那個隊列中去席镀。
這個標(biāo)簽是什么作用呢?看下SDK中的描述:
FLAG_RECEIVER_FOREGROUND 接受器以前臺優(yōu)先級運行
If set, when sending a broadcast the recipient is allowed to run at foreground priority, with a shorter timeout interval. During normal broadcasts the receivers are not automatically hoisted out of the background priority class.
廣播默認都是后臺優(yōu)先級夏漱,如果廣播中添加了這個標(biāo)簽就會以前臺優(yōu)先級運行豪诲,發(fā)送到接收到廣播的時間間隔會更短。
也就是說麻蹋,默認廣播都是天劍到mBgBroadcastQueue隊列中去的跛溉,只有廣播添加了這個標(biāo)簽后,才會被添加到mFgBroadcastQueue隊列中扮授。這兩個隊列中處理邏輯的區(qū)別我們后面再詳細分析。
第二步专肪,將Intent和廣播接收者隊列封裝成了一個BroadcastRecord對象刹勃,也就是說每一個廣播在AMS都是對應(yīng)一個BroadcastRecord對象的。
5. BroadcastQueue. Enqueue……BroadcastLocked
BroadcastQueue中有兩個添加隊列的方法:
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
mParallelBroadcasts.add(r);
r.enqueueClockTime = System.currentTimeMillis();
}
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
mOrderedBroadcasts.add(r);
r.enqueueClockTime = System.currentTimeMillis();
}
該消息發(fā)送了了一個Handler消息嚎尤,有Hander的handleMessage來處理荔仁,最終調(diào)用了processNextBroadcast方法來處理。
7. BroadcastQueue. processNextBroadcast
動態(tài)注冊廣播接收者的處理邏輯
這個方法有點復(fù)雜芽死,主要是兩種廣播的處理邏輯不一樣乏梁,那我們就先分析動態(tài)注冊的廣播接收者處理邏輯,然后在分析靜態(tài)注冊或者有序廣播的處理邏輯关贵。
我們在前面講過遇骑,動態(tài)注冊的廣播接收者處理的時候是一次性的循環(huán)發(fā)送完國有廣播,而靜態(tài)注冊或者有序廣播則是一個發(fā)送完成在發(fā)送另一個揖曾。
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
BroadcastRecord r;
……
while (mParallelBroadcasts.size() > 0) {
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++) {
Object target = r.receivers.get(i);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
addBroadcastToHistoryLocked(r);
}
動態(tài)廣播的處理邏輯是在processNextBroadcast方法的開始處理的落萎,變量mParallelBroadcasts列表,從列表開始位置一次拿到保存的BroadcastRecord對象炭剪,每個BroadcastRecord中可能對應(yīng)多個廣播接收者练链,依次遍歷廣播接收者,然后調(diào)用deliverToRegisteredReceiverLocked方法發(fā)送廣播
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered) {
boolean skip = false;
//檢查是否具有相關(guān)權(quán)限传泊,沒有權(quán)限則skip = true 表示跳過這個廣播接收者
……
//檢查接收廣播的進程是否存在逼庞,如果接收廣播的進程不存在則跳過這個廣播接收者霸妹,不向它發(fā)送該廣播
if (filter.receiverList.app == null || filter.receiverList.app.crashing) {
Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
+ " to " + filter.receiverList + ": process crashing");
skip = true;
}
if (!skip) {
if (ordered) {
//有序廣播處理邏輯
}
try {
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
……
}
}
}
我們只關(guān)心和我們處理邏輯相關(guān)的關(guān)鍵代碼规辱。
檢查相關(guān)的權(quán)限绿鸣,如果沒有權(quán)限則skip設(shè)置為true,
檢查廣播接收者對應(yīng)的進程是否存在疚沐,如果不存在skip設(shè)置為true
我們目前是無序廣播,所以ordered為false,最終調(diào)用performReceiveLocked方法來處理枚驻。
我么回憶下ReceiverList是什么濒旦,ReceiverList是我們在注冊廣播接收者的時候,一個廣播接收者的代表信息再登,它繼承者ArrayList<BroadcastFilter>尔邓,這樣可以實現(xiàn)一對多的數(shù)據(jù)結(jié)構(gòu),因為一個廣播接收者可能對應(yīng)多個BroadcastFilter锉矢。所以receiverList.app代表了廣播接收者所在的進程梯嗽,receiverList.receiver則是一個Binder對象,指向了App進程中的一個InnerReceiver的對象沽损。
繼續(xù)看performReceiveLocked方法如何處理灯节。
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
if (app != null) {
if (app.thread != null) {
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
參數(shù)receiver是一個IIntentReceiver接口的Binder代理對象,它的服務(wù)端是應(yīng)用進程的InnerReceiver绵估,參數(shù)app則是接收廣播的應(yīng)用進程的進程對象ProcessRecord炎疆,在注冊廣播接收者的時候,我們知道在創(chuàng)建廣播接收者對應(yīng)的ReceiverList對象的時候會初始化app的值国裳。
ReceiverList rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver);
一般情況下receiver的變量app都是不為null的形入,所以大部分情況下廣播都是通過應(yīng)用進程的ApplicationThread對象的Binder代理對象,通過進程間調(diào)用缝左,將這個廣播發(fā)送到應(yīng)用進程主線程來處理亿遂,應(yīng)用進程的主線程再調(diào)用對應(yīng)的receiver來處理。而不是直接通過Receiver的Binder代理端來進行進程間的調(diào)用渺杉。
接著看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 {
updateProcessState(processState, false);
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
此時直接調(diào)用receiver的performReceive方法,receiver是一個binder類型的代理對象是越,這個方法調(diào)用最終調(diào)用到InnerReceiver的performReceiver方法中耳舅。
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
//得到當(dāng)前的dispatcher
LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
}
……
}
這個方法很簡單,首先得到對應(yīng)的dispatcher英妓,然后調(diào)用dispatcher的方法來處理挽放。
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 (mRegistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
args.sendFinished(mgr);
}
}
}
mActivityThread是一個Handler對象,該對象指向ActivityThread的Hander對象蔓纠,Handler的post最終調(diào)用了Args的run方法辑畦。
final class Args extends BroadcastReceiver.PendingResult implements Runnable {
……
public void run() {
final BroadcastReceiver receiver = mReceiver;
……
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
}
……
}
}
變量receiver指向了一個廣播接收者BroadcastReceiver,然后調(diào)用receiver.onReceive()方法腿倚。到此動態(tài)注冊的廣播接收者接收廣播的邏輯就處理完成了纯出。
下一步看靜態(tài)注冊或者有序廣播的發(fā)送邏輯。
靜態(tài)注冊或者有序廣播接收者的處理邏輯
我們再回到processNextBroadcast方法中,接著往下看
//判斷當(dāng)前是否正在等待靜態(tài)注冊的廣播接收者控件啟動并接收任務(wù)
if (mPendingBroadcast != null) {
boolean isDead;
synchronized (mService.mPidsSelfLocked) {
ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.crashing;
}
if (!isDead) {
//如果有個任務(wù)正在啟動則直接返回繼續(xù)等待
return;
}
}
boolean looped = false;
do {
//從mOrderedBroadcasts列表中獲取下一個要發(fā)送的廣播
r = mOrderedBroadcasts.get(0);
boolean forceReceive = false;
//判斷有序廣播是否發(fā)送超時暂筝,如果發(fā)送超時則直接強制停止發(fā)送這個廣播
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
if (mService.mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
broadcastTimeoutLocked(false); //強制停止這個廣播
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
……
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
//如果這個廣播接收者receivers已經(jīng)處理完了箩言,或者這個廣播已經(jīng)強制停止了
if (r.resultTo != null) {
……
}
//從Handler延時消息中移除timeout的消息
cancelBroadcastTimeoutLocked();
//添加到history中
addBroadcastToHistoryLocked(r);
//從mOrderedBroadcasts列表中移除
mOrderedBroadcasts.remove(0);
//置為null
r = null;
looped = true;
continue;
}
} while (r == null);
首先判斷mPendingBroadcast是不是為空,這個mPendingBroadcast的作用是什么呢焕襟?
我們知道陨收,mOrderedBroadcast中保存的廣播接收者都是需要一個發(fā)送完成另一個才可以發(fā)送的。其中靜態(tài)注冊的廣播接收者有可能對應(yīng)的進程還未啟動鸵赖,者就需要首先來啟動該進程务漩。如果是這種情況的話mPendingBroadcast就是描述了一個正在等待靜態(tài)注冊的對應(yīng)進程啟動的廣播。
如果他不為空它褪,說明當(dāng)前有任務(wù)正在處理饵骨,在對這個正在啟動的進程檢查之后就直接退出了。
如果mPendingBroadcast不為空茫打,AMS就會繼續(xù)等待居触,否則的話就會準(zhǔn)備處理mOrderedBroadcast的下一個廣播。
接下來是一個while循化老赤,主要工作是從mOrderedBroadcasts列表中找到下一個要處理的廣播轮洋,退出條件是 r != null,即找到下一個合適的廣播。
1.首先從列表的開始拿出第一個BroadcastRecord抬旺,第一個有可能是正在處理的廣播砖瞧,判斷他是否已經(jīng)開始分發(fā)廣播,如果開始但是已經(jīng)超時嚷狞,則直接強制停止這個廣播。
2.然后荣堰,判斷這個廣播是否已經(jīng)處理完成床未,或者是否強制停止,然后直接停止該廣播振坚。
3.將發(fā)送給AMS的關(guān)于超時的延時消息移除
4.將第一個廣播移除掉薇搁,并把r設(shè)置為null,表示沒有找到合適的廣播渡八,然后繼續(xù)循環(huán)查找啃洋,知道找到下一個合適的廣播,退出循環(huán)屎鳍。
//獲取下一個要執(zhí)行的Receiver信息
int recIdx = r.nextReceiver++;
r.receiverTime = SystemClock.uptimeMillis();
//如果recIdx = 0宏娄,說明這個廣播的才剛開始發(fā)送廣播任務(wù),則記錄下當(dāng)前的時間為分發(fā)廣播的時間
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
}
if (! mPendingBroadcastTimeoutMessage) {
//向AMS的handler發(fā)送一個延時的超時消息逮壁,到超時的時間后自動發(fā)送
long timeoutTime = r.receiverTime + mTimeoutPeriod;
setBroadcastTimeoutLocked(timeoutTime);
}
……
final Object nextReceiver = r.receivers.get(recIdx);
if (nextReceiver instanceof BroadcastFilter) {
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
deliverToRegisteredReceiverLocked(r, filter, r.ordered);
return;
}
我們知道一個廣播可能對應(yīng)多個廣播接收者孵坚,在mOrderedBroadcasts列表處理的時候是需要向一個Receiver發(fā)送成功后,在向另一個發(fā)送。BroadcastRecord的變量nextReceiver表示下一個廣播接收者的序號卖宠。
如果為0巍杈,說明這個廣播的廣播接收者一個都沒有發(fā)送,也就是說這個廣播才剛開始發(fā)送扛伍,此時就要記錄下當(dāng)前廣播分發(fā)的時間筷畦,然后計算下超時時間然后向AMS服務(wù)發(fā)送一個延時消息。接著刺洒,獲取到下一個Receiver鳖宾,判斷它是否是BroadcastFilter類型,如果是作媚,然后調(diào)用deliverToRegisteredReceiverLocked方法來處理攘滩,我們在動態(tài)注冊的廣播處理的時候已經(jīng)分析過這個方法了,這邊不再討論纸泡。
ResolveInfo info =
(ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
//判斷權(quán)限相關(guān)及其他來覺是否跳過這個廣播接收者
boolean skip = false;
int perm = mService.checkComponentPermission(info.activityInfo.permission,
……
//判斷這個廣播接收者對應(yīng)的進程是否已經(jīng)啟動
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid, false);
if (app != null && app.thread != null) {
//如果已經(jīng)啟動則發(fā)送廣播給當(dāng)前的廣播接收者
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
processCurBroadcastLocked(r, app);
return;
}
……
}
//否則的話則新建一個進程漂问,并把mPendingBroadcast設(shè)置為當(dāng)前的廣播接收者,等待新進程啟動完成
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) {
……
}
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
廣播接收者分為兩種類型女揭,動態(tài)注冊和靜態(tài)注冊蚤假,靜態(tài)注冊的廣播是ResolveInfo類型,所以此處主要來處理靜態(tài)注冊的廣播接收者發(fā)送廣播的邏輯吧兔。
1.首先磷仰,判斷相關(guān)的權(quán)限及其他信息來決定是否可以發(fā)送廣播給這個廣播接收者
2.如果可以,查詢廣播接收者對應(yīng)的進程是否存在境蔼,如果已經(jīng)存在灶平,直接 調(diào)用processCurBroadcastLocked方法來處理當(dāng)前廣播
如果不存在,則啟動一個新的進程箍土,將mPendingBroadcast的值設(shè)置為當(dāng)前的BroadcastRecord的值逢享,然后等待新的進程啟動完成。
后邊發(fā)送的過程和動態(tài)注冊的廣播mParallelBroadcasts列表處理邏輯一致吴藻,不再詳細介紹瞒爬。由于mOrderedBroadcasts列表中的廣播是一個處理完成在處理另一個,那我們看下發(fā)送廣播給receiver后沟堡,如何處理的侧但。
在前面分析過,Args的run方法中最終調(diào)用了BroadcastReceiver的onReceive方法航罗,在調(diào)用完receiver方法后會調(diào)用AMS的finishReceiver方法禀横。其實不僅僅是這個地方調(diào)用了finishReceiver方法,在發(fā)送失敗等情況下也會調(diào)用伤哺。
IActivityManager mgr = ActivityManagerNative.getDefault();
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
AMS的finishReceiver方法中則會繼續(xù)處理后續(xù)的廣播接收者的發(fā)送或者調(diào)用processNextBroadcast方法燕侠,繼續(xù)執(zhí)行下一個廣播的發(fā)送者祖。
到此為止廣播的發(fā)送過程也就簡單的分析完了。從分析過程中可以看出AMS服務(wù)具體是如何管理Broadcast廣播绢彤。