Android 應(yīng)用啟動(dòng)全流程深度剖析!(建議收藏)
本文是努比亞技術(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ò)程大致流程如下:
InputReader 負(fù)責(zé)從 EventHub 里面把 Input 事件讀取出來(lái),然后交給 InputDispatcher 進(jìn)行事件分發(fā); InputDispatcher 在拿到 InputReader 獲取的事件之后,對(duì)事件進(jìn)行包裝后,尋找并分發(fā)到目標(biāo)窗口; InboundQueue 隊(duì)列(“iq”)中放著 InputDispatcher 從 InputReader 中拿到的 input 事件; OutboundQueue(“oq”)隊(duì)列里面放的是即將要被派發(fā)給各個(gè)目標(biāo)窗口 App 的事件; WaitQueue 隊(duì)列里面記錄的是已經(jīng)派發(fā)給 App(“wq”),但是 App 還在處理沒(méi)有返回處理成功的事件; PendingInputEventQueue 隊(duì)列(“aq”)中記錄的是應(yīng)用需要處理的 Input 事件,這里可以看到 input 事件已經(jīng)傳遞到了應(yīng)用進(jìn)程; deliverInputEvent 標(biāo)識(shí) App UI Thread 被 Input 事件喚醒; InputResponse 標(biāo)識(shí) Input 事件區(qū)域,這里可以看到一個(gè) Input_Down 事件 + 若干個(gè) Input_Move 事件 + 一個(gè) Input_Up 事件的處理階段都被算到了這里; 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 截圖所示:

接著上面的流程繼續(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 異常。

桌面應(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 上看如下圖所示:

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 上看,如下圖所示:
通知 pause 桌面應(yīng)用:

確認(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)如下圖所示:

我們接著上節(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)程的邏輯:
openZygoteSocketIfNeeded 函數(shù)中打開(kāi)本地 socket 客戶(hù)端連接到 zygote 進(jìn)程的 socket 服務(wù)端; zygoteSendArgsAndGetResult 發(fā)送 socket 請(qǐng)求參數(shù),帶上了創(chuàng)建的應(yīng)用進(jìn)程參數(shù)信息; return 返回的數(shù)據(jù)結(jié)構(gòu) ProcessStartResult 中會(huì)有新創(chuàng)建的進(jìn)程的 pid 字段。
從 systrace 上看這個(gè)過(guò)程如下:

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 上看如下圖所示:

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ò)程中主要依次完成以下幾件事情:
應(yīng)用進(jìn)程默認(rèn)的 java 異常處理機(jī)制(可以實(shí)現(xiàn)監(jiān)聽(tīng)、攔截應(yīng)用進(jìn)程所有的 Java crash 的邏輯); JNI 調(diào)用啟動(dòng)進(jìn)程的 binder 線(xiàn)程池(注意應(yīng)用進(jìn)程的 binder 線(xiàn)程池資源是自己創(chuàng)建的并非從 zygote 父進(jìn)程繼承的); 通過(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ù)初始化的主要邏輯是:
創(chuàng)建并啟動(dòng)主線(xiàn)程的 loop 消息循環(huán); 通過(guò) binder 調(diào)用 AMS 的 attachApplication 接口將自己 attach 注冊(cè)到 AMS 中。
以上初始化過(guò)程。從 systrace 上看如下圖所示:

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)行原理如下圖所示:

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。 Looper : Looper 可以看成是一個(gè)循環(huán)器,其 loop 方法開(kāi)啟后,不斷地從 MessageQueue 中獲取 Message,對(duì) Message 進(jìn)行 Delivery 和 Dispatch,最終發(fā)給對(duì)應(yīng)的 Handler 去處理。 MessageQueue:MessageQueue 就是一個(gè) Message 管理器,隊(duì)列中是 Message,在沒(méi)有 Message 的時(shí)候,MessageQueue 借助 Linux 的 ePoll 機(jī)制,阻塞休眠等待,直到有 Message 進(jìn)入隊(duì)列將其喚醒。 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)求的:

我們繼續(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 看如下圖所示:

我們繼續(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)程中主要完成如下幾件事件 **:
根據(jù)框架傳入的 ApplicationInfo 信息創(chuàng)建應(yīng)用 APK 對(duì)應(yīng)的 LoadedApk 對(duì)象; 創(chuàng)建應(yīng)用 Application 的 Context 對(duì)象; 創(chuàng)建類(lèi)加載器 ClassLoader 對(duì)象并觸發(fā) Art 虛擬機(jī)執(zhí)行 OpenDexFilesFromOat 動(dòng)作加載應(yīng)用 APK 的 Dex 文件; 通過(guò) LoadedApk 加載應(yīng)用 APK 的 Resource 資源; 調(diào)用 LoadedApk 的 makeApplication 函數(shù),創(chuàng)建應(yīng)用的 Application 對(duì)象; 執(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 上看如下圖所示:

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

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 上看如下圖所示:

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 的流程主要步驟如下:
創(chuàng)建 Activity 的 Context; 通過(guò)反射創(chuàng)建 Activity 對(duì)象; 執(zhí)行 Activity 的 attach 動(dòng)作,其中會(huì)創(chuàng)建應(yīng)用窗口的 PhoneWindow 對(duì)象并設(shè)置 WindowManage; 執(zhí)行應(yīng)用 Activity 的 onCreate 生命周期函數(shù),并在 setContentView 中創(chuàng)建窗口的 DecorView 對(duì)象;從 systrace 上看整個(gè)過(guò)程如下圖所示:

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 的流程主要步驟如下:
執(zhí)行應(yīng)用 Activity 的 onResume 生命周期函數(shù); 執(zhí)行 WindowManager 的 addView 動(dòng)作開(kāi)啟視圖繪制邏輯; 創(chuàng)建 Activity 的 ViewRootImpl 對(duì)象; 執(zhí)行 ViewRootImpl 的 setView 函數(shù)開(kāi)啟 UI 界面繪制動(dòng)作;
從 systrace 上看整個(gè)過(guò)程如下圖所示:

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)如下圖所示:

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); DecorView 是整個(gè)界面布局 View 控件樹(shù)的根節(jié)點(diǎn),通過(guò)它可以遍歷訪(fǎng)問(wèn)到整個(gè) View 控件樹(shù)上的任意節(jié)點(diǎn); WindowManager 是一個(gè)接口,繼承自 ViewManager 接口,提供了 View 的基本操作方法;WindowManagerImp 實(shí)現(xiàn)了 WindowManager 接口,內(nèi)部通過(guò)組合方式持有 WindowManagerGlobal,用來(lái)操作 View;WindowManagerGlobal 是一個(gè)全局單例,內(nèi)部可以通過(guò) ViewRootImpl 將 View 添加至窗口中; 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)鍵流程如下:
requestLayout () 通過(guò)一系列調(diào)用觸發(fā)界面繪制(measure、layout、draw)動(dòng)作,下文會(huì)詳細(xì)展開(kāi)分析; 通過(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)分析了。 創(chuàng)建 WindowInputEventReceiver 對(duì)象,封裝實(shí)現(xiàn)應(yīng)用窗口接收系統(tǒng)觸控事件的邏輯; 執(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 渲染鏈路中承上啟下的角色:
承上:負(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í)等; 啟下:負(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)部的工作流程如下圖所示:

從以上流程圖可以看出: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 上看如下圖所示:

我們接著 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)用界面繪制的主要流程如下:
從界面 View 控件樹(shù)的根節(jié)點(diǎn) DecorView 出發(fā),遞歸遍歷整個(gè) View 控件樹(shù),完成對(duì)整個(gè) View 控件樹(shù)的 measure 測(cè)量操作,由于篇幅所限,本文就不展開(kāi)分析這塊的詳細(xì)流程; 界面第一次執(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ì)流程; 從界面 View 控件樹(shù)的根節(jié)點(diǎn) DecorView 出發(fā),遞歸遍歷整個(gè) View 控件樹(shù),完成對(duì)整個(gè) View 控件樹(shù)的 layout 測(cè)量操作; 從界面 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 上看如下圖所示:


借用一張圖來(lái)總結(jié)應(yīng)用 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è)階段:
從 DecorView 根節(jié)點(diǎn)出發(fā),遞歸遍歷 View 控件樹(shù),記錄每個(gè) View 節(jié)點(diǎn)的 drawOp 繪制操作命令,完成繪制操作命令樹(shù)的構(gòu)建; 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)述流程如下:
利用 View 對(duì)象構(gòu)造時(shí)創(chuàng)建的 RenderNode 獲取一個(gè) SkiaRecordingCanvas “畫(huà)布”; 利用 SkiaRecordingCanvas,在每個(gè)子 View 控件的 onDraw 繪制函數(shù)中調(diào)用 drawLine、drawRect 等繪制操作時(shí),創(chuàng)建對(duì)應(yīng)的 DisplayListOp 繪制命令,并緩存記錄到其內(nèi)部的 SkiaDisplayList 持有的 DisplayListData 中; 將包含有 DisplayListOp 繪制命令緩存的 SkiaDisplayList 對(duì)象設(shè)置填充到 RenderNode 中; 最后將根 View 的緩存 DisplayListOp 設(shè)置到 RootRenderNode 中,完成構(gòu)建。
以上整個(gè)構(gòu)建繪制命令樹(shù)的過(guò)程可以用如下流程圖表示:

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

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

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

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

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è)備。如下圖所示:

從上圖可以看出,其實(shí) SurfaceFlinger 在 Android 系統(tǒng)的整個(gè)圖形顯示系統(tǒng)中是起到一個(gè)承上啟下的作用:
對(duì)上:通過(guò) Surface 與不同的應(yīng)用進(jìn)程建立聯(lián)系,接收它們寫(xiě)入 Surface 中的繪制緩沖數(shù)據(jù),對(duì)它們進(jìn)行統(tǒng)一合成。 對(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 是一個(gè)典型的生產(chǎn)者 - 消費(fèi)者模型中的數(shù)據(jù)結(jié)構(gòu)。在 Android 應(yīng)用的渲染流程中,應(yīng)用扮演的就是 “生產(chǎn)者” 的角色,而 SurfaceFlinger 扮演的則是 “消費(fèi)者” 的角色,其配合工作的流程如下:
應(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 則阻塞等待; 應(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); SurfaceFlinger 在收到 Vsync 信號(hào)之后,開(kāi)始準(zhǔn)備合成,使用 acquireBuffer 獲取應(yīng)用對(duì)應(yīng)的 BufferQueue 中的 Buffer 并進(jìn)行合成操作; 合成結(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)型:
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)作; 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)如下圖所示:

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


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)化的方向:
對(duì)于 SOC 芯片廠(chǎng)商而言:需要不斷升級(jí) CPU 和 GPU 的硬件算力; 對(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)化等; 對(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ī)制; 對(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)流程的全貌:

11. 參考
Systrace 流暢性實(shí)戰(zhàn) 1 :了解卡頓原理 https://www.androidperformance.com/2021/04/24/android-systrace-smooth-in-action-1/ 史上最全 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 理解 Android 硬件加速原理的小白文 https://www.jianshu.com/p/40f660e17a73
推薦閱讀
? 耗時(shí)2年,Android進(jìn)階三部曲第三部《Android進(jìn)階指北》出版!
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)??
