重點(diǎn)分析流程西雀,而不陷于代碼,可以照著流程再細(xì)看。
一歉摧、廣播注冊
//客戶端注冊廣播的例子
mBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.broadcast.test");
registerReceiver(mBroadcastReceiver, intentFilter);
registerReceiver其實(shí)是ContexImpl來調(diào)用的蒋搜,走過幾個類似重載的registerReceiver方法,最終來到registerReceiverInternal方法判莉。在registerReceiverInternal里構(gòu)建出ReceiverDispatcher,ReceiverDispatcher具有跨進(jìn)程的binder內(nèi)部類IIntentReceiver育谬,然后交給ActivityManagerService的registerReceiver方法去完成注冊券盅。ActivityManagerService用 mRegisteredReceivers存儲注冊的動態(tài)廣播,
/**
* Keeps track of all IIntentReceivers that have been registered for broadcasts.
* Hash keys are the receiver IBinder, hash value is a ReceiverList.
*/
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
key為注冊的receiver膛檀,value為ReceiverList锰镀,ReceiverList為ArrayList<BroadcastFilter>列表,而BroadcastFilter extends IntentFilter 咖刃,當(dāng)發(fā)送廣播后找匹配的receiver時泳炉,通過IntentFilter匹配,找動態(tài)注冊的BroadcastFilter嚎杨。 下面幾句表示的BroadcastReceiver存儲的方式:
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId);
rl.add(bf);
mReceiverResolver.addFilter(bf);
上面注意最后一句花鹅,mReceiverResolver的作用是什么呢?見源碼,下一節(jié)分析枫浙。
/**
* Resolver for broadcast intents to registered receivers.
* Holds BroadcastFilter (subclass of IntentFilter).
*/
final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
= new IntentResolver<BroadcastFilter, BroadcastFilter>() {
二刨肃、發(fā)送廣播
//發(fā)送廣播的例子
Intent intent = new Intent();
intent.setAction("android.broadcast.test");
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
//sendBroadcast(intent);
sendOrderedBroadcast(intent, null);
客戶端的sendBroadcast最終會走到ActivityManagerService的broadcastIntentLocked,前面很多代碼是權(quán)限之類的檢查箩帚,忽略掉真友,重點(diǎn)分析怎么發(fā)送。因?yàn)榇嬖趧討B(tài)廣播和靜態(tài)廣播紧帕,所以檢查sendBroadcast的Intent是不是只有動態(tài)廣播receiver可以接收盔然,通過下面這句,如果不只是動態(tài)廣播receiver能接收,那就要也發(fā)送那些靜態(tài)注冊的receiver愈案。registeredReceivers是動態(tài)廣播接收器列表 挺尾,receivers是靜態(tài)廣播接收器列表。
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY ==0) {
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
還記得在廣播注冊最后的mReceiverResolver嗎刻帚?在這里派上用場潦嘶,registeredReceivers通過下面這句得到。
registeredReceivers = mReceiverResolver.queryIntent(intent,resolvedType, false, userId);
這樣就得到了符合能接收Intent的所有Receiver崇众。
下面要構(gòu)建一個BroadcastRecord對象掂僵,并入隊(duì)發(fā)送出去。首先的問題是入哪個隊(duì)列顷歌,有ActivityManagerService前臺和后臺兩個隊(duì)列锰蓬,如果發(fā)送的Intent有Intent.FLAG_RECEIVER_FOREGROUND就選前臺隊(duì)列,否則選后臺隊(duì)列眯漩。
前臺和后臺隊(duì)列又分別含有兩個列表mParallelBroadcasts和mOrderedBroadcasts對應(yīng)無序廣播和有序廣播芹扭。
最后發(fā)送時,調(diào)用
//無序廣播
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
//有序廣播
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
三赦抖、廣播的處理
scheduleBroadcastsLocked只是通過Handler發(fā)送一個消息BROADCAST_INTENT_MSG舱卡,Handler收到消息后調(diào)用processNextBroadcast,這里如果是無序廣播队萤,一次處理轮锥,走到deliverToRegisteredReceiverLocked,然后調(diào)用LoadedApk中ReceiverDispatcher的performReceive要尔,在里面構(gòu)造一個叫Args的Runnable舍杜,然后ActivityThread中的H這個Handler去post執(zhí)行。
這樣Runnable的run()方法執(zhí)行赵辕,走到了我們熟悉的onReceive回調(diào)既绩。
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
四、其他東西
以上簡單分析了廣播的整個流程还惠,中間很多細(xì)節(jié)的東西還需要精讀源碼分析饲握,比如有序廣播怎么處理的,靜態(tài)廣播怎么處理的蚕键。
下面列一些結(jié)論性的東西:
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
1.默認(rèn)動態(tài)注冊的廣播ANR時間為60S互拾,說明默認(rèn)動態(tài)注冊的廣播為后臺廣播。
2.無序廣播不會ANR嚎幸,有序廣播會ANR颜矿。但是廣播回調(diào)onReceive如果在主線程耗時,會出現(xiàn)ANR嫉晶,此ANR非廣播ANR骑疆,而是Activity的ANR田篇。
3.ActivityManagerService中有兩個BroadcastQueue,分別是mFgBroadcastQueue和mBgBroadcastQueue,對應(yīng)前臺廣播和后臺廣播箍铭,而每個BroadcastQueue中又含有兩個ArrayList<BroadcastRecord>泊柬,分別為mParallelBroadcasts和mOrderedBroadcasts,對應(yīng)并行廣播和有序廣播诈火。
4.ANR簡單流程如下兽赁,重點(diǎn)在函數(shù)processNextBroadcast:取得下一個有序廣播,Handler發(fā)送延遲ANR msg冷守,如果沒有TIMEOUT刀崖,Handler remove ANR msg,如果TIMEOUT,Handler執(zhí)行AppNotResponding這個Runnable拍摇。
//前臺廣播mTimeoutPeriod為10s亮钦,后臺廣播為60s,通過Handler發(fā)送BROADCAST_TIMEOUT_MSG
if (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
setBroadcastTimeoutLocked(timeoutTime);
}
//如果沒有timeout充活,將之前的BROADCAST_TIMEOUT_MSG取消掉
final void cancelBroadcastTimeoutLocked() {
if (mPendingBroadcastTimeoutMessage) {
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
mPendingBroadcastTimeoutMessage = false;
}
}
/*如果到了timeout時間蜂莉,還沒有取消BROADCAST_TIMEOUT_MSG,就會執(zhí)行這個混卵,
調(diào)用到broadcastTimeoutLocked映穗,最終通過Handler來post AppNotResponding這個Runnable*/
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
當(dāng)然還有個地方也會發(fā)生ANR,和Receiver的個數(shù)有關(guān)系,而且不是通過Handler來發(fā)生的幕随,當(dāng)發(fā)生Timeout時蚁滋,直接調(diào)用broadcastTimeoutLocked
//在processNextBroadcast方法里
if (mService.mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&(now > r.dispatchTime +
(2*mTimeoutPeriod*numReceivers))) {
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
5.設(shè)置 intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);這個flag后,廣播不會發(fā)送給已經(jīng)停止的應(yīng)用,系統(tǒng)默認(rèn)是不讓我們的廣播發(fā)送給已經(jīng)停止的應(yīng)用的合陵。