從systrace看app冷啟動(dòng)過程(一)-應(yīng)用程序啟動(dòng)

原創(chuàng)文章顷帖,轉(zhuǎn)載注明出處,多謝合作鼎文。

本文從systrace的角度通過關(guān)鍵標(biāo)簽渔肩,來簡(jiǎn)單看下app冷啟動(dòng)牽扯到的圖形渲染的整個(gè)流程。代碼參考Android 9.0漂问。

以優(yōu)酷app冷啟動(dòng)為例:

先看第一幀顯示過程赖瞒,如下圖所示:

整個(gè)過程包括:

  • 應(yīng)用程序啟動(dòng)女揭。
  • 首幀的繪制與渲染蚤假。
  • 首幀的合成與送顯。

注:
我們可以看到systrace中吧兔,每一幀主要分紅磷仰、黃、綠三種顏色:

  • 紅色: 代表從performTraversals到renderthread繪制完成的時(shí)間超過2 * vsync境蔼,定義成terrible frame灶平。
  • 黃色: 代表時(shí)間超過1 * vsync 不到 2* vsync,在有renderthread的情況下箍土,超過一個(gè)vsync是不一定會(huì)導(dǎo)致掉幀的逢享,所以只是黃色,定義成bad frame吴藻。
  • 綠色: 代表時(shí)間在1 * vsync以內(nèi), 定義成ok frame瞒爬。

先看第一個(gè)過程:應(yīng)用程序啟動(dòng)。

因?yàn)檎归_的圖太長(zhǎng)了沟堡,這個(gè)過程又主要拆分為如下兩個(gè)階段:

1)進(jìn)程創(chuàng)建階段

Zygote初始化過程中侧但,最后會(huì)調(diào)用runSelectLoop(),隨時(shí)待命航罗,當(dāng)接收到請(qǐng)求創(chuàng)建新進(jìn)程請(qǐng)求時(shí)立即喚醒并執(zhí)行相應(yīng)工作禀横。

那么在App冷啟過程中,先確定調(diào)用的Activity以及對(duì)信息與權(quán)限的驗(yàn)證粥血,并調(diào)整其task和stack之后柏锄,會(huì)開始準(zhǔn)備創(chuàng)建進(jìn)程。

進(jìn)程創(chuàng)建流程

runSelectLoop之前流程是將啟動(dòng)參數(shù)封裝成ZygoteState复亏。Zygote 待命的loop通過socket獲取到請(qǐng)求信息趾娃,runOnce就開始讀取參數(shù)列表, 并執(zhí)行forkAndSpecialize來創(chuàng)建進(jìn)程,之后就是創(chuàng)建Binder線程池以及通過反射調(diào)用ActivityThread的main函數(shù)等等蜓耻。PostFork過程就在forkAndSpecialize與handleChildProc之間茫舶,描述進(jìn)程fork的過程。而ZygoteInit部分則是描述進(jìn)程啟動(dòng)之后一些準(zhǔn)備工作刹淌。

以PostFork為例:

frameworks/base/core/java/com/android/internal/os/Zygote.java

133    public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
134          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
135          int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
            ...
143        if (pid == 0) {
144            Trace.setTracingEnabled(true, runtimeFlags);
146            // Note that this event ends at the end of handleChildProc,
147            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
148        }
149        VM_HOOKS.postForkCommon();
150        return pid;
151    }

從這里看到了traceBegin的標(biāo)簽饶氏,而且通過注釋我們知道對(duì)應(yīng)的End標(biāo)簽在handleChildProc.

 frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

844    private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
845            FileDescriptor pipeFd, boolean isZygote) {
             ...
871        // End of the postFork event.
872        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             ...
}

另外讥耗,CPU調(diào)度也提一下,也是systrace需要重點(diǎn)關(guān)注的部分:

這部分表示CPU調(diào)度狀態(tài):

  • 灰色:Sleeping
  • 藍(lán)色:Runnable (它可以運(yùn)行疹启,但是需要等待調(diào)度程序喚醒)
  • 綠色:Running
  • 橙色:Uninterruptible sleep 由于 I/O 負(fù)載而不可中斷休眠

如果當(dāng)前部分存在耗時(shí)情況古程,先對(duì)比看看相同部分的Running 時(shí)間是否差不多,如果差很多可能是方法本身耗時(shí)了喊崖,如果差不多挣磨,那么可能是調(diào)度上耗時(shí)了,比如Uninterruptible sleep狀態(tài)太多荤懂,如果是這種情況的話則需要看緊隨其后的Runnable茁裙,跟一下wake up它的對(duì)應(yīng)進(jìn)程or線程是誰,一步步分析下去节仿,找到root issue晤锥。

2)Activity啟動(dòng)階段

進(jìn)程創(chuàng)建后,繼續(xù)Activity的啟動(dòng)階段廊宪,包括對(duì)要啟動(dòng)的Activity信息矾瘾、權(quán)限等的驗(yàn)證,數(shù)據(jù)的封裝箭启、任務(wù)棧的調(diào)整等等一系列操作壕翩,最后進(jìn)入應(yīng)用的ActivityThread。

ActivityThreadMain部分:

frameworks/base/core/java/android/app/ActivityThread.java

6764    public static void main(String[] args) {
6765        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
6782        ...
6783        Looper.prepareMainLooper();
               ...
6796        ActivityThread thread = new ActivityThread();
6797        thread.attach(false, startSeq);
6808        // End of event ActivityThreadMain.
6809        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
6810        Looper.loop();
6811
6812        throw new RuntimeException("Main thread loop unexpectedly exited");
6813    }

ActivityThreadMain這就是反映了ActivityThread的main方法執(zhí)行過程傅寡,這個(gè)過程很簡(jiǎn)單就是創(chuàng)建ActivityThread并讓它的Looper消息泵循環(huán)跑起來放妈。所以一般這個(gè)過程不會(huì)有什么耗時(shí)問題。

其中有個(gè)不起眼的方法:attach 看看它的調(diào)用流程:

ActivityThread.attach() ->AMS.attachApplicationLocked()->ActivityThread.bindApplication - >sendMessage(H.BIND_APPLICATION, data);

那么就到了接下的bindApplication過程了赏僧。

bindApplication部分:

class H extends Handler {
1665        public void handleMessage(Message msg) {
1666            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
1667            // MIUI ADD
1668            long startTime = SystemClock.uptimeMillis();
1669            switch (msg.what) {
1670                case BIND_APPLICATION:
1671                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
1672                    AppBindData data = (AppBindData)msg.obj;
1673                    handleBindApplication(data);
1674                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1675                    break;
                  ...
 }
}

這個(gè)標(biāo)簽對(duì)應(yīng)的就是 handleBindApplication過程大猛,應(yīng)用進(jìn)程的創(chuàng)建是從Zygote fork的進(jìn)程,copy了一份Zygote進(jìn)程的內(nèi)存拷貝淀零,在當(dāng)前過程中挽绩,就是正式往fork出來的進(jìn)程中填充屬于當(dāng)前應(yīng)用私有的資源與數(shù)據(jù)。

注:
Zygote 剛fork出應(yīng)用進(jìn)程時(shí)驾中,兩者是共享物理內(nèi)存的唉堪,且對(duì)data區(qū)內(nèi)容只有可讀權(quán)限,一方開始了寫操作了肩民,即會(huì)開辟一塊新的內(nèi)存唠亚,保存新的修改內(nèi)容。這技術(shù)就是fork copy-on-write.

bindApplication這個(gè)過程包括:

  • 加載應(yīng)用資源持痰、load Class到內(nèi)存灶搜。
  • 創(chuàng)建上下文。
  • 初始化Instrumentation,并通過它調(diào)用application的onCreate割卖。Instrumentation是ActivityThread與組件之間的傳話官前酿,ActivityThread通過H分發(fā)出來的對(duì)應(yīng)的操作都是通過Instrumentation來調(diào)用組件實(shí)現(xiàn)。

注:
google原生邏輯是安裝應(yīng)用的時(shí)候解壓APK包鹏溯,對(duì)dex做初步優(yōu)化罢维,你會(huì)發(fā)現(xiàn)在安裝完應(yīng)用后 data/app/<packageName>/oat/arm / 路徑下會(huì)生成 .odex .vdex文件。之后會(huì)在空閑狀態(tài)下執(zhí)行dex2oat丙挽。這部分之后開章節(jié)來詳細(xì)說肺孵。

繼續(xù):


scheduleLaunchActivity流程

這部分就是走scheduleLaunchActivity流程了,內(nèi)容包括:

創(chuàng)建Activity颜阐,并走對(duì)應(yīng)的生命周期平窘。這個(gè)過程主要是應(yīng)用布局的加載:

setContentView 創(chuàng)建DecorView,并把xml的View樹解析出來瞬浓,加到DecorView上的contentParent部分初婆。之后Activity 調(diào)用makeVisible 通過WindowManagerGlobal執(zhí)行addView操作蓬坡,開啟下一個(gè)階段的繪制工作猿棉。

至此,第一個(gè)Vsync信號(hào)響應(yīng)階段就簡(jiǎn)單介紹完了屑咳,中間牽扯到的其他標(biāo)簽有興趣的可以一一追源碼看下萨赁,這里就不贅述了。下一篇分析首幀繪制與渲染過程兆龙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載杖爽,如需轉(zhuǎn)載請(qǐng)通過簡(jiǎn)信或評(píng)論聯(lián)系作者。
  • 序言:七十年代末紫皇,一起剝皮案震驚了整個(gè)濱河市慰安,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌聪铺,老刑警劉巖化焕,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铃剔,居然都是意外死亡撒桨,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門键兜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凤类,“玉大人,你說我怎么就攤上這事普气∶瞻蹋” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)夷磕。 經(jīng)常有香客問我苇侵,道長(zhǎng),這世上最難降的妖魔是什么企锌? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任榆浓,我火速辦了婚禮,結(jié)果婚禮上撕攒,老公的妹妹穿的比我還像新娘陡鹃。我一直安慰自己,他們只是感情好抖坪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布萍鲸。 她就那樣靜靜地躺著,像睡著了一般擦俐。 火紅的嫁衣襯著肌膚如雪脊阴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天蚯瞧,我揣著相機(jī)與錄音嘿期,去河邊找鬼。 笑死埋合,一個(gè)胖子當(dāng)著我的面吹牛备徐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甚颂,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼蜜猾,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了振诬?” 一聲冷哼從身側(cè)響起蹭睡,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赶么,沒想到半個(gè)月后肩豁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡禽绪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年蓖救,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片印屁。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡循捺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出雄人,到底是詐尸還是另有隱情从橘,我是刑警寧澤念赶,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站恰力,受9級(jí)特大地震影響叉谜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜踩萎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一停局、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧香府,春花似錦董栽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至勿璃,卻和暖如春擒抛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背补疑。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工歧沪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人癣丧。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓槽畔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胁编。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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