OpenHarmony ArkUI - ets_runtime啟動(dòng)流程源碼解讀
??想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):??
??51CTO 開(kāi)源基礎(chǔ)軟件社區(qū)??
前言
本文基于OpenHarmony源碼梳理應(yīng)用的啟動(dòng)過(guò)程,介紹appspawn/ability_runtime/ace_engine/ets_runtime等重要模塊的初始化流程,以及它們之間的相互關(guān)系。
不同形態(tài)的hap應(yīng)用在具體細(xì)節(jié)上會(huì)有一些差異,但整體的流程上是一致的。本文基于OpenHarmoney 3.2標(biāo)準(zhǔn)系統(tǒng) FA模式的ets應(yīng)用進(jìn)行闡述。
1、應(yīng)用啟動(dòng)整體流程
查看各個(gè)進(jìn)程的父子關(guān)系可知,OpenHarmony的系統(tǒng)應(yīng)用和用戶應(yīng)用進(jìn)程,都是由應(yīng)用孵化器(appspawn)拉起的。
應(yīng)用啟動(dòng)的整理流程如下圖所示:
說(shuō)明: 應(yīng)用啟動(dòng)時(shí),appspawn進(jìn)程會(huì)fork出一個(gè)應(yīng)用子進(jìn)程,創(chuàng)建AceAbility實(shí)現(xiàn)類和AceContainer。AceContainer初始化過(guò)程中會(huì)在JS線程中創(chuàng)建JS運(yùn)行環(huán)境,包括JsEngine、NativeEngin、ArkJSRuntime、JSThread、EcmaVM等重要組件。
2、啟動(dòng)流程詳解
(1)appspawn 創(chuàng)建應(yīng)用進(jìn)程
應(yīng)用日志:
關(guān)鍵代碼流程:
(2)應(yīng)用主線程初始化Ability
應(yīng)用的整體狀態(tài)流轉(zhuǎn)是由Ability實(shí)例對(duì)象來(lái)控制完成的。因此應(yīng)用進(jìn)程拉起時(shí),會(huì)先創(chuàng)建出Ability。不同的應(yīng)用模型在這里會(huì)創(chuàng)建不同的實(shí)例類型:
AbilityImpl實(shí)例創(chuàng)建后,應(yīng)用開(kāi)始進(jìn)入Start狀態(tài),觸發(fā)AceAbility::OnStart()回調(diào)。在該回調(diào)中,會(huì)創(chuàng)建JS運(yùn)行環(huán)境。
(3)AceContainer初始化
AceContainer初始化可分為兩個(gè)階段:
第一個(gè)階段創(chuàng)建JS運(yùn)行時(shí)環(huán)境(js_engine, native_engine, ets_runtime);
第二個(gè)階段調(diào)度js_engine開(kāi)始讀取js字節(jié)碼文件(xxx.abc)
階段一:創(chuàng)建JS運(yùn)行時(shí)環(huán)境
這里的代碼流程比較長(zhǎng)… 具體調(diào)用過(guò)程見(jiàn)上圖說(shuō)明。講幾個(gè)主要的點(diǎn):
- AceContianer初始化時(shí)會(huì)創(chuàng)建一個(gè)任務(wù)執(zhí)行線程 FlutterTaskExecutor,這就是后續(xù)js代碼的執(zhí)行線程。 應(yīng)用主線程把需要在js線程中執(zhí)行的代碼包裝成task,放到FlutterTaskExecutor中去執(zhí)行。
- 創(chuàng)建Js引擎時(shí)可以選擇不同的引擎類型,這是在源碼編譯階段由宏開(kāi)關(guān)控制的。
\foundation\arkui\ace_engine\frameworks\bridge\declarative_frontend\engine\declarative_engine_loader.cpp
宏開(kāi)關(guān)在如下配置文件中定義:
foundation/arkui/ace_engine/adapter/ohos/build/config.gni。
- ArkNativeEngine初始化時(shí)創(chuàng)建了NAPI層的各個(gè)重要組件(moduleManager, scopeManager, referenceManager, loop…)
- ArkNativeEngine向js運(yùn)行環(huán)境中注冊(cè)了一個(gè)"requireNapi()"方法,該方法是js應(yīng)用import各種NAPI庫(kù)的入口。
js代碼中的"import xxxx"在hap包編譯階段會(huì)改寫為“requireNapi(xxx)”,當(dāng)這行代碼被js引擎解釋執(zhí)行時(shí),即會(huì)調(diào)用到 ArkNativeEngine 中注冊(cè)的requireNapi c++實(shí)現(xiàn)代碼,通過(guò)NAPI的ModuleManager 模塊完成 xxxNAPI模塊lib庫(kù)的加載。
階段二:讀取并執(zhí)行js字節(jié)碼文件
在 AceContainer::RunPage() 流程中,會(huì)依次創(chuàng)建兩個(gè)js線程的task, 分別讀取 app.abc和index.abc文件。
細(xì)節(jié)1: JsiDeclarativeEngine::LoadJs()方法中是根據(jù)傳入的*.js文件名去讀取對(duì)應(yīng)的*.abc
細(xì)節(jié)2:EcmaVM::InvokeEcmaEntrypoint() 方法中會(huì)執(zhí)行index.abc中的入口函數(shù)func_main_0, 該函數(shù)在原始的index.js文件中并沒(méi)有,是hap包編譯后生成在index.abc文件中的。
??想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):??