<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Android 應(yīng)用啟動(dòng)全流程深度剖析!(建議收藏)

          共 110401字,需瀏覽 221分鐘

           ·

          2021-09-26 08:44


          本文是努比亞技術(shù)團(tuán)隊(duì)原創(chuàng)內(nèi)容

          原文地址:https://www.jianshu.com/p/37370c1d17fc

          加入努比亞
          團(tuán)隊(duì)主要負(fù)責(zé) Nubia 紅魔電競(jìng)手機(jī)系統(tǒng)整體性能優(yōu)化,我們專(zhuān)注于性能、顯示、框架、Kernel 等方向的深耕。
          Nubia 技術(shù)團(tuán)隊(duì)持續(xù)招聘 Android 應(yīng)用 / 系統(tǒng) / 驅(qū)動(dòng) / 通信 / 協(xié)議及性能優(yōu)化相關(guān)開(kāi)發(fā)崗位,校招點(diǎn)擊(http://hr.nubia.com)投遞簡(jiǎn)歷,社招內(nèi)推渠道:發(fā)送簡(jiǎn)歷到 [email protected],郵件標(biāo)題:姓名 - 工作年限 - 應(yīng)聘方向

          1. 前言

          從用戶(hù)手指點(diǎn)擊桌面上的應(yīng)用圖標(biāo)到屏幕上顯示出應(yīng)用主 Activity 界面而完成應(yīng)用啟動(dòng),快的話(huà)往往都不需要一秒鐘,但是這整個(gè)過(guò)程卻是十分復(fù)雜的,其中涉及了 Android 系統(tǒng)的幾乎所有核心知識(shí)點(diǎn)。同時(shí)應(yīng)用的啟動(dòng)速度也絕對(duì)是系統(tǒng)的核心用戶(hù)體驗(yàn)指標(biāo)之一,多少年來(lái),無(wú)論是谷歌或是手機(jī)系統(tǒng)廠(chǎng)商們還是各個(gè) Android 應(yīng)用開(kāi)發(fā)者,都在為實(shí)現(xiàn)應(yīng)用打開(kāi)速度更快一點(diǎn)的目標(biāo)而不斷努力

          但是要想真正做好應(yīng)用啟動(dòng)速度優(yōu)化這件事情,我想是必須要對(duì)應(yīng)用啟動(dòng)的整個(gè)流程有充分的認(rèn)識(shí)和理解的,所以無(wú)論作為 Android 系統(tǒng)或應(yīng)用開(kāi)發(fā)者,都有必要好好的學(xué)習(xí)和了解一下這個(gè)過(guò)程的。網(wǎng)上有很多介紹應(yīng)用啟動(dòng)流程源碼的文章,但是總感覺(jué)大多數(shù)都不太全面,很多只是介紹了應(yīng)用啟動(dòng)過(guò)程中的部分流程,而沒(méi)有總體清晰的認(rèn)識(shí)應(yīng)用啟動(dòng)過(guò)程的總體脈絡(luò)與系統(tǒng)架構(gòu)設(shè)計(jì)思想

          所以本文將結(jié)合筆者多年來(lái)的工作經(jīng)歷,結(jié)合 Systrace 分析工具,基于最新 Android R AOSP 源碼完整的分析一下這個(gè)從用戶(hù)手指觸控點(diǎn)擊屏幕應(yīng)用圖標(biāo)到應(yīng)用界面展示到屏幕上的整個(gè)應(yīng)用啟動(dòng)過(guò)程,也是對(duì)之前所做所學(xué)的一個(gè)總結(jié)與歸納

          2. 大綱

          • Android 觸控事件處理機(jī)制
          • Zygote 進(jìn)程啟動(dòng)和應(yīng)用進(jìn)程創(chuàng)建流程
          • Handler 消息機(jī)制
          • AMS 的 Activity 組件管理
          • 應(yīng)用 Application 和 Activity 組件創(chuàng)建與初始化
          • 應(yīng)用 UI 布局與繪制
          • RenderThread 渲染
          • SurfaceFlinger 合成顯示
          • 寫(xiě)在最后
          • 參考

          3. Input 觸控事件處理流程

          3.1 系統(tǒng)機(jī)制分析

          Android 系統(tǒng)是由事件驅(qū)動(dòng)的,而 input 是最常見(jiàn)的事件之一,用戶(hù)的點(diǎn)擊、滑動(dòng)、長(zhǎng)按等操作,都屬于 input 事件驅(qū)動(dòng),其中的核心就是 InputReader 和 InputDispatcher。InputReader 和 InputDispatcher 是跑在 SystemServer 進(jìn)程中的兩個(gè) native 循環(huán)線(xiàn)程,負(fù)責(zé)讀取和分發(fā) Input 事件。整個(gè)處理過(guò)程大致流程如下:

          1. InputReader 負(fù)責(zé)從 EventHub 里面把 Input 事件讀取出來(lái),然后交給 InputDispatcher 進(jìn)行事件分發(fā);
          2. InputDispatcher 在拿到 InputReader 獲取的事件之后,對(duì)事件進(jìn)行包裝后,尋找并分發(fā)到目標(biāo)窗口;
          3. InboundQueue 隊(duì)列(“iq”)中放著 InputDispatcher 從 InputReader 中拿到的 input 事件;
          4. OutboundQueue(“oq”)隊(duì)列里面放的是即將要被派發(fā)給各個(gè)目標(biāo)窗口 App 的事件;
          5. WaitQueue 隊(duì)列里面記錄的是已經(jīng)派發(fā)給 App(“wq”),但是 App 還在處理沒(méi)有返回處理成功的事件;
          6. PendingInputEventQueue 隊(duì)列(“aq”)中記錄的是應(yīng)用需要處理的 Input 事件,這里可以看到 input 事件已經(jīng)傳遞到了應(yīng)用進(jìn)程;
          7. deliverInputEvent 標(biāo)識(shí) App UI Thread 被 Input 事件喚醒;
          8. InputResponse 標(biāo)識(shí) Input 事件區(qū)域,這里可以看到一個(gè) Input_Down 事件 + 若干個(gè) Input_Move 事件 + 一個(gè) Input_Up 事件的處理階段都被算到了這里;
          9. App 響應(yīng)處理 Input 事件,內(nèi)部會(huì)在其界面 View 樹(shù)中傳遞處理。

          用一張圖描述整個(gè)過(guò)程大致如下:

          3.2 結(jié)合 Systrace 分析

          從桌面點(diǎn)擊應(yīng)用圖標(biāo)啟動(dòng)應(yīng)用,system_server 的 native 線(xiàn)程 InputReader 首先負(fù)責(zé)從 EventHub 中利用 linux 的 epolle 機(jī)制監(jiān)聽(tīng)并從屏幕驅(qū)動(dòng)讀取上報(bào)的觸控事件,然后喚醒另外一條 native 線(xiàn)程 InputDispatcher 負(fù)責(zé)進(jìn)行進(jìn)一步事件分發(fā)。InputDispatcher 中會(huì)先將事件放到 InboundQueue 也就是 “iq” 隊(duì)列中,然后尋找具體處理 input 事件的目標(biāo)應(yīng)用窗口,并將事件放入對(duì)應(yīng)的目標(biāo)窗口 OutboundQueue 也就是 “oq” 隊(duì)列中等待通過(guò) SocketPair 雙工信道發(fā)送到應(yīng)用目標(biāo)窗口中。最后當(dāng)事件發(fā)送給具體的應(yīng)用目標(biāo)窗口后,會(huì)將事件移動(dòng)到 WaitQueue 也就是 “wq” 中等待目標(biāo)應(yīng)用處理事件完成,并開(kāi)啟倒計(jì)時(shí),如果目標(biāo)應(yīng)用窗口在 5S 內(nèi)沒(méi)有處理完成此次觸控事件,就會(huì)向 system_server 報(bào)應(yīng)用 ANR 異常事件。以上整個(gè)過(guò)程在 Android 系統(tǒng)源碼中都加有相應(yīng)的 systrace tag,如下 systrace 截圖所示:

          input 事件處理 1

          接著上面的流程繼續(xù)往下分析:當(dāng) input 觸控事件傳遞到桌面應(yīng)用進(jìn)程后,Input 事件到來(lái)后先通過(guò) enqueueInputEvent 函數(shù)放入 “aq” 本地待處理隊(duì)列中,并喚醒應(yīng)用的 UI 線(xiàn)程在 deliverInputEvent 的流程中進(jìn)行 input 事件的具體分發(fā)與處理。具體會(huì)先交給在應(yīng)用界面 Window 創(chuàng)建時(shí)的 ViewRootImpl#setView 流程中創(chuàng)建的多個(gè)不同類(lèi)型的 InputUsage 中依次進(jìn)行處理(比如對(duì)輸入法處理邏輯的封裝 ImeInputUsage),整個(gè)處理流程是按照責(zé)任鏈的設(shè)計(jì)模式進(jìn)行。最后會(huì)交給 ViewpostImeInputUsage 中具體進(jìn)行處理,這里面會(huì)從 View 布局樹(shù)的根節(jié)點(diǎn) DecorView 開(kāi)始遍歷整個(gè) View 樹(shù)上的每一個(gè)子 View 或 ViewGroup 界面進(jìn)行事件的分發(fā)、攔截、處理的邏輯。最后觸控事件處理完成后會(huì)調(diào)用 finishInputEvent 結(jié)束應(yīng)用對(duì)觸控事件處理邏輯,這里面會(huì)通過(guò) JNI 調(diào)用到 native 層 InputConsumer 的 sendFinishedSignal 函數(shù)通知 InputDispatcher 事件處理完成,從觸發(fā)從 "wq" 隊(duì)列中及時(shí)移除待處理事件以免報(bào) ANR 異常。

          Input 事件處理 2

          桌面應(yīng)用界面 View 中在連續(xù)處理一個(gè) ACTION_DOWN 的 TouchEvent 觸控事件和多個(gè) ACTION_MOVE,直到最后出現(xiàn)一個(gè) ACTION_UP 的 TouchEvent 事件后,判斷屬于 onClick 點(diǎn)擊事件,然后透過(guò) ActivityManager Binder 調(diào)用 AMS 的 startActivity 服務(wù)接口觸發(fā)啟動(dòng)應(yīng)用的邏輯。從 systrace 上看如下圖所示:

          input 事件處理 3

          4. 應(yīng)用進(jìn)程的創(chuàng)建與啟動(dòng)

          4.1 Pause 桌面應(yīng)用

          接著上一節(jié)繼續(xù)往下看,桌面進(jìn)程收到 input 觸控事件并處理后 binder 調(diào)用框架 AMS 的的 startActivity 接口啟動(dòng)應(yīng)用,相關(guān)簡(jiǎn)化代碼如下:

            /*frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java*/
            private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                          IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                          int startFlags, boolean doResume, ActivityOptions options, Task inTask,
                          boolean restrictedBgActivity, NeededUriGrants intentGrants) {
                  ...
                  try {
                      ...
                      // 添加“startActivityInner”的systrace tag
                      Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
                      // 執(zhí)行startActivityInner啟動(dòng)應(yīng)用的邏輯
                      result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                              startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
                  } finally {
                      Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                      ...
                  }
                  ...
              }

          在執(zhí)行 startActivityInner 啟動(dòng)應(yīng)用邏輯中,AMS 中的 Activity 棧管理的邏輯,檢查發(fā)現(xiàn)當(dāng)前處于前臺(tái) Resume 狀態(tài)的 Activity 是桌面應(yīng)用,所以第一步需要通知桌面應(yīng)用的 Activity 進(jìn)入 Paused 狀態(tài),相關(guān)簡(jiǎn)化代碼邏輯如下:

          /*frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java*/
          private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
             ...
             // mResumedActivity不為null,說(shuō)明當(dāng)前存在處于resume狀態(tài)的Activity且不是新需要啟動(dòng)的應(yīng)用
             if (mResumedActivity != null) {
                // 執(zhí)行startPausingLocked通知桌面應(yīng)用進(jìn)入paused狀態(tài)
                pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next);
             }
             ...
          }

          final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
                      ActivityRecord resuming) {
              ...
              ActivityRecord prev = mResumedActivity;
              ...
              if (prev.attachedToProcess()) {
                  try {
                       ...
                       // 相關(guān)執(zhí)行動(dòng)作封裝事務(wù),binder通知mResumedActivity也就是桌面執(zhí)行pause動(dòng)作
                       mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
                                  prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
                                  prev.configChangeFlags, pauseImmediately));
                  } catch (Exception e) {
                     ...
                  }
               }
               ...
          }

          桌面應(yīng)用進(jìn)程這邊執(zhí)行收到 pause 消息后執(zhí)行 Activity 的 onPause 生命周期,并在執(zhí)行完成后,會(huì) binder 調(diào)用 AMS 的 activityPaused 接口通知系統(tǒng)執(zhí)行完 activity 的 pause 動(dòng)作,相關(guān)代碼如下:

            /*frameworks/base/core/java/android/app/servertransaction/PauseActivityItem.java*/
            @Override
            public void postExecute(ClientTransactionHandler client, IBinder token,
                      PendingTransactionActions pendingActions) {
                  ...
                  try {
                      // binder通知AMS當(dāng)前應(yīng)用activity已經(jīng)執(zhí)行完pause的流程
                      ActivityTaskManager.getService().activityPaused(token);
                  } catch (RemoteException ex) {
                      throw ex.rethrowFromSystemServer();
                  }
              }

          AMS 這邊收到應(yīng)用的 activityPaused 調(diào)用后,繼續(xù)執(zhí)行啟動(dòng)應(yīng)用的邏輯,判斷需要啟動(dòng)的應(yīng)用 Activity 所在的進(jìn)程不存在,所以接下來(lái)需要先 startProcessAsync 創(chuàng)建應(yīng)用進(jìn)程,相關(guān)簡(jiǎn)化代碼如下:

          /*frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java*/
           void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
                  final WindowProcessController wpc =
                          mService.getProcessController(r.processName, r.info.applicationInfo.uid);
                  ...
                  // 1.如果wpc不為null且hasThread表示應(yīng)用Activity所屬進(jìn)程存在,直接realStartActivityLocked啟動(dòng)Activity
                  if (wpc != null && wpc.hasThread()) {
                      try {
                          realStartActivityLocked(r, wpc, andResume, checkConfig);
                          return;
                      } catch (RemoteException e) {
                          Slog.w(TAG, "Exception when starting activity "
                                  + r.intent.getComponent().flattenToShortString(), e);
                      }
                     ...
                  }
                  ...
                  // 2.否則,調(diào)用AMS的startProcessAsync正式開(kāi)始創(chuàng)建應(yīng)用進(jìn)程 
                  mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
              }

          以上過(guò)程從 systrace 上看,如下圖所示:

          1. 通知 pause 桌面應(yīng)用:

          2. 確認(rèn)桌面 activityPaused 狀態(tài)之后,開(kāi)始創(chuàng)建應(yīng)用進(jìn)程:

          4.2 創(chuàng)建應(yīng)用進(jìn)程

          接上一小節(jié)的分析可以知道,Android 應(yīng)用進(jìn)程的啟動(dòng)是被動(dòng)式的,在桌面點(diǎn)擊圖標(biāo)啟動(dòng)一個(gè)應(yīng)用的組件如 Activity 時(shí),如果 Activity 所在的進(jìn)程不存在,就會(huì)創(chuàng)建并啟動(dòng)進(jìn)程。Android 系統(tǒng)中一般應(yīng)用進(jìn)程的創(chuàng)建都是統(tǒng)一由 zygote 進(jìn)程 fork 創(chuàng)建的,AMS 在需要?jiǎng)?chuàng)建應(yīng)用進(jìn)程時(shí),會(huì)通過(guò) socket 連接并通知到到 zygote 進(jìn)程在開(kāi)機(jī)階段就創(chuàng)建好的 socket 服務(wù)端,然后由 zygote 進(jìn)程 fork 創(chuàng)建出應(yīng)用進(jìn)程。整體架構(gòu)如下圖所示:

          應(yīng)用進(jìn)程創(chuàng)建流程圖

          我們接著上節(jié)中的分析,繼續(xù)從 AMS#startProcessAsync 創(chuàng)建進(jìn)程函數(shù)入手,繼續(xù)看一下應(yīng)用進(jìn)程創(chuàng)建相關(guān)簡(jiǎn)化流程代碼

          4.2.1 AMS 發(fā)送 socket 請(qǐng)求

            /*frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java*/  
             @GuardedBy("this")
              final ProcessRecord startProcessLocked(...) {
                  return mProcessList.startProcessLocked(...);
             }
             
             /*frameworks/base/services/core/java/com/android/server/am/ProcessList.java*/
             private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
                      ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
                      int mountExternal, String seInfo, String requiredAbi, String instructionSet,
                      String invokeWith, long startTime) {
                  try {
                      // 原生標(biāo)識(shí)應(yīng)用進(jìn)程創(chuàng)建所加的systrace tag
                      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                              app.processName);
                      ...
                      // 調(diào)用Process的start方法創(chuàng)建進(jìn)程
                      startResult = Process.start(...);
                      ...
                  } finally {
                      Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                  }
              }
              
              /*frameworks/base/core/java/android/os/Process.java*/
              public static ProcessStartResult start(...) {
                  // 調(diào)用ZygoteProcess的start函數(shù)
                  return ZYGOTE_PROCESS.start(...);
              }
              
              /*frameworks/base/core/java/android/os/ZygoteProcess.java*/
              public final Process.ProcessStartResult start(...){
                  try {
                      return startViaZygote(...);
                  } catch (ZygoteStartFailedEx ex) {
                     ...
                  }
              }
              
              private Process.ProcessStartResult startViaZygote(...){
                  ArrayList<String> argsForZygote = new ArrayList<String>();
                  ...
                  return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
              }

          在 ZygoteProcess#startViaZygote 中,最后創(chuàng)建應(yīng)用進(jìn)程的邏輯:

          1. openZygoteSocketIfNeeded 函數(shù)中打開(kāi)本地 socket 客戶(hù)端連接到 zygote 進(jìn)程的 socket 服務(wù)端;
          2. zygoteSendArgsAndGetResult 發(fā)送 socket 請(qǐng)求參數(shù),帶上了創(chuàng)建的應(yīng)用進(jìn)程參數(shù)信息;
          3. return 返回的數(shù)據(jù)結(jié)構(gòu) ProcessStartResult 中會(huì)有新創(chuàng)建的進(jìn)程的 pid 字段。

          從 systrace 上看這個(gè)過(guò)程如下:

          start_proc

          4.2.2 Zygote 處理 socket 請(qǐng)求

          其實(shí)早在系統(tǒng)開(kāi)機(jī)階段,zygote 進(jìn)程創(chuàng)建時(shí),就會(huì)在 ZygoteInit#main 入口函數(shù)中創(chuàng)建服務(wù)端 socket,并預(yù)加載系統(tǒng)資源和框架類(lèi)(加速應(yīng)用進(jìn)程啟動(dòng)速度),代碼如下:

           /*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
           public static void main(String[] argv) {
                  ZygoteServer zygoteServer = null;
                   ...
                  try {
                      ...
                      // 1.preload提前加載框架通用類(lèi)和系統(tǒng)資源到進(jìn)程,加速進(jìn)程啟動(dòng)
                      preload(bootTimingsTraceLog);
                      ...
                      // 2.創(chuàng)建zygote進(jìn)程的socket server服務(wù)端對(duì)象
                      zygoteServer = new ZygoteServer(isPrimaryZygote);
                      ...
                      // 3.進(jìn)入死循環(huán),等待AMS發(fā)請(qǐng)求過(guò)來(lái)
                      caller = zygoteServer.runSelectLoop(abiList);
                  } catch (Throwable ex) {
                      ...
                  } finally {
                      ...
                  }
                  ...
              }

          繼續(xù)往下看 ZygoteServer#runSelectLoop 如何監(jiān)聽(tīng)并處理 AMS 客戶(hù)端的請(qǐng)求:

           /*frameworks/base/core/java/com/android/internal/os/ZygoteServer.java*/
           Runnable runSelectLoop(String abiList) {
               // 進(jìn)入死循環(huán)監(jiān)聽(tīng)
               while (true) {
                  while (--pollIndex >= 0) {
                     if (pollIndex == 0) {
                       ...
                     } else if (pollIndex < usapPoolEventFDIndex) {
                       // Session socket accepted from the Zygote server socket
                       // 得到一個(gè)請(qǐng)求連接封裝對(duì)象ZygoteConnection
                       ZygoteConnection connection = peers.get(pollIndex);
                       // processCommand函數(shù)中處理AMS客戶(hù)端請(qǐng)求
                       final Runnable command = connection.processCommand(this, multipleForksOK);
                     }
                  }
               }
           }
           
           Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
                   ...
                   // 1.fork創(chuàng)建應(yīng)用子進(jìn)程
                   pid = Zygote.forkAndSpecialize(...);
                   try {
                       if (pid == 0) {
                           ...
                           // 2.pid為0,當(dāng)前處于新創(chuàng)建的子應(yīng)用進(jìn)程中,處理請(qǐng)求參數(shù)
                           return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
                       } else {
                           ...
                           handleParentProc(pid, serverPipeFd);
                       }
                    } finally {
                       ...
                    }
           }
           
            private Runnable handleChildProc(ZygoteArguments parsedArgs,
                      FileDescriptor pipeFd, boolean isZygote) {
                  ...
                  // 關(guān)閉從父進(jìn)程zygote繼承過(guò)來(lái)的ZygoteServer服務(wù)端地址
                  closeSocket();
                  ...
                  if (parsedArgs.mInvokeWith != null) {
                     ...
                  } else {
                      if (!isZygote) {
                          // 繼續(xù)進(jìn)入ZygoteInit#zygoteInit繼續(xù)完成子應(yīng)用進(jìn)程的相關(guān)初始化工作
                          return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                                  parsedArgs.mDisabledCompatChanges,
                                  parsedArgs.mRemainingArgs, null /* classLoader */);
                      } else {
                          ...
                      }
                  }
              }

          以上過(guò)程從 systrace 上看如下圖所示:

          zygote_fork

          4.2.3 應(yīng)用進(jìn)程初始化

          接上一節(jié)中的分析,zygote 進(jìn)程監(jiān)聽(tīng)接收 AMS 的請(qǐng)求,fork 創(chuàng)建子應(yīng)用進(jìn)程,然后 pid 為 0 時(shí)進(jìn)入子進(jìn)程空間,然后在 ZygoteInit#zygoteInit 中完成進(jìn)程的初始化動(dòng)作,相關(guān)簡(jiǎn)化代碼如下:

          /*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
          public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
                      String[] argv, ClassLoader classLoader) {
                  ...
                  // 原生添加名為“ZygoteInit ”的systrace tag以標(biāo)識(shí)進(jìn)程初始化流程
                  Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
                  RuntimeInit.redirectLogStreams();
                  // 1.RuntimeInit#commonInit中設(shè)置應(yīng)用進(jìn)程默認(rèn)的java異常處理機(jī)制
                  RuntimeInit.commonInit();
                  // 2.ZygoteInit#nativeZygoteInit函數(shù)中JNI調(diào)用啟動(dòng)進(jìn)程的binder線(xiàn)程池
                  ZygoteInit.nativeZygoteInit();
                  // 3.RuntimeInit#applicationInit中反射創(chuàng)建ActivityThread對(duì)象并調(diào)用其“main”入口方法
                  return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                          classLoader);
           }

          應(yīng)用進(jìn)程啟動(dòng)后,初始化過(guò)程中主要依次完成以下幾件事情:

          1. 應(yīng)用進(jìn)程默認(rèn)的 java 異常處理機(jī)制(可以實(shí)現(xiàn)監(jiān)聽(tīng)、攔截應(yīng)用進(jìn)程所有的 Java crash 的邏輯);
          2. JNI 調(diào)用啟動(dòng)進(jìn)程的 binder 線(xiàn)程池(注意應(yīng)用進(jìn)程的 binder 線(xiàn)程池資源是自己創(chuàng)建的并非從 zygote 父進(jìn)程繼承的);
          3. 通過(guò)反射創(chuàng)建 ActivityThread 對(duì)象并調(diào)用其 “main” 入口方法。

          我們繼續(xù)看 RuntimeInit#applicationInit 簡(jiǎn)化的代碼流程:

           /*frameworks/base/core/java/com/android/internal/os/RuntimeInit.java*/
           protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
                      String[] argv, ClassLoader classLoader) {
                  ...
                  // 結(jié)束“ZygoteInit ”的systrace tag
                  Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                  // Remaining arguments are passed to the start class's static main
                  return findStaticMain(args.startClass, args.startArgs, classLoader);
            }
            
            protected static Runnable findStaticMain(String className, String[] argv,
                      ClassLoader classLoader) {
                  Class<?> cl;
                  try {
                      // 1.反射加載創(chuàng)建ActivityThread類(lèi)對(duì)象
                      cl = Class.forName(className, true, classLoader);
                  } catch (ClassNotFoundException ex) {
                      ...
                  }
                  Method m;
                  try {
                      // 2.反射調(diào)用其main方法
                      m = cl.getMethod("main", new Class[] { String[].class });
                  } catch (NoSuchMethodException ex) {
                      ...
                  } catch (SecurityException ex) {
                      ...
                  }
                  ...
                  // 3.觸發(fā)執(zhí)行以上邏輯
                  return new MethodAndArgsCaller(m, argv);
              }

          我們繼續(xù)往下看 ActivityThread 的 main 函數(shù)中又干了什么:

          /*frameworks/base/core/java/android/app/ActivityThread.java*/
          public static void main(String[] args) {
               // 原生添加的標(biāo)識(shí)進(jìn)程ActivityThread初始化過(guò)程的systrace tag,名為“ActivityThreadMain”
               Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
               ...
               // 1.創(chuàng)建并啟動(dòng)主線(xiàn)程的loop消息循環(huán)
               Looper.prepareMainLooper();
               ...
               // 2.attachApplication注冊(cè)到系統(tǒng)AMS中
               ActivityThread thread = new ActivityThread();
               thread.attach(false, startSeq);
               ...
               Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
               Looper.loop();
               ...
          }

          private void attach(boolean system, long startSeq) {
              ...
              if (!system) {
                 ...
                 final IActivityManager mgr = ActivityManager.getService();
                 try {
                    // 通過(guò)binder調(diào)用AMS的attachApplication接口將自己注冊(cè)到AMS中
                    mgr.attachApplication(mAppThread, startSeq);
                 } catch (RemoteException ex) {
                          throw ex.rethrowFromSystemServer();
                 }
              }
          }

          可以看到進(jìn)程 ActivityThread#main 函數(shù)初始化的主要邏輯是:

          1. 創(chuàng)建并啟動(dòng)主線(xiàn)程的 loop 消息循環(huán);
          2. 通過(guò) binder 調(diào)用 AMS 的 attachApplication 接口將自己 attach 注冊(cè)到 AMS 中。

          以上初始化過(guò)程。從 systrace 上看如下圖所示:

          activitythread_main

          5. 應(yīng)用主線(xiàn)程消息循環(huán)機(jī)制建立

          接上一節(jié)的分析,我們知道應(yīng)用進(jìn)程創(chuàng)建后會(huì)通過(guò)反射創(chuàng)建 ActivityThread 對(duì)象并執(zhí)行其 main 函數(shù),進(jìn)行主線(xiàn)程的初始化工作:

          /*frameworks/base/core/java/android/app/ActivityThread.java*/
          public static void main(String[] args) {
               ...
               // 1.創(chuàng)建Looper、MessageQueue
               Looper.prepareMainLooper();
               ...
               // 2.啟動(dòng)loop消息循環(huán),開(kāi)始準(zhǔn)備接收消息
               Looper.loop();
               ...
          }

          // 3.創(chuàng)建主線(xiàn)程Handler對(duì)象
          final H mH = new H();

          class H extends Handler {
            ...
          }

          /*frameworks/base/core/java/android/os/Looper.java*/
          public static void prepareMainLooper() {
               // 準(zhǔn)備主線(xiàn)程的Looper
               prepare(false);
               synchronized (Looper.class) {
                    if (sMainLooper != null) {
                        throw new IllegalStateException("The main Looper has already been prepared.");
                    }
                    sMainLooper = myLooper();
               }
          }

          private static void prepare(boolean quitAllowed) {
                if (sThreadLocal.get() != null) {
                    throw new RuntimeException("Only one Looper may be created per thread");
                }
                // 創(chuàng)建主線(xiàn)程的Looper對(duì)象,并通過(guò)ThreadLocal機(jī)制實(shí)現(xiàn)與主線(xiàn)程的一對(duì)一綁定
                sThreadLocal.set(new Looper(quitAllowed));
          }

          private Looper(boolean quitAllowed) {
                // 創(chuàng)建MessageQueue消息隊(duì)列
                mQueue = new MessageQueue(quitAllowed);
                mThread = Thread.currentThread();
          }

          主線(xiàn)程初始化完成后,主線(xiàn)程就有了完整的 Looper、MessageQueue、Handler,此時(shí) ActivityThread 的 Handler 就可以開(kāi)始處理 Message,包括 Application、Activity、ContentProvider、Service、Broadcast 等組件的生命周期函數(shù),都會(huì)以 Message 的形式,在主線(xiàn)程按照順序處理,這就是 App 主線(xiàn)程的初始化和運(yùn)行原理,部分處理的 Message 如下

          /*frameworks/base/core/java/android/app/ActivityThread.java*/
          class H extends Handler {
                  public static final int BIND_APPLICATION        = 110;
                  @UnsupportedAppUsage
                  public static final int RECEIVER                = 113;
                  @UnsupportedAppUsage
                  public static final int CREATE_SERVICE          = 114;
                  @UnsupportedAppUsage
                  public static final int BIND_SERVICE            = 121;
                  
                  public void handleMessage(Message msg) {
                      switch (msg.what) {
                          case BIND_APPLICATION:
                              Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                              AppBindData data = (AppBindData)msg.obj;
                              handleBindApplication(data);
                              Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                              break;
                              ...
                      }
                   }
                   ...
          }

          主線(xiàn)程初始化完成后,主線(xiàn)程就進(jìn)入阻塞狀態(tài),等待 Message,一旦有 Message 發(fā)過(guò)來(lái),主線(xiàn)程就會(huì)被喚醒,處理 Message,處理完成之后,如果沒(méi)有其他的 Message 需要處理,那么主線(xiàn)程就會(huì)進(jìn)入休眠阻塞狀態(tài)繼續(xù)等待。可以說(shuō) Android 系統(tǒng)的運(yùn)行是受消息機(jī)制驅(qū)動(dòng)的,而整個(gè)消息機(jī)制是由上面所說(shuō)的四個(gè)關(guān)鍵角色相互配合實(shí)現(xiàn)的(Handler、Looper、MessageQueue、Message),其運(yùn)行原理如下圖所示:

          Android 消息機(jī)制
          1. Handler : Handler 主要是用來(lái)處理 Message,應(yīng)用可以在任何線(xiàn)程創(chuàng)建 Handler,只要在創(chuàng)建的時(shí)候指定對(duì)應(yīng)的 Looper 即可,如果不指定,默認(rèn)是在當(dāng)前 Thread 對(duì)應(yīng)的 Looper。
          2. Looper : Looper 可以看成是一個(gè)循環(huán)器,其 loop 方法開(kāi)啟后,不斷地從 MessageQueue 中獲取 Message,對(duì) Message 進(jìn)行 Delivery 和 Dispatch,最終發(fā)給對(duì)應(yīng)的 Handler 去處理。
          3. MessageQueue:MessageQueue 就是一個(gè) Message 管理器,隊(duì)列中是 Message,在沒(méi)有 Message 的時(shí)候,MessageQueue 借助 Linux 的 ePoll 機(jī)制,阻塞休眠等待,直到有 Message 進(jìn)入隊(duì)列將其喚醒。
          4. Message:Message 是傳遞消息的對(duì)象,其內(nèi)部包含了要傳遞的內(nèi)容,最常用的包括 what、arg、callback 等。

          6. 應(yīng)用 Application 和 Activity 組件創(chuàng)建與初始化

          6.1 Application 的創(chuàng)建與初始化

          從前面 4.2.3 小結(jié)中的分析我們知道,應(yīng)用進(jìn)程啟動(dòng)初始化執(zhí)行 ActivityThread#main 函數(shù)過(guò)程中,在開(kāi)啟主線(xiàn)程 loop 消息循環(huán)之前,會(huì)通過(guò) Binder 調(diào)用系統(tǒng)核心服務(wù) AMS 的 attachApplication 接口將自己注冊(cè)到 AMS 中。下面我們接著這個(gè)流程往下看,我們先從 systrace 上看看 AMS 服務(wù)的 attachApplication 接口是如何處理應(yīng)用進(jìn)程的 attach 注冊(cè)請(qǐng)求的:

          attachApplication

          我們繼續(xù)來(lái)看相關(guān)代碼的簡(jiǎn)化流程:

          /*frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java*/
          @GuardedBy("this")
          private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
                      int pid, int callingUid, long startSeq) {
               ...
               if (app.isolatedEntryPoint != null) {
                     ...
               } else if (instr2 != null) {
                     // 1.通過(guò)oneway異步類(lèi)型的binder調(diào)用應(yīng)用進(jìn)程ActivityThread#IApplicationThread#bindApplication接口
                     thread.bindApplication(...);
               } else {
                     thread.bindApplication(...);
               }
               ...
               // See if the top visible activity is waiting to run in this process...
               if (normalMode) {
                    try {
                      // 2.繼續(xù)執(zhí)行啟動(dòng)應(yīng)用Activity的流程
                      didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
                    } catch (Exception e) {
                          Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                          badApp = true;
                    }
                }
          }

          /*frameworks/base/core/java/android/app/ActivityThread.java*/
          private class ApplicationThread extends IApplicationThread.Stub {
                @Override
                public final void bindApplication(...) {
                      ...
                      AppBindData data = new AppBindData();
                      data.processName = processName;
                      data.appInfo = appInfo;
                      ...
                      // 向應(yīng)用進(jìn)程主線(xiàn)程Handler發(fā)送BIND_APPLICATION消息,觸發(fā)在應(yīng)用主線(xiàn)程執(zhí)行handleBindApplication初始化動(dòng)作
                      sendMessage(H.BIND_APPLICATION, data);
                }
                ...
          }

          class H extends Handler {
                ...
                public void handleMessage(Message msg) {
                     switch (msg.what) {
                          case BIND_APPLICATION:
                              Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                              AppBindData data = (AppBindData)msg.obj;
                              // 在應(yīng)用主線(xiàn)程執(zhí)行handleBindApplication初始化動(dòng)作
                              handleBindApplication(data);
                              Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                              break;
                              ...
                     }
                }
                ...
          }

          @UnsupportedAppUsage
          private void handleBindApplication(AppBindData data) {
              ...
          }

          從上面的代碼流程可以看出:AMS 服務(wù)在執(zhí)行應(yīng)用的 attachApplication 注冊(cè)請(qǐng)求過(guò)程中,會(huì)通過(guò) oneway 類(lèi)型的 binder 調(diào)用應(yīng)用進(jìn)程 ActivityThread#IApplicationThread 的 bindApplication 接口,而 bindApplication 接口函數(shù)實(shí)現(xiàn)中又會(huì)通過(guò)往應(yīng)用主線(xiàn)程消息隊(duì)列 post BIND_APPLICATION 消息觸發(fā)執(zhí)行 handleBindApplication 初始化函數(shù),從 systrace 看如下圖所示:

          handleBindApplication

          我們繼續(xù)結(jié)合代碼看看 handleBindApplication 的簡(jiǎn)化關(guān)鍵流程:

          /*frameworks/base/core/java/android/app/ActivityThread.java*/
          @UnsupportedAppUsage
          private void handleBindApplication(AppBindData data) {
              ...
              // 1.創(chuàng)建應(yīng)用的LoadedApk對(duì)象
              data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
              ...
              // 2.創(chuàng)建應(yīng)用Application的Context、觸發(fā)Art虛擬機(jī)加載應(yīng)用APK的Dex文件到內(nèi)存中,并加載應(yīng)用APK的Resource資源
              final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
              ...
              // 3.調(diào)用LoadedApk的makeApplication函數(shù),實(shí)現(xiàn)創(chuàng)建應(yīng)用的Application對(duì)象
              app = data.info.makeApplication(data.restrictedBackupMode, null);
              ...
              // 4.執(zhí)行應(yīng)用Application#onCreate生命周期函數(shù)
              mInstrumentation.onCreate(data.instrumentationArgs);
              ...
          }

          在 ActivityThread#**handleBindApplication 初始化過(guò)程中在應(yīng)用主線(xiàn)程中主要完成如下幾件事件 **:

          1. 根據(jù)框架傳入的 ApplicationInfo 信息創(chuàng)建應(yīng)用 APK 對(duì)應(yīng)的 LoadedApk 對(duì)象;
          2. 創(chuàng)建應(yīng)用 Application 的 Context 對(duì)象;
          3. 創(chuàng)建類(lèi)加載器 ClassLoader 對(duì)象并觸發(fā) Art 虛擬機(jī)執(zhí)行 OpenDexFilesFromOat 動(dòng)作加載應(yīng)用 APK 的 Dex 文件;
          4. 通過(guò) LoadedApk 加載應(yīng)用 APK 的 Resource 資源;
          5. 調(diào)用 LoadedApk 的 makeApplication 函數(shù),創(chuàng)建應(yīng)用的 Application 對(duì)象;
          6. 執(zhí)行應(yīng)用 Application#onCreate 生命周期函數(shù)(APP 應(yīng)用開(kāi)發(fā)者能控制的第一行代碼);

          下面我們結(jié)合代碼重點(diǎn)看看 APK Dex 文件的加載和 Resource 資源的加載流程。

          6.1.1 應(yīng)用 APK 的 Dex 文件加載

          /*frameworks/base/core/java/android/app/ContextImpl.java*/
          static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
                      String opPackageName) {
              if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
              // 1.創(chuàng)建應(yīng)用Application的Context對(duì)象
              ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null,
                          0, null, opPackageName);
              // 2.觸發(fā)加載APK的DEX文件和Resource資源
              context.setResources(packageInfo.getResources());
              context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
              return context;
          }

          /*frameworks/base/core/java/android/app/LoadedApk.java*/
          @UnsupportedAppUsage
          public Resources getResources() {
               if (mResources == null) {
                   ...
                   // 加載APK的Resource資源
                   mResources = ResourcesManager.getInstance().getResources(null, mResDir,
                              splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
                              Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
                              getClassLoader()/*觸發(fā)加載APK的DEX文件*/, null);
                }
                return mResources;
          }

          @UnsupportedAppUsage
          public ClassLoader getClassLoader() {
               synchronized (this) {
                   if (mClassLoader == null) {
                       createOrUpdateClassLoaderLocked(null /*addedPaths*/);
                    }
                    return mClassLoader;
               }
          }

          private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
               ...
               if (mDefaultClassLoader == null) {
                    ...
                    // 創(chuàng)建默認(rèn)的mDefaultClassLoader對(duì)象,觸發(fā)art虛擬機(jī)加載dex文件
                    mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
                              zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
                              libraryPermittedPath, mBaseClassLoader,
                              mApplicationInfo.classLoaderName, sharedLibraries);
                    ...
               }
               ...
               if (mClassLoader == null) {
                   // 賦值給mClassLoader對(duì)象
                   mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader,
                              new ApplicationInfo(mApplicationInfo));
               }
          }

          /*frameworks/base/core/java/android/app/ApplicationLoaders.java*/
          ClassLoader getClassLoaderWithSharedLibraries(...) {
              // For normal usage the cache key used is the same as the zip path.
              return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
                                        libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries);
          }

          private ClassLoader getClassLoader(String zip, ...) {
                  ...
                  synchronized (mLoaders) {
                      ...
                      if (parent == baseParent) {
                          ...
                          // 1.創(chuàng)建BootClassLoader加載系統(tǒng)框架類(lèi),并增加相應(yīng)的systrace tag
                          Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                          ClassLoader classloader = ClassLoaderFactory.createClassLoader(
                                  zip,  librarySearchPath, libraryPermittedPath, parent,
                                  targetSdkVersion, isBundled, classLoaderName, sharedLibraries);
                          Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                          ...
                          return classloader;
                      }
                      // 2.創(chuàng)建PathClassLoader加載應(yīng)用APK的Dex類(lèi),并增加相應(yīng)的systrace tag
                      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                      ClassLoader loader = ClassLoaderFactory.createClassLoader(
                              zip, null, parent, classLoaderName, sharedLibraries);
                      Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                      return loader;
                  }
          }

          /*frameworks/base/core/java/com/android/internal/os/ClassLoaderFactory.java*/
          public static ClassLoader createClassLoader(...) {
                  // 通過(guò)new的方式創(chuàng)建ClassLoader對(duì)象,最終會(huì)觸發(fā)art虛擬機(jī)加載APK的dex文件
                  ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)
                          ? null
                          : sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);
                  if (isPathClassLoaderName(classloaderName)) {
                      return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries);
                  }
                  ...
          }

          從以上代碼可以看出:在創(chuàng)建 Application 的 Context 對(duì)象后會(huì)立馬嘗試去加載 APK 的 Resource 資源,而在這之前需要通過(guò) LoadedApk 去創(chuàng)建類(lèi)加載器 ClassLoader 對(duì)象,而這個(gè)過(guò)程最終就會(huì)觸發(fā) Art 虛擬機(jī)加載應(yīng)用 APK 的 dex 文件,從 systrace 上看如下圖所示:

          OpenDexFilesFromOat

          具體 art 虛擬機(jī)加載 dex 文件的流程由于篇幅所限這里就不展開(kāi)講了,這邊畫(huà)了一張流程圖可以參考一下,感興趣的讀者可以對(duì)照追一下源碼流程:

          Art 虛擬機(jī) Dex 加載流程

          6.1.2 應(yīng)用 APK 的 Resource 資源加載

          /*frameworks/base/core/java/android/app/LoadedApk.java*/
          @UnsupportedAppUsage
          public Resources getResources() {
               if (mResources == null) {
                   ...
                   // 加載APK的Resource資源
                   mResources = ResourcesManager.getInstance().getResources(null, mResDir,
                              splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
                              Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
                              getClassLoader()/*觸發(fā)加載APK的DEX文件*/, null);
                }
                return mResources;
          }

          /*frameworks/base/core/java/android/app/ResourcesManager.java*/
          public @Nullable Resources getResources(...) {
                try {
                    // 原生Resource資源加載的systrace tag
                    Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
                    ...
                    return createResources(activityToken, key, classLoader, assetsSupplier);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
                }
          }

          private @Nullable Resources createResources(...) {
                synchronized (this) {
                      ...
                      // 執(zhí)行創(chuàng)建Resources資源對(duì)象
                      ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key, apkSupplier);
                      if (resourcesImpl == null) {
                          return null;
                      }
                      ...
               }
          }

          private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked(
                      @NonNull ResourcesKey key, @Nullable ApkAssetsSupplier apkSupplier) {
                ...
                impl = createResourcesImpl(key, apkSupplier);
                ...
          }

          private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key,
                      @Nullable ApkAssetsSupplier apkSupplier) {
                  ...
                  // 創(chuàng)建AssetManager對(duì)象,真正實(shí)現(xiàn)的APK文件加載解析動(dòng)作
                  final AssetManager assets = createAssetManager(key, apkSupplier);
                  ...
          }

          private @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key,
                      @Nullable ApkAssetsSupplier apkSupplier) {
                  ...
                  for (int i = 0, n = apkKeys.size(); i < n; i++) {
                      final ApkKey apkKey = apkKeys.get(i);
                      try {
                          // 通過(guò)loadApkAssets實(shí)現(xiàn)應(yīng)用APK文件的加載
                          builder.addApkAssets(
                                  (apkSupplier != null) ? apkSupplier.load(apkKey) : loadApkAssets(apkKey));
                      } catch (IOException e) {
                          ...
                      }
                  }
                  ...   
          }

          private @NonNull ApkAssets loadApkAssets(@NonNull final ApkKey key) throws IOException {
                  ...
                  if (key.overlay) {
                      ...
                  } else {
                      // 通過(guò)ApkAssets從APK文件所在的路徑去加載
                      apkAssets = ApkAssets.loadFromPath(key.path,
                              key.sharedLib ? ApkAssets.PROPERTY_DYNAMIC : 0);
                  }
                  ...
              }

          /*frameworks/base/core/java/android/content/res/ApkAssets.java*/
          public static @NonNull ApkAssets loadFromPath(@NonNull String path, @PropertyFlags int flags)
                      throws IOException {
                  return new ApkAssets(FORMAT_APK, path, flags, null /* assets */);
          }

          private ApkAssets(@FormatType int format, @NonNull String path, @PropertyFlags int flags,
                      @Nullable AssetsProvider assets) throws IOException {
                  ...
                  // 通過(guò)JNI調(diào)用Native層的系統(tǒng)system/lib/libandroidfw.so庫(kù)中的相關(guān)C函數(shù)實(shí)現(xiàn)對(duì)APK文件壓縮包的解析與加載
                  mNativePtr = nativeLoad(format, path, flags, assets);
                  ...
          }

          從以上代碼可以看出:系統(tǒng)對(duì)于應(yīng)用 APK 文件資源的加載過(guò)程其實(shí)就是創(chuàng)建應(yīng)用進(jìn)程中的 Resources 資源對(duì)象的過(guò)程,其中真正實(shí)現(xiàn) APK 資源文件的 I/O 解析,最終是借助于 AssetManager 中通過(guò) JNI 調(diào)用系統(tǒng) Native 層的相關(guān) C 函數(shù)實(shí)現(xiàn)。整個(gè)過(guò)程從 systrace 上看如下圖所示:

          getResources

          6.2 Activity 的創(chuàng)建與初始化

          我們回到 6.1 小結(jié)中,看看 AMS 在收到應(yīng)用進(jìn)程的 attachApplication 注冊(cè)請(qǐng)求后,先通過(guò) oneway 類(lèi)型的 binder 調(diào)用應(yīng)用及進(jìn)程的 IApplicationThread#bindApplication 接口,觸發(fā)應(yīng)用進(jìn)程在主線(xiàn)程執(zhí)行 handleBindeApplication 初始化操作,然后繼續(xù)執(zhí)行啟動(dòng)應(yīng)用 Activity 的操作,下面我們來(lái)看看系統(tǒng)是如何啟動(dòng)創(chuàng)建應(yīng)用 Activity 的,簡(jiǎn)化代碼流程如下:

          /*frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java*/
          @GuardedBy("this")
          private boolean attachApplicationLocked(...) {
               ...
               if (app.isolatedEntryPoint != null) {
                     ...
               } else if (instr2 != null) {
                     // 1.通過(guò)oneway異步類(lèi)型的binder調(diào)用應(yīng)用進(jìn)程ActivityThread#IApplicationThread#bindApplication接口
                     thread.bindApplication(...);
               } else {
                     thread.bindApplication(...);
               }
               ...
               // See if the top visible activity is waiting to run in this process...
               if (normalMode) {
                    try {
                      // 2.繼續(xù)執(zhí)行啟動(dòng)應(yīng)用Activity的流程
                      didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
                    } catch (Exception e) {
                          Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                          badApp = true;
                    }
                }
          }

          /*frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java*/
          public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
                 synchronized (mGlobalLockWithoutBoost) {
                      if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                          // 原生標(biāo)識(shí)attachApplication過(guò)程的systrace tag
                          Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "attachApplication:" + wpc.mName);
                      }
                      try {
                          return mRootWindowContainer.attachApplication(wpc);
                      } finally {
                          Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                      }
                 }
          }

          /*frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java*/
          boolean attachApplication(WindowProcessController app) throws RemoteException {
                 ...
                 final PooledFunction c = PooledLambda.obtainFunction(
                          // startActivityForAttachedApplicationIfNeeded執(zhí)行啟動(dòng)應(yīng)用Activity流程
                          RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
                          PooledLambda.__(ActivityRecord.class), app,
                          rootTask.topRunningActivity());
                 ...
          }
           
          private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
                      WindowProcessController app, ActivityRecord top) {
                  ...
                  try {
                      // ActivityStackSupervisor的realStartActivityLocked真正實(shí)現(xiàn)啟動(dòng)應(yīng)用Activity流程
                      if (mStackSupervisor.realStartActivityLocked(r, app,
                              top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/)) {
                          ...
                      }
                  } catch (RemoteException e) {
                      ..
                  }
          }

          /*frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java*/
          boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
                      boolean andResume, boolean checkConfig) throws RemoteException {
                   ...
                  // 1.先通過(guò)LaunchActivityItem封裝Binder通知應(yīng)用進(jìn)程執(zhí)行Launch Activity動(dòng)作       
                   clientTransaction.addCallback(LaunchActivityItem.obtain(...);
                   // Set desired final state.
                   final ActivityLifecycleItem lifecycleItem;
                   if (andResume) {
                          // 2.再通過(guò)ResumeActivityItem封裝Binder通知應(yīng)用進(jìn)程執(zhí)行Launch Resume動(dòng)作        
                          lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
                   }
                   ...
                   clientTransaction.setLifecycleStateRequest(lifecycleItem);
                   // 執(zhí)行以上封裝的Binder調(diào)用
                   mService.getLifecycleManager().scheduleTransaction(clientTransaction);
                   ...
          }

          從以上代碼分析可以看到,框架 system_server 進(jìn)程最終是通過(guò) ActivityStackSupervisor#realStartActivityLocked 函數(shù)中,通過(guò) LaunchActivityItem 和 ResumeActivityItem 兩個(gè)類(lèi)的封裝,依次實(shí)現(xiàn) binder 調(diào)用通知應(yīng)用進(jìn)程這邊執(zhí)行 Activity 的 Launch 和 Resume 動(dòng)作的,我們繼續(xù)往下看相關(guān)代碼流程:

          6.2.1 Activity Create

          /*frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java*/
          @Override
          public void execute(ClientTransactionHandler client, IBinder token,
                      PendingTransactionActions pendingActions) {
               // 原生標(biāo)識(shí)Activity Launch的systrace tag
               Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
               ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                          mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                          mPendingResults, mPendingNewIntents, mIsForward,
                          mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
               // 調(diào)用到ActivityThread的handleLaunchActivity函數(shù)在主線(xiàn)程執(zhí)行應(yīng)用Activity的Launch創(chuàng)建動(dòng)作
               client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
               Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
          }

          /*frameworks/base/core/java/android/app/ActivityThread.java*/
          @Override
          public Activity handleLaunchActivity(ActivityClientRecord r,
                      PendingTransactionActions pendingActions, Intent customIntent) {
               ...
               final Activity a = performLaunchActivity(r, customIntent);
               ...
          }

          /**  Core implementation of activity launch. */
          private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
                  ...
                  // 1.創(chuàng)建Activity的Context
                  ContextImpl appContext = createBaseContextForActivity(r);
                  try {
                      //2.反射創(chuàng)建Activity對(duì)象
                      activity = mInstrumentation.newActivity(
                              cl, component.getClassName(), r.intent);
                      ...
                  } catch (Exception e) {
                      ...
                  }
                  try {
                      ...
                      if (activity != null) {
                          ...
                          // 3.執(zhí)行Activity的attach動(dòng)作
                          activity.attach(...);
                          ...
                          // 4.執(zhí)行應(yīng)用Activity的onCreate生命周期函數(shù),并在setContentView調(diào)用中創(chuàng)建DecorView對(duì)象
                          mInstrumentation.callActivityOnCreate(activity, r.state);
                          ...
                      }
                      ...
                  } catch (SuperNotCalledException e) {
                      ...
                  }
          }

          /*frameworks/base/core/java/android/app/Activity.java*/
           @UnsupportedAppUsage
           final void attach(...) {
                  ...
                  // 1.創(chuàng)建表示應(yīng)用窗口的PhoneWindow對(duì)象
                  mWindow = new PhoneWindow(this, window, activityConfigCallback);
                  ...
                  // 2.為PhoneWindow配置WindowManager
                  mWindow.setWindowManager(
                          (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                          mToken, mComponent.flattenToString(),
                          (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
                  ...
          }

          從上面代碼可以看出,應(yīng)用進(jìn)程這邊在收到系統(tǒng) binder 調(diào)用后,在主線(xiàn)程中創(chuàng)建 Activiy 的流程主要步驟如下:

          1. 創(chuàng)建 Activity 的 Context;
          2. 通過(guò)反射創(chuàng)建 Activity 對(duì)象;
          3. 執(zhí)行 Activity 的 attach 動(dòng)作,其中會(huì)創(chuàng)建應(yīng)用窗口的 PhoneWindow 對(duì)象并設(shè)置 WindowManage;
          4. 執(zhí)行應(yīng)用 Activity 的 onCreate 生命周期函數(shù),并在 setContentView 中創(chuàng)建窗口的 DecorView 對(duì)象;從 systrace 上看整個(gè)過(guò)程如下圖所示:
          ActivityStart

          6.2.2 Activity Resume

          /*frameworks/base/core/java/android/app/servertransaction/ResumeActivityItem.java*/
          @Override
          public void execute(ClientTransactionHandler client, IBinder token,
                      PendingTransactionActions pendingActions) {
             // 原生標(biāo)識(shí)Activity Resume的systrace tag
             Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
             client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
                          "RESUME_ACTIVITY");
             Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
          }

          /*frameworks/base/core/java/android/app/ActivityThread.java*/
           @Override
          public void handleResumeActivity(...){
              ...
              // 1.執(zhí)行performResumeActivity流程,執(zhí)行應(yīng)用Activity的onResume生命周期函數(shù)
              final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
              ...
              if (r.window == null && !a.mFinished && willBeVisible) {
                      ...
                      if (a.mVisibleFromClient) {
                          if (!a.mWindowAdded) {
                              ...
                              // 2.執(zhí)行WindowManager#addView動(dòng)作開(kāi)啟視圖繪制邏輯
                              wm.addView(decor, l);
                          } else {
                            ...
                          }
                      }
               }
              ...
          }

          public ActivityClientRecord performResumeActivity(...) {
              ...
              // 執(zhí)行應(yīng)用Activity的onResume生命周期函數(shù)
              r.activity.performResume(r.startsNotResumed, reason);
              ...
          }

          /*frameworks/base/core/java/android/view/WindowManagerGlobal.java*/
          public void addView(...) {
               // 創(chuàng)建ViewRootImpl對(duì)象
               root = new ViewRootImpl(view.getContext(), display);
               ...
               try {
                   // 執(zhí)行ViewRootImpl的setView函數(shù)
                   root.setView(view, wparams, panelParentView, userId);
               } catch (RuntimeException e) {
                   ...
               } 
          }

          從上面代碼可以看出,應(yīng)用進(jìn)程這邊在接收到系統(tǒng) Binder 調(diào)用請(qǐng)求后,在主線(xiàn)程中 Activiy Resume 的流程主要步驟如下:

          1. 執(zhí)行應(yīng)用 Activity 的 onResume 生命周期函數(shù);
          2. 執(zhí)行 WindowManager 的 addView 動(dòng)作開(kāi)啟視圖繪制邏輯;
          3. 創(chuàng)建 Activity 的 ViewRootImpl 對(duì)象;
          4. 執(zhí)行 ViewRootImpl 的 setView 函數(shù)開(kāi)啟 UI 界面繪制動(dòng)作;

          從 systrace 上看整個(gè)過(guò)程如下圖所示:

          activityResume

          7. 應(yīng)用 UI 布局與繪制

          接上一節(jié)的分析,應(yīng)用主線(xiàn)程中在執(zhí)行 Activity 的 Resume 流程的最后,會(huì)創(chuàng)建 ViewRootImpl 對(duì)象并調(diào)用其 setView 函數(shù),從此并開(kāi)啟了應(yīng)用界面 UI 布局與繪制的流程。在開(kāi)始講解這個(gè)過(guò)程之前,我們先來(lái)整理一下前面代碼中講到的這些概念,如 Activity、PhoneWindow、DecorView、ViewRootImpl、WindowManager 它們之間的關(guān)系與職責(zé),因?yàn)檫@些核心類(lèi)基本構(gòu)成了 Android 系統(tǒng)的 GUI 顯示系統(tǒng)在應(yīng)用進(jìn)程側(cè)的核心架構(gòu),其整體架構(gòu)如下圖所示:

          GUI_APP
          1. Window 是一個(gè)抽象類(lèi),通過(guò)控制 DecorView 提供了一些標(biāo)準(zhǔn)的 UI 方案,比如背景、標(biāo)題、虛擬按鍵等,而 PhoneWindow 是 Window 的唯一實(shí)現(xiàn)類(lèi),在 Activity 創(chuàng)建后的 attach 流程中創(chuàng)建,應(yīng)用啟動(dòng)顯示的內(nèi)容裝載到其內(nèi)部的 mDecor(DecorView);
          2. DecorView 是整個(gè)界面布局 View 控件樹(shù)的根節(jié)點(diǎn),通過(guò)它可以遍歷訪(fǎng)問(wèn)到整個(gè) View 控件樹(shù)上的任意節(jié)點(diǎn);
          3. WindowManager 是一個(gè)接口,繼承自 ViewManager 接口,提供了 View 的基本操作方法;WindowManagerImp 實(shí)現(xiàn)了 WindowManager 接口,內(nèi)部通過(guò)組合方式持有 WindowManagerGlobal,用來(lái)操作 View;WindowManagerGlobal 是一個(gè)全局單例,內(nèi)部可以通過(guò) ViewRootImpl 將 View 添加至窗口中;
          4. ViewRootImpl 是所有 View 的 Parent,用來(lái)總體管理 View 的繪制以及與系統(tǒng) WMS 窗口管理服務(wù)的 IPC 交互從而實(shí)現(xiàn)窗口的開(kāi)辟;ViewRootImpl 是應(yīng)用進(jìn)程運(yùn)轉(zhuǎn)的發(fā)動(dòng)機(jī),可以看到 ViewRootImpl 內(nèi)部包含 mView(就是 DecorView)、mSurface、Choregrapher,mView 代表整個(gè)控件樹(shù),mSurfacce 代表畫(huà)布,應(yīng)用的 UI 渲染會(huì)直接放到 mSurface 中,Choregorapher 使得應(yīng)用請(qǐng)求 vsync 信號(hào),接收信號(hào)后開(kāi)始渲染流程;

          我們從 ViewRootImpl 的 setView 流程繼續(xù)結(jié)合代碼往下看:

          /*frameworks/base/core/java/android/view/ViewRootImpl.java*/
          public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
                      int userId) {
                synchronized (this) {
                   if (mView == null) {
                       mView = view;
                   }
                   ...
                   // 開(kāi)啟繪制硬件加速,初始化RenderThread渲染線(xiàn)程運(yùn)行環(huán)境
                   enableHardwareAcceleration(attrs);
                   ...
                   // 1.觸發(fā)繪制動(dòng)作
                   requestLayout();
                   ...
                   inputChannel = new InputChannel();
                   ...
                   // 2.Binder調(diào)用訪(fǎng)問(wèn)系統(tǒng)窗口管理服務(wù)WMS接口,實(shí)現(xiàn)addWindow添加注冊(cè)應(yīng)用窗口的操作,并傳入inputChannel用于接收觸控事件
                   res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                                      getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                                      mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                      mAttachInfo.mDisplayCutout, inputChannel,
                                      mTempInsets, mTempControls);
                   ...
                   // 3.創(chuàng)建WindowInputEventReceiver對(duì)象,實(shí)現(xiàn)應(yīng)用窗口接收觸控事件
                   mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                                      Looper.myLooper());
                   ...
                   // 4.設(shè)置DecorView的mParent為ViewRootImpl
                   view.assignParent(this);
                   ...
                }
          }

          從以上代碼可以看出 ViewRootImpl 的 setView 內(nèi)部關(guān)鍵流程如下:

          1. requestLayout () 通過(guò)一系列調(diào)用觸發(fā)界面繪制(measure、layout、draw)動(dòng)作,下文會(huì)詳細(xì)展開(kāi)分析;
          2. 通過(guò) Binder 調(diào)用訪(fǎng)問(wèn)系統(tǒng)窗口管理服務(wù) WMS 的 addWindow 接口,實(shí)現(xiàn)添加、注冊(cè)應(yīng)用窗口的操作,并傳入本地創(chuàng)建 inputChannel 對(duì)象用于后續(xù)接收系統(tǒng)的觸控事件,這一步執(zhí)行完我們的 View 就可以顯示到屏幕上了。關(guān)于 WMS 的內(nèi)部實(shí)現(xiàn)流程也非常復(fù)雜,由于篇幅有限本文就不詳細(xì)展開(kāi)分析了。
          3. 創(chuàng)建 WindowInputEventReceiver 對(duì)象,封裝實(shí)現(xiàn)應(yīng)用窗口接收系統(tǒng)觸控事件的邏輯;
          4. 執(zhí)行 view.assignParent (this),設(shè)置 DecorView 的 mParent 為 ViewRootImpl。所以,雖然 ViewRootImpl 不是一個(gè) View, 但它是所有 View 的頂層 Parent。

          我們順著 ViewRootImpl 的 requestLayout 動(dòng)作繼續(xù)往下看界面繪制的流程代碼:

          /*frameworks/base/core/java/android/view/ViewRootImpl.java*/
          public void requestLayout() {
              if (!mHandlingLayoutInLayoutRequest) {
                   // 檢查當(dāng)前UI繪制操作是否發(fā)生在主線(xiàn)程,如果發(fā)生在子線(xiàn)程則會(huì)拋出異常
                   checkThread();
                   mLayoutRequested = true;
                   // 觸發(fā)繪制操作
                   scheduleTraversals();
              }
          }

          @UnsupportedAppUsage
          void scheduleTraversals() {
              if (!mTraversalScheduled) {
                   ...
                   // 注意此處會(huì)往主線(xiàn)程的MessageQueue消息隊(duì)列中添加同步欄刪,因?yàn)橄到y(tǒng)繪制消息屬于異步消息,需要更高優(yōu)先級(jí)的處理
                   mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
                   // 通過(guò)Choreographer往主線(xiàn)程消息隊(duì)列添加CALLBACK_TRAVERSAL繪制類(lèi)型的待執(zhí)行消息,用于觸發(fā)后續(xù)UI線(xiàn)程真正實(shí)現(xiàn)繪制動(dòng)作
                   mChoreographer.postCallback(
                              Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
                   ...
               }
          }

          Choreographer 的引入,主要是配合系統(tǒng) Vsync 垂直同步機(jī)制(Android “黃油計(jì)劃” 中引入的機(jī)制之一,協(xié)調(diào) APP 生成 UI 數(shù)據(jù)和 SurfaceFlinger 合成圖像,避免 Tearing 畫(huà)面撕裂的現(xiàn)象),給上層 App 的渲染提供一個(gè)穩(wěn)定的 Message 處理的時(shí)機(jī),也就是 Vsync 到來(lái)的時(shí)候 ,系統(tǒng)通過(guò)對(duì) Vsync 信號(hào)周期的調(diào)整,來(lái)控制每一幀繪制操作的時(shí)機(jī)。Choreographer 扮演 Android 渲染鏈路中承上啟下的角色:

          1. 承上:負(fù)責(zé)接收和處理 App 的各種更新消息和回調(diào),等到 Vsync 到來(lái)的時(shí)候統(tǒng)一處理。比如集中處理 Input (主要是 Input 事件的處理) 、Animation (動(dòng)畫(huà)相關(guān))、Traversal (包括 measure、layout、draw 等操作) ,判斷卡頓掉幀情況,記錄 CallBack 耗時(shí)等;
          2. 啟下:負(fù)責(zé)請(qǐng)求和接收 Vsync 信號(hào)。接收 Vsync 事件回調(diào) (通過(guò) FrameDisplayEventReceiver.onVsync),請(qǐng)求 Vsync (FrameDisplayEventReceiver.scheduleVsync) 。

          Choreographer 在收到 CALLBACK_TRAVERSAL 類(lèi)型的繪制任務(wù)后,其內(nèi)部的工作流程如下圖所示:

          Choreographer 工作原理

          從以上流程圖可以看出:ViewRootImpl 調(diào)用 Choreographer 的 postCallback 接口放入待執(zhí)行的繪制消息后,Choreographer 會(huì)先向系統(tǒng)申請(qǐng) APP 類(lèi)型的 vsync 信號(hào),然后等待系統(tǒng) vsync 信號(hào)到來(lái)后,去回調(diào)到 ViewRootImpl 的 doTraversal 函數(shù)中執(zhí)行真正的繪制動(dòng)作(measure、layout、draw)。這個(gè)繪制過(guò)程從 systrace 上看如下圖所示:

          UI 繪制任務(wù)

          我們接著 ViewRootImpl 的 doTraversal 函數(shù)的簡(jiǎn)化代碼流程往下看:

          /*frameworks/base/core/java/android/view/ViewRootImpl.java*/
          void doTraversal() {
               if (mTraversalScheduled) {
                   mTraversalScheduled = false;
                   // 調(diào)用removeSyncBarrier及時(shí)移除主線(xiàn)程MessageQueue中的Barrier同步欄刪,以避免主線(xiàn)程發(fā)生“假死”
                   mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
                   ...
                   // 執(zhí)行具體的繪制任務(wù)
                   performTraversals();
                   ...
              }
          }

          private void performTraversals() {
               ...
               // 1.從DecorView根節(jié)點(diǎn)出發(fā),遍歷整個(gè)View控件樹(shù),完成整個(gè)View控件樹(shù)的measure測(cè)量操作
               windowSizeMayChange |= measureHierarchy(...);
               ...
               if (mFirst...) {
              // 2.第一次執(zhí)行traversals繪制任務(wù)時(shí),Binder調(diào)用訪(fǎng)問(wèn)系統(tǒng)窗口管理服務(wù)WMS的relayoutWindow接口,實(shí)現(xiàn)WMS計(jì)算應(yīng)用窗口尺寸并向系統(tǒng)surfaceflinger正式申請(qǐng)Surface“畫(huà)布”操作
                   relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
               }
               ...
               // 3.從DecorView根節(jié)點(diǎn)出發(fā),遍歷整個(gè)View控件樹(shù),完成整個(gè)View控件樹(shù)的layout測(cè)量操作
               performLayout(lp, mWidth, mHeight);
               ...
               // 4.從DecorView根節(jié)點(diǎn)出發(fā),遍歷整個(gè)View控件樹(shù),完成整個(gè)View控件樹(shù)的draw測(cè)量操作
               performDraw();
               ...
          }

          private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
                      boolean insetsPending) throws RemoteException {
                  ...
                  // 通過(guò)Binder IPC訪(fǎng)問(wèn)系統(tǒng)WMS服務(wù)的relayout接口,申請(qǐng)Surface“畫(huà)布”操作
                  int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
                          (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                          (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
                          insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
                          mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame,
                          mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
                          mTempControls, mSurfaceSize, mBlastSurfaceControl);
                  if (mSurfaceControl.isValid()) {
                      if (!useBLAST()) {
                          // 本地Surface對(duì)象獲取指向遠(yuǎn)端分配的Surface的引用
                          mSurface.copyFrom(mSurfaceControl);
                      } else {
                         ...
                      }
                  }
                  ...
          }

          private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
                  ...
                  // 原生標(biāo)識(shí)View樹(shù)的measure測(cè)量過(guò)程的trace tag
                  Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
                  try {
                      // 從mView指向的View控件樹(shù)的根節(jié)點(diǎn)DecorView出發(fā),遍歷訪(fǎng)問(wèn)整個(gè)View樹(shù),并完成整個(gè)布局View樹(shù)的測(cè)量工作
                      mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
                  } finally {
                      Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                  }
          }

          private void performDraw() {
               ...
               boolean canUseAsync = draw(fullRedrawNeeded);
               ...
          }

          private boolean draw(boolean fullRedrawNeeded) {
              ...
              if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
                  ...
                  // 如果開(kāi)啟并支持硬件繪制加速,則走硬件繪制的流程(從Android 4.+開(kāi)始,默認(rèn)情況下都是支持跟開(kāi)啟了硬件加速的)
                  mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
              } else {
                  // 否則走drawSoftware軟件繪制的流程
                  if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
                                  scalingRequired, dirty, surfaceInsets)) {
                              return false;
                   }
              }
          }

          從上面的代碼流程可以看出,ViewRootImpl 中負(fù)責(zé)的整個(gè)應(yīng)用界面繪制的主要流程如下:

          1. 從界面 View 控件樹(shù)的根節(jié)點(diǎn) DecorView 出發(fā),遞歸遍歷整個(gè) View 控件樹(shù),完成對(duì)整個(gè) View 控件樹(shù)的 measure 測(cè)量操作,由于篇幅所限,本文就不展開(kāi)分析這塊的詳細(xì)流程;
          2. 界面第一次執(zhí)行繪制任務(wù)時(shí),會(huì)通過(guò) Binder IPC 訪(fǎng)問(wèn)系統(tǒng)窗口管理服務(wù) WMS 的 relayout 接口,實(shí)現(xiàn)窗口尺寸的計(jì)算并向系統(tǒng)申請(qǐng)用于本地繪制渲染的 Surface “畫(huà)布” 的操作(具體由 SurfaceFlinger 負(fù)責(zé)創(chuàng)建應(yīng)用界面對(duì)應(yīng)的 BufferQueueLayer 對(duì)象,并通過(guò)內(nèi)存共享的方式通過(guò) Binder 將地址引用透過(guò) WMS 回傳給應(yīng)用進(jìn)程這邊),由于篇幅所限,本文就不展開(kāi)分析這塊的詳細(xì)流程;
          3. 從界面 View 控件樹(shù)的根節(jié)點(diǎn) DecorView 出發(fā),遞歸遍歷整個(gè) View 控件樹(shù),完成對(duì)整個(gè) View 控件樹(shù)的 layout 測(cè)量操作;
          4. 從界面 View 控件樹(shù)的根節(jié)點(diǎn) DecorView 出發(fā),遞歸遍歷整個(gè) View 控件樹(shù),完成對(duì)整個(gè) View 控件樹(shù)的 draw 測(cè)量操作,如果開(kāi)啟并支持硬件繪制加速(從 Android 4.X 開(kāi)始谷歌已經(jīng)默認(rèn)開(kāi)啟硬件加速),則走 GPU 硬件繪制的流程,否則走 CPU 軟件繪制的流程;

          以上繪制過(guò)程從 systrace 上看如下圖所示:

          performTraversal 繪制
          relayoutWindow

          借用一張圖來(lái)總結(jié)應(yīng)用 UI 繪制的流程,如下所示:

          UI 繪制流程

          8. RenderThread 渲染

          截止到目前,在 ViewRootImpl 中完成了對(duì)界面的 measure、layout 和 draw 等繪制流程后,用戶(hù)依然還是看不到屏幕上顯示的應(yīng)用界面內(nèi)容,因?yàn)檎麄€(gè) Android 系統(tǒng)的顯示流程除了前面講到的 UI 線(xiàn)程的繪制外,界面還需要經(jīng)過(guò) RenderThread 線(xiàn)程的渲染處理,渲染完成后,還需要通過(guò) Binder 調(diào)用 “上幀” 交給 surfaceflinger 進(jìn)程中進(jìn)行合成后送顯才能最終顯示到屏幕上。本小節(jié)中,我們將接上一節(jié)中 ViewRootImpl 中最后 draw 的流程繼續(xù)往下分析開(kāi)啟硬件加速情況下,RenderThread 渲染線(xiàn)程的工作流程。由于目前 Android 4.X 之后系統(tǒng)默認(rèn)界面是開(kāi)啟硬件加速的,所以本文我們重點(diǎn)分析硬件加速條件下的界面渲染流程,我們先分析一下簡(jiǎn)化的代碼流程:

          /*frameworks/base/core/java/android/view/ViewRootImpl.java*/
          private boolean draw(boolean fullRedrawNeeded) {
              ...
              if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
                  ...
                  // 硬件加速條件下的界面渲染流程
                  mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
              } else {
                  ...
              }
          }

          /*frameworks/base/core/java/android/view/ThreadedRenderer.java*/
          void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
              ...
              // 1.從DecorView根節(jié)點(diǎn)出發(fā),遞歸遍歷View控件樹(shù),記錄每個(gè)View節(jié)點(diǎn)的繪制操作命令,完成繪制操作命令樹(shù)的構(gòu)建
              updateRootDisplayList(view, callbacks);
              ...
              // 2.JNI調(diào)用同步Java層構(gòu)建的繪制命令樹(shù)到Native層的RenderThread渲染線(xiàn)程,并喚醒渲染線(xiàn)程利用OpenGL執(zhí)行渲染任務(wù);
              int syncResult = syncAndDrawFrame(choreographer.mFrameInfo);
              ...
          }

          從上面的代碼可以看出,硬件加速繪制主要包括兩個(gè)階段:

          1. 從 DecorView 根節(jié)點(diǎn)出發(fā),遞歸遍歷 View 控件樹(shù),記錄每個(gè) View 節(jié)點(diǎn)的 drawOp 繪制操作命令,完成繪制操作命令樹(shù)的構(gòu)建;
          2. JNI 調(diào)用同步 Java 層構(gòu)建的繪制命令樹(shù)到 Native 層的 RenderThread 渲染線(xiàn)程,并喚醒渲染線(xiàn)程利用 OpenGL 執(zhí)行渲染任務(wù);

          8.1 構(gòu)建繪制命令樹(shù)

          我們先來(lái)看看第一階段構(gòu)建繪制命令樹(shù)的代碼簡(jiǎn)化流程:

          /*frameworks/base/core/java/android/view/ThreadedRenderer.java*/
          private void updateRootDisplayList(View view, DrawCallbacks callbacks) {
                  // 原生標(biāo)記構(gòu)建View繪制操作命令樹(shù)過(guò)程的systrace tag
                  Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
                  // 遞歸子View的updateDisplayListIfDirty實(shí)現(xiàn)構(gòu)建DisplayListOp
                  updateViewTreeDisplayList(view);
                  ...
                  if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {
                      // 獲取根View的SkiaRecordingCanvas
                      RecordingCanvas canvas = mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight);
                      try {
                          ...
                          // 利用canvas緩存DisplayListOp繪制命令
                          canvas.drawRenderNode(view.updateDisplayListIfDirty());
                          ...
                      } finally {
                          // 將所有DisplayListOp繪制命令填充到RootRenderNode中
                          mRootNode.endRecording();
                      }
                  }
                  Trace.traceEnd(Trace.TRACE_TAG_VIEW);
          }

          private void updateViewTreeDisplayList(View view) {
                  ...
                  // 從DecorView根節(jié)點(diǎn)出發(fā),開(kāi)始遞歸調(diào)用每個(gè)View樹(shù)節(jié)點(diǎn)的updateDisplayListIfDirty函數(shù)
                  view.updateDisplayListIfDirty();
                  ...
          }

          /*frameworks/base/core/java/android/view/View.java*/
          public RenderNode updateDisplayListIfDirty() {
               ...
               // 1.利用`View`對(duì)象構(gòu)造時(shí)創(chuàng)建的`RenderNode`獲取一個(gè)`SkiaRecordingCanvas`“畫(huà)布”;
               final RecordingCanvas canvas = renderNode.beginRecording(width, height);
               try {
                   ...
                   if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                        // 如果僅僅是ViewGroup,并且自身不用繪制,直接遞歸子View
                        dispatchDraw(canvas);
                        ...
                   } else {
                        // 2.利用SkiaRecordingCanvas,在每個(gè)子View控件的onDraw繪制函數(shù)中調(diào)用drawLine、drawRect等繪制操作時(shí),創(chuàng)建對(duì)應(yīng)的DisplayListOp繪制命令,并緩存記錄到其內(nèi)部的SkiaDisplayList持有的DisplayListData中;
                        draw(canvas);
                   }
               } finally {
                   // 3.將包含有`DisplayListOp`繪制命令緩存的`SkiaDisplayList`對(duì)象設(shè)置填充到`RenderNode`中;
                   renderNode.endRecording();
                   ...
               }
               ...
          }

          public void draw(Canvas canvas) {
              ...
              // draw the content(View自己實(shí)現(xiàn)的onDraw繪制,由應(yīng)用開(kāi)發(fā)者自己實(shí)現(xiàn))
              onDraw(canvas);
              ...
              // draw the children
              dispatchDraw(canvas);
              ...
          }

          /*frameworks/base/graphics/java/android/graphics/RenderNode.java*/
          public void endRecording() {
                  ...
                  // 從SkiaRecordingCanvas中獲取SkiaDisplayList對(duì)象
                  long displayList = canvas.finishRecording();
                  // 將SkiaDisplayList對(duì)象填充到RenderNode中
                  nSetDisplayList(mNativeRenderNode, displayList);
                  canvas.recycle();
          }

          從以上代碼可以看出,構(gòu)建繪制命令樹(shù)的過(guò)程是從 View 控件樹(shù)的根節(jié)點(diǎn) DecorView 觸發(fā),遞歸調(diào)用每個(gè)子 View 節(jié)點(diǎn)的 updateDisplayListIfDirty 函數(shù),最終完成繪制樹(shù)的創(chuàng)建,簡(jiǎn)述流程如下:

          1. 利用 View 對(duì)象構(gòu)造時(shí)創(chuàng)建的 RenderNode 獲取一個(gè) SkiaRecordingCanvas “畫(huà)布”;
          2. 利用 SkiaRecordingCanvas,在每個(gè)子 View 控件的 onDraw 繪制函數(shù)中調(diào)用 drawLine、drawRect 等繪制操作時(shí),創(chuàng)建對(duì)應(yīng)的 DisplayListOp 繪制命令,并緩存記錄到其內(nèi)部的 SkiaDisplayList 持有的 DisplayListData 中;
          3. 將包含有 DisplayListOp 繪制命令緩存的 SkiaDisplayList 對(duì)象設(shè)置填充到 RenderNode 中;
          4. 最后將根 View 的緩存 DisplayListOp 設(shè)置到 RootRenderNode 中,完成構(gòu)建。

          以上整個(gè)構(gòu)建繪制命令樹(shù)的過(guò)程可以用如下流程圖表示:

          硬件加速繪制之繪制命令樹(shù)構(gòu)建

          硬件加速下的整個(gè)界面的 View 樹(shù)的結(jié)構(gòu)如下圖所示:

          硬件繪制下的 View 樹(shù)結(jié)構(gòu)

          最后從 systrace 上看這個(gè)過(guò)程如下圖所示:

          構(gòu)建 View 繪制命令樹(shù)

          8.2 執(zhí)行渲染繪制任務(wù)

          經(jīng)過(guò)上一小節(jié)中的分析,應(yīng)用在 UI 線(xiàn)程中從根節(jié)點(diǎn) DecorView 出發(fā),遞歸遍歷每個(gè)子 View 節(jié)點(diǎn),搜集其 drawXXX 繪制動(dòng)作并轉(zhuǎn)換成 DisplayListOp 命令,將其記錄到 DisplayListData 并填充到 RenderNode 中,最終完成整個(gè) View 繪制命令樹(shù)的構(gòu)建。從此 UI 線(xiàn)程的繪制任務(wù)就完成了。下一步 UI 線(xiàn)程將喚醒 RenderThread 渲染線(xiàn)程,觸發(fā)其利用 OpenGL 執(zhí)行界面的渲染任務(wù),本小節(jié)中我們將重點(diǎn)分析這個(gè)流程。我們還是先看看這塊代碼的簡(jiǎn)化流程:

          /*frameworks/base/graphics/java/android/graphics/HardwareRenderer.java*/
          public int syncAndDrawFrame(@NonNull FrameInfo frameInfo) {
              // JNI調(diào)用native層的相關(guān)函數(shù)
              return nSyncAndDrawFrame(mNativeProxy, frameInfo.frameInfo, frameInfo.frameInfo.length);
          }

          /*frameworks/base/libs/hwui/jni/android_graphics_HardwareRenderer.cpp*/
          static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
                  jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
              ...
              RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
              env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
              return proxy->syncAndDrawFrame();
          }

          /*frameworks/base/libs/hwui/renderthread/RenderProxy.cpp*/
          int RenderProxy::syncAndDrawFrame() {
              // 喚醒RenderThread渲染線(xiàn)程,執(zhí)行DrawFrame繪制任務(wù)
              return mDrawFrameTask.drawFrame();
          }

          /*frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp*/
          int DrawFrameTask::drawFrame() {
              ...
              postAndWait();
              ...
          }

          void DrawFrameTask::postAndWait() {
              AutoMutex _lock(mLock);
              // 向RenderThread渲染線(xiàn)程的MessageQueue消息隊(duì)列放入一個(gè)待執(zhí)行任務(wù),以將其喚醒執(zhí)行run函數(shù)
              mRenderThread->queue().post([this]() { run(); });
              // UI線(xiàn)程暫時(shí)進(jìn)入wait等待狀態(tài)
              mSignal.wait(mLock);
          }

          void DrawFrameTask::run() {
              // 原生標(biāo)識(shí)一幀渲染繪制任務(wù)的systrace tag
              ATRACE_NAME("DrawFrame");
              ...
              {
                  TreeInfo info(TreeInfo::MODE_FULL, *mContext);
                  //1.將UI線(xiàn)程構(gòu)建的DisplayListOp繪制命令樹(shù)同步到RenderThread渲染線(xiàn)程
                  canUnblockUiThread = syncFrameState(info);
                  ...
              }
              ...
              // 同步完成后則可以喚醒UI線(xiàn)程
              if (canUnblockUiThread) {
                  unblockUiThread();
              }
              ...
              if (CC_LIKELY(canDrawThisFrame)) {
                  // 2.執(zhí)行draw渲染繪制動(dòng)作
                  context->draw();
              } else {
                  ...
              }
              ...
          }

          bool DrawFrameTask::syncFrameState(TreeInfo& info) {
              ATRACE_CALL();
              ...
              // 調(diào)用CanvasContext的prepareTree函數(shù)實(shí)現(xiàn)繪制命令樹(shù)同步的流程
              mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
              ...
          }

          /*frameworks/base/libs/hwui/renderthread/CanvasContext.cpp*/
          void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued,
                                          RenderNode* target) {
               ...
               for (const sp<RenderNode>& node : mRenderNodes) {
                  ...
                  // 遞歸調(diào)用各個(gè)子View對(duì)應(yīng)的RenderNode執(zhí)行prepareTree動(dòng)作
                  node->prepareTree(info);
                  ...
              }
              ...
          }

          /*frameworks/base/libs/hwui/RenderNode.cpp*/
          void RenderNode::prepareTree(TreeInfo& info) {
              ATRACE_CALL();
              ...
              prepareTreeImpl(observer, info, false);
              ...
          }

          void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) {
              ...
              if (info.mode == TreeInfo::MODE_FULL) {
                  // 同步繪制命令樹(shù)
                  pushStagingDisplayListChanges(observer, info);
              }
              if (mDisplayList) {
                  // 遍歷調(diào)用各個(gè)子View對(duì)應(yīng)的RenderNode的prepareTreeImpl
                  bool isDirty = mDisplayList->prepareListAndChildren(
                          observer, info, childFunctorsNeedLayer,
                          [](RenderNode* child, TreeObserver& observer, TreeInfo& info,
                             bool functorsNeedLayer) {
                              child->prepareTreeImpl(observer, info, functorsNeedLayer);
                          });
                  ...
              }
              ...
          }

          void RenderNode::pushStagingDisplayListChanges(TreeObserver& observer, TreeInfo& info) {
              ...
              syncDisplayList(observer, &info);
              ...
          }

          void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
              ...
              // 完成賦值同步DisplayList對(duì)象
              mDisplayList = mStagingDisplayList;
              mStagingDisplayList = nullptr;
              ...
          }

          void CanvasContext::draw() {
              ...
              // 1.調(diào)用OpenGL庫(kù)使用GPU,按照構(gòu)建好的繪制命令完成界面的渲染
              bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
                                                mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
                                                &(profiler()));
              ...
              // 2.將前面已經(jīng)繪制渲染好的圖形緩沖區(qū)Binder上幀給SurfaceFlinger合成和顯示
              bool didSwap =
                      mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
              ...
          }

          從以上代碼可以看出:UI 線(xiàn)程利用 RenderProxy 向 RenderThread 線(xiàn)程發(fā)送一個(gè) DrawFrameTask 任務(wù)請(qǐng)求,RenderThread 被喚醒,開(kāi)始渲染,大致流程如下:

          1. syncFrameState 中遍歷 View 樹(shù)上每一個(gè) RenderNode,執(zhí)行 prepareTreeImpl 函數(shù),實(shí)現(xiàn)同步繪制命令樹(shù)的操作;
          2. 調(diào)用 OpenGL 庫(kù) API 使用 GPU,按照構(gòu)建好的繪制命令完成界面的渲染(具體過(guò)程,由于本文篇幅所限,暫不展開(kāi)分析);
          3. 將前面已經(jīng)繪制渲染好的圖形緩沖區(qū) Binder 上幀給 SurfaceFlinger 合成和顯示;

          整個(gè)過(guò)程可以用如下流程圖表示

          RenderThread 線(xiàn)程渲染流程

          從 systrace 上這個(gè)過(guò)程如下圖所示:

          RenderThread 實(shí)現(xiàn)界面渲染

          9. SurfaceFlinger 合成顯示

          SurfaceFlinger 合成顯示部分完全屬于 Android 系統(tǒng) GUI 中圖形顯示的內(nèi)容,邏輯結(jié)構(gòu)也比較復(fù)雜,但不屬于本文介紹內(nèi)容的重點(diǎn)。所以本小節(jié)中只是總體上介紹一下其工作原理與思想,不再詳細(xì)分析源碼,感興趣的讀者可以關(guān)注筆者后續(xù)的文章再來(lái)詳細(xì)分析講解。簡(jiǎn)單的說(shuō) SurfaceFlinger 作為系統(tǒng)中獨(dú)立運(yùn)行的一個(gè) Native 進(jìn)程,借用 Android 官網(wǎng)的描述,其職責(zé)就是負(fù)責(zé)接受來(lái)自多個(gè)來(lái)源的數(shù)據(jù)緩沖區(qū),對(duì)它們進(jìn)行合成,然后發(fā)送到顯示設(shè)備。如下圖所示:

          SurfaceFlinger 工作原理

          從上圖可以看出,其實(shí) SurfaceFlinger 在 Android 系統(tǒng)的整個(gè)圖形顯示系統(tǒng)中是起到一個(gè)承上啟下的作用:

          1. 對(duì)上:通過(guò) Surface 與不同的應(yīng)用進(jìn)程建立聯(lián)系,接收它們寫(xiě)入 Surface 中的繪制緩沖數(shù)據(jù),對(duì)它們進(jìn)行統(tǒng)一合成。
          2. 對(duì)下:通過(guò)屏幕的后緩存區(qū)與屏幕建立聯(lián)系,發(fā)送合成好的數(shù)據(jù)到屏幕顯示設(shè)備。

          圖形的傳遞是通過(guò) Buffer 作為載體,Surface 是對(duì) Buffer 的進(jìn)一步封裝,也就是說(shuō) Surface 內(nèi)部具有多個(gè) Buffer 供上層使用,如何管理這些 Buffer 呢?答案就是 BufferQueue ,下面我們來(lái)看看 BufferQueue 的工作原理:

          9.1 BufferQueue 機(jī)制

          借用一張經(jīng)典的圖來(lái)描述 BufferQueue 的工作原理:

          BufferQueue 狀態(tài)轉(zhuǎn)換圖

          BufferQueue 是一個(gè)典型的生產(chǎn)者 - 消費(fèi)者模型中的數(shù)據(jù)結(jié)構(gòu)。在 Android 應(yīng)用的渲染流程中,應(yīng)用扮演的就是 “生產(chǎn)者” 的角色,而 SurfaceFlinger 扮演的則是 “消費(fèi)者” 的角色,其配合工作的流程如下:

          1. 應(yīng)用進(jìn)程中在開(kāi)始界面的繪制渲染之前,需要通過(guò) Binder 調(diào)用 dequeueBuffer 接口從 SurfaceFlinger 進(jìn)程中管理的 BufferQueue 中申請(qǐng)一張?zhí)幱?free 狀態(tài)的可用 Buffer,如果此時(shí)沒(méi)有可用 Buffer 則阻塞等待;
          2. 應(yīng)用進(jìn)程中拿到這張可用的 Buffer 之后,選擇使用 CPU 軟件繪制渲染或 GPU 硬件加速繪制渲染,渲染完成后再通過(guò) Binder 調(diào)用 queueBuffer 接口將緩存數(shù)據(jù)返回給應(yīng)用進(jìn)程對(duì)應(yīng)的 BufferQueue(如果是 GPU 渲染的話(huà),這里還有個(gè) GPU 處理的過(guò)程,所以這個(gè) Buffer 不會(huì)馬上可用,需要等 GPU 渲染完成的 Fence 信號(hào)),并申請(qǐng) sf 類(lèi)型的 Vsync 以便喚醒 “消費(fèi)者” SurfaceFlinger 進(jìn)行消費(fèi);
          3. SurfaceFlinger 在收到 Vsync 信號(hào)之后,開(kāi)始準(zhǔn)備合成,使用 acquireBuffer 獲取應(yīng)用對(duì)應(yīng)的 BufferQueue 中的 Buffer 并進(jìn)行合成操作;
          4. 合成結(jié)束后,SurfaceFlinger 將通過(guò)調(diào)用 releaseBuffer 將 Buffer 置為可用的 free 狀態(tài),返回到應(yīng)用對(duì)應(yīng)的 BufferQueue 中。

          9.2 Vsync 同步機(jī)制

          Vysnc 垂直同步是 Android 在 “黃油計(jì)劃” 中引入的一個(gè)重要機(jī)制,本質(zhì)上是為了協(xié)調(diào) BufferQueue 的應(yīng)用生產(chǎn)者生成 UI 數(shù)據(jù)動(dòng)作和 SurfaceFlinger 消費(fèi)者的合成消費(fèi)動(dòng)作,避免出現(xiàn)畫(huà)面撕裂的 Tearing 現(xiàn)象。Vysnc 信號(hào)分為兩種類(lèi)型:

          1. app 類(lèi)型的 Vsync:app 類(lèi)型的 Vysnc 信號(hào)由上層應(yīng)用中的 Choreographer 根據(jù)繪制需求進(jìn)行注冊(cè)和接收,用于控制應(yīng)用 UI 繪制上幀的生產(chǎn)節(jié)奏。根據(jù)第 7 小結(jié)中的分析:應(yīng)用在 UI 線(xiàn)程中調(diào)用 invalidate 刷新界面繪制時(shí),需要先透過(guò) Choreographer 向系統(tǒng)申請(qǐng)注冊(cè) app 類(lèi)型的 Vsync 信號(hào),待 Vsync 信號(hào)到來(lái)后,才能往主線(xiàn)程的消息隊(duì)列放入待繪制任務(wù)進(jìn)行真正 UI 的繪制動(dòng)作;
          2. sf 類(lèi)型的 Vsync: sf 類(lèi)型的 Vsync 是用于控制 SurfaceFlinger 的合成消費(fèi)節(jié)奏。應(yīng)用完成界面的繪制渲染后,通過(guò) Binder 調(diào)用 queueBuffer 接口將緩存數(shù)據(jù)返還給應(yīng)用對(duì)應(yīng)的 BufferQueue 時(shí),會(huì)申請(qǐng) sf 類(lèi)型的 Vsync,待 SurfaceFlinger 在其 UI 線(xiàn)程中收到 Vsync 信號(hào)之后,便開(kāi)始進(jìn)行界面的合成操作。

          Vsync 信號(hào)的生成是參考屏幕硬件的刷新周期的,其架構(gòu)如下圖所示:

          Vsync

          本小節(jié)所描述的流程,從 systrace 上看 SurfaceFlinger 處理應(yīng)用上幀工作的流程如下圖所示:

          requestVsync
          SurfaceFlinger 處理

          10. 寫(xiě)在最后

          至此,本文結(jié)合源碼和 systrace 完整的分析了從用戶(hù)手指點(diǎn)擊桌面上的應(yīng)用圖標(biāo)到屏幕上顯示出應(yīng)用主 Activity 界面第一幀畫(huà)面的完整流程,這其中涉及了 App 應(yīng)用、system_server 框架、Art 虛擬機(jī)、surfaceflinger 等一系列 Android 系統(tǒng)核心模塊的相互配合,有很多的細(xì)節(jié)也由于篇幅所限無(wú)法完全展開(kāi)分析,感興趣的讀者可以結(jié)合 AOSP 源碼繼續(xù)深入分析。而優(yōu)化應(yīng)用啟動(dòng)打開(kāi)的速度這個(gè)系統(tǒng)核心用戶(hù)體驗(yàn)的指標(biāo),也是多少年來(lái)谷歌、SOC 芯片廠(chǎng)商、ODM 手機(jī)廠(chǎng)商以及各個(gè)應(yīng)用開(kāi)發(fā)者共同努力優(yōu)化的方向:

          1. 對(duì)于 SOC 芯片廠(chǎng)商而言:需要不斷升級(jí) CPU 和 GPU 的硬件算力;
          2. 對(duì)于 Android 系統(tǒng)的維護(hù)者谷歌而言:在 Android 系統(tǒng)大版本升級(jí)過(guò)程中,不斷的優(yōu)化應(yīng)用啟動(dòng)過(guò)程上的各個(gè)系統(tǒng)流程,比如進(jìn)程創(chuàng)建的速度優(yōu)化、Art 虛擬機(jī)的引入與性能優(yōu)化、View 繪制流程的簡(jiǎn)化、硬件繪制加速機(jī)制的引入、系統(tǒng)核心 AMS、WMS 等核心服務(wù)的鎖優(yōu)化等;
          3. 對(duì)于各個(gè) ODM 手機(jī)廠(chǎng)商而言:會(huì)開(kāi)發(fā)識(shí)別應(yīng)用啟動(dòng)的場(chǎng)景,進(jìn)行針對(duì)性的 CPU 主頻的拉升調(diào)節(jié)、觸控響應(yīng)速度的優(yōu)化等機(jī)制;
          4. 對(duì)于各個(gè)應(yīng)用開(kāi)發(fā)者而言:會(huì)結(jié)合自己的業(yè)務(wù)對(duì)應(yīng)用啟動(dòng)的場(chǎng)景進(jìn)行優(yōu)化,比如盡量減少或推遲在 Application、Activity 生命周期函數(shù)中的初始化邏輯、去除界面布局的過(guò)度繪制、異步化的布局 XML 文件解析等機(jī)制。

          本文只是分析了應(yīng)用啟動(dòng)一般性流程,至于如何去優(yōu)化應(yīng)用啟動(dòng)的速度,可以關(guān)注筆者后續(xù)文章的更新,而本文則可以作為應(yīng)用啟動(dòng)優(yōu)化課題的一個(gè)基礎(chǔ)認(rèn)知。最后用一張流程圖來(lái)概述一下應(yīng)用啟動(dòng)流程的全貌:

          應(yīng)用冷啟動(dòng)流程

          11. 參考

          1. Systrace 流暢性實(shí)戰(zhàn) 1 :了解卡頓原理 https://www.androidperformance.com/2021/04/24/android-systrace-smooth-in-action-1/
          2. 史上最全 Android 渲染機(jī)制講解(長(zhǎng)文源碼深度剖析)https://mp.weixin.qq.com/s?__biz=MzU2MTk0ODUxOQ==&mid=2247483782&idx=1&sn=f9eae167b217c83036b3a24cd4182cd1&chksm=fc71b38ecb063a9847f4518802fc541091d7f708b112399ec39827e68a6f590249748d643747&mpshare=1&scene=1&srcid=0224RGsfWeG5GyMpxLwEhx7N&sharer_sharetime=1582507745901&sharer_shareid=2d76fc4769fc55b6ca84ec3820ba5821#rd
          3. 理解 Android 硬件加速原理的小白文 https://www.jianshu.com/p/40f660e17a73



          ·················END·················

          推薦閱讀

          ? 耗時(shí)2年,Android進(jìn)階三部曲第三部《Android進(jìn)階指北》出版!

          ? 『BATcoder』做了多年安卓還沒(méi)編譯過(guò)源碼?一個(gè)視頻帶你玩轉(zhuǎn)!

          ? 『BATcoder』我去!安裝Ubuntu還有坑?

          ? 重生!進(jìn)階三部曲第一部《Android進(jìn)階之光》第2版 出版!

          BATcoder技術(shù)群,讓一部分人先進(jìn)大廠(chǎng)

          大家,我是劉望舒,騰訊TVP,著有三本業(yè)內(nèi)知名暢銷(xiāo)書(shū),連續(xù)四年蟬聯(lián)電子工業(yè)出版社年度優(yōu)秀作者,谷歌開(kāi)發(fā)者社區(qū)特邀講師,百度百科收錄的高級(jí)技術(shù)專(zhuān)家。

          前華為技術(shù)專(zhuān)家,現(xiàn)大廠(chǎng)技術(shù)總監(jiān)。


          想要加入 BATcoder技術(shù)群,公號(hào)回復(fù)BAT 即可。

          為了防止失聯(lián),歡迎關(guān)注我的小號(hào)

            微信改了推送機(jī)制,真愛(ài)請(qǐng)星標(biāo)本公號(hào)??
          瀏覽 154
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  WWW日本色情视频 | 天天草人人草 | 亚洲欧洲日韩在线蜜桃 | AV亚洲天堂网 | 亚洲不卡黄色网址 |