說說Android的廣播(4) - 前臺廣播為什么比后臺廣播快雨饺?

說說Android的廣播(4) - 前臺廣播為什么比后臺廣播快袭异?

前臺廣播為什么比后臺廣播快

討論超時的細(xì)節(jié)之前钠龙,我們先講講對應(yīng)用開發(fā)有幫助的,為什么前臺隊列比后臺隊列要快?
應(yīng)用開發(fā)的同學(xué)在給系統(tǒng)團(tuán)隊提意見的時候講碴里,說以前我們都是靠通過將廣播消息設(shè)成前臺廣播的方式來做workaround來解決一些廣播的性能問題的沈矿,你們系統(tǒng)為什么不能將后臺廣播做得跟前臺廣播一樣快呢?這一定是設(shè)計上的問題咬腋。

其實羹膳,這種前臺廣播的設(shè)計,就是為了加速廣播的性能而設(shè)計的根竿。二者在設(shè)計思想上就有不同陵像。根據(jù)應(yīng)用層實際的需求,決定使用前臺廣播還是后臺廣播犀填,本來就是應(yīng)用設(shè)計時候應(yīng)該考慮的問題。
當(dāng)然嗓违,Android的這個設(shè)計對應(yīng)用開發(fā)的要求比較高九巡,我看了一些Android的教程,也沒有講到這么細(xì)節(jié)的東西蹂季。系統(tǒng)還是應(yīng)該更智能一些冕广。

這里面主要有三點(diǎn)原因:

  1. 前臺隊列相對比較空閑
  2. 前臺隊列的超時時間是10s,而后臺是60s. 后臺廣播的設(shè)計思想就是當(dāng)前應(yīng)用優(yōu)先偿洁,盡可能多讓收到廣播的應(yīng)用有充足的時間把事件做完撒汉。而前臺廣播的目的是緊急通知,設(shè)計上就傾向于當(dāng)前應(yīng)用趕快處理完涕滋,盡快傳給下一個睬辐。
  3. 前臺隊列不等后臺服務(wù),而后臺隊列要多等后臺服務(wù)一定的時間宾肺。這還是設(shè)計思想上的原因溯饵。

比如我們舉個關(guān)機(jī)廣播的例子,寫應(yīng)用的同學(xué)可以參照這個例子來寫發(fā)送前臺廣播哈:

Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
        UserHandle.ALL, null, br, mHandler, 0, null, null);

比起普通廣播锨用,只是多加一個intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);就可以了丰刊。

不過,紙上得來終覺淺增拥,我們看下實際的代碼中是如何實現(xiàn)的吧啄巧。

廣播隊列的構(gòu)造

我們來看AMS中的構(gòu)造函數(shù)里,是如何為前臺隊列和后臺隊列配置參數(shù)的:

...
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
        "foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
        "background", BROADCAST_BG_TIMEOUT, true);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
...

我們可以看到有兩點(diǎn)不同:一個是超時時間不同掌栅,另一個是allowDelayBehindServices參數(shù)不同秩仆,前臺是false,就是不等待猾封,而后臺是true逗概,要等待。
我們來看看BroadcastQueue的構(gòu)造函數(shù):

BroadcastQueue(ActivityManagerService service, Handler handler,
        String name, long timeoutPeriod, boolean allowDelayBehindServices) {
    mService = service;
    mHandler = new BroadcastHandler(handler.getLooper());
    mQueueName = name;
    mTimeoutPeriod = timeoutPeriod;
    mDelayBehindServices = allowDelayBehindServices;
}

timeoutPeriod是超時時間,我們來看看前臺和后臺的超時時間是如何定義的:

// 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;

BroadcastRecord中的幾個時間點(diǎn)

既然是分析超時逾苫,我們先對BroadcastRecord中記錄的幾個時間點(diǎn)有個印象卿城。

long enqueueClockTime;  // the clock time the broadcast was enqueued
long dispatchTime;      // when dispatch started on this set of receivers
long dispatchClockTime; // the clock time the dispatch started
long receiverTime;      // when current receiver started for timeouts.
long finishTime;        // when we finished the broadcast.

其中最繞的是dispatchTime和dispatchClockTime,都是開始分發(fā)消息時的時間铅搓,它們有什么不同呢瑟押?

其實,它們的區(qū)別僅僅是計時方法不同:

r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();

其他的時間也都一樣星掰,凡是叫ClockTime的都是System.currentTimeMillis()多望,只叫Time的,就是SystemClock.uptimeMillis().

我們看下它們的實際賦值氢烘,加深一下印象:
ClockTime就這兩個:

r.enqueueClockTime = System.currentTimeMillis();
r.dispatchClockTime = System.currentTimeMillis();

非Clock的Time有三個:

r.dispatchTime = SystemClock.uptimeMillis();
r.receiverTime = SystemClock.uptimeMillis();
r.finishTime = SystemClock.uptimeMillis();

入隊列的時間

入隊列的邏輯我們在第三講中已經(jīng)分析過了怀偷,我們再復(fù)習(xí)一下:

214    public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
215        mParallelBroadcasts.add(r);
216        r.enqueueClockTime = System.currentTimeMillis();
217    }
218
219    public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
220        mOrderedBroadcasts.add(r);
221        r.enqueueClockTime = System.currentTimeMillis();
222    }

派發(fā)的時間

這就是剛才我們看到的同時記兩個時間點(diǎn)的那個,在processNextBroadcast中播玖,我們下講會專門分析這個大派發(fā)函數(shù):

先看對于并發(fā)隊列的派發(fā):

...
654            // First, deliver any non-serialized broadcasts right away.
655            while (mParallelBroadcasts.size() > 0) {
656                r = mParallelBroadcasts.remove(0);
657                r.dispatchTime = SystemClock.uptimeMillis();
658                r.dispatchClockTime = System.currentTimeMillis();
659                final int N = r.receivers.size();
...
662                for (int i=0; i<N; i++) {
663                    Object target = r.receivers.get(i);
...
667                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
668                }
669                addBroadcastToHistoryLocked(r);
...
672            }
...

后面還有針對串行隊列的椎工,也是兩個同時要賦值喲~

796            // Keep track of when this receiver started, and make sure there
797            // is a timeout message pending to kill it if need be.
798            r.receiverTime = SystemClock.uptimeMillis();
799            if (recIdx == 0) {
800                r.dispatchTime = r.receiverTime;
801                r.dispatchClockTime = System.currentTimeMillis();
...

receiver接收到的時間

這段邏輯也是在處理廣播消息的主循環(huán)processNextBroadcast函數(shù)中。
第一處就是剛才看到的位置

796            // Keep track of when this receiver started, and make sure there
797            // is a timeout message pending to kill it if need be.
798            r.receiverTime = SystemClock.uptimeMillis();

另一處是超時之后蜀踏,反正也不打算繼續(xù)等它了维蒙,就把超時那一刻的時間記錄成收到的時間吧。這段邏輯位于超時處理的函數(shù)broadcastTimeoutLocked中果覆。

1164        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r. receiver
1165                + ", started " + (now - r.receiverTime) + "ms ago");
1166        r.receiverTime = now;
1167        r.anrCount++;

廣播處理結(jié)束的時間

這個省事了颅痊,只在一處出現(xiàn),就是修史書的時候局待,具體的函數(shù)是addBroadcastToHistoryLocked.

1221    private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
...
1226        r.finishTime = SystemClock.uptimeMillis();
1227
1228        mBroadcastHistory[mHistoryNext] = r;
1229        mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY);
1230
1231        mBroadcastSummaryHistory[mSummaryHistoryNext] = r.intent;
1232        mSummaryHistoryEnqueueTime[mSummaryHistoryNext] = r.enqueueClockTime;
1233        mSummaryHistoryDispatchTime[mSummaryHistoryNext] = r.dispatchClockTime;
1234        mSummaryHistoryFinishTime[mSummaryHistoryNext] = System.currentTimeMillis();
1235        mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY);
1236    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斑响,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子钳榨,更是在濱河造成了極大的恐慌恋捆,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件重绷,死亡現(xiàn)場離奇詭異沸停,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)昭卓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門愤钾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人候醒,你說我怎么就攤上這事能颁。” “怎么了倒淫?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵伙菊,是天一觀的道長。 經(jīng)常有香客問我,道長镜硕,這世上最難降的妖魔是什么运翼? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮兴枯,結(jié)果婚禮上血淌,老公的妹妹穿的比我還像新娘。我一直安慰自己财剖,他們只是感情好悠夯,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著躺坟,像睡著了一般沦补。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咪橙,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天夕膀,我揣著相機(jī)與錄音,去河邊找鬼匣摘。 笑死店诗,一個胖子當(dāng)著我的面吹牛裹刮,可吹牛的內(nèi)容都是我干的音榜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼捧弃,長吁一口氣:“原來是場噩夢啊……” “哼赠叼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起违霞,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嘴办,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后买鸽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涧郊,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年眼五,在試婚紗的時候發(fā)現(xiàn)自己被綠了妆艘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡看幼,死狀恐怖批旺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诵姜,我是刑警寧澤汽煮,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響暇赤,放射性物質(zhì)發(fā)生泄漏心例。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一翎卓、第九天 我趴在偏房一處隱蔽的房頂上張望契邀。 院中可真熱鬧,春花似錦失暴、人聲如沸坯门。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽古戴。三九已至,卻和暖如春矩肩,著一層夾襖步出監(jiān)牢的瞬間现恼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工黍檩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叉袍,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓刽酱,卻偏偏與公主長得像喳逛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子棵里,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容