OpenHarmony ArkUI - ets_runtime启动流程源码解读

系统 OpenHarmony
本文基于OpenHarmony源码梳理应用的启动过程,介绍Appspawn/ability_runtime/ace_engine/ets_runtime等重要模块的初始化流程,以及它们之间的相互关系。

想了解更多关于开源的内容,请访问:

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

前言

本文基于OpenHarmony源码梳理应用的启动过程,介绍appspawn/ability_runtime/ace_engine/ets_runtime等重要模块的初始化流程,以及它们之间的相互关系。

不同形态的hap应用在具体细节上会有一些差异,但整体的流程上是一致的。本文基于OpenHarmoney 3.2标准系统 FA模式的ets应用进行阐述。

1、应用启动整体流程

查看各个进程的父子关系可知,OpenHarmony的系统应用和用户应用进程,都是由应用孵化器(appspawn)拉起的。

OpenHarmony ArkUI - ets_runtime启动流程源码解读-开源基础软件社区

应用启动的整理流程如下图所示:

OpenHarmony ArkUI - ets_runtime启动流程源码解读-开源基础软件社区

说明: 应用启动时,appspawn进程会fork出一个应用子进程,创建AceAbility实现类和AceContainer。AceContainer初始化过程中会在JS线程中创建JS运行环境,包括JsEngine、NativeEngin、ArkJSRuntime、JSThread、EcmaVM等重要组件。

2、启动流程详解

(1)appspawn 创建应用进程

OpenHarmony ArkUI - ets_runtime启动流程源码解读-开源基础软件社区

应用日志:

08-05 17:58:11.955 255-255/appspawn I C02c11/APPSPAWN: [appspawn_service.c:408]child process com.example.myapplication success pid 2345

关键代码流程:

// base\startup\appspawn\standard\appspawn_service.c
APPSPAWN_STATIC void OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer, uint32_t buffLen)
AppSpawnProcessMsg(sandboxArg, &appProperty->pid);
// base/startup/appspawn/common/appspawn_server.c
int AppSpawnProcessMsg(AppSandboxArg *sandbox, pid_t *childPid)
if (client->cloneFlags & CLONE_NEWPID) {
pid = clone(AppSpawnChild, childStack + SANDBOX_STACK_SIZE, client->cloneFlags | SIGCHLD, (void *)sandbox);
pid = fork(); // fork出应用进程
*childPid = pid;
if (pid == 0) { // 子进程流程执行
AppSpawnChild((void *)sandbox);
int AppSpawnChild(void *arg)
struct AppSpawnContent_ *content = sandbox->content;
DoStartApp(content, client, content->longProcName, content->longProcNameLen);
// notify success to father process and start app process
NotifyResToParent(content, client, 0);
content->runChildProcessor(content, client); // 进入应用主线程 (ability_runtime 的 MainThread)
}

(2)应用主线程初始化Ability

OpenHarmony ArkUI - ets_runtime启动流程源码解读-开源基础软件社区

应用的整体状态流转是由Ability实例对象来控制完成的。因此应用进程拉起时,会先创建出Ability。不同的应用模型在这里会创建不同的实例类型:

// foundation\ability\ability_runtime\frameworks\native\ability\native\ability_impl_factory.cpp
// AbilityImplFactory::MakeAbilityImplObject() 方法:
switch (info->type) {
case AppExecFwk::AbilityType::PAGE:
if (info->isStageBasedModel) {
abilityImpl = std::make_shared<NewAbilityImpl>();
} else {
abilityImpl = std::make_shared<PageAbilityImpl>();
}
break;
case AppExecFwk::AbilityType::SERVICE:
abilityImpl = std::make_shared<ServiceAbilityImpl>();
break;
case AppExecFwk::AbilityType::DATA:
abilityImpl = std::make_shared<DataAbilityImpl>();
break;

AbilityImpl实例创建后,应用开始进入Start状态,触发AceAbility::OnStart()回调。在该回调中,会创建JS运行环境。

(3)AceContainer初始化

AceContainer初始化可分为两个阶段:

第一个阶段创建JS运行时环境(js_engine, native_engine, ets_runtime);

第二个阶段调度js_engine开始读取js字节码文件(xxx.abc)

阶段一:创建JS运行时环境

OpenHarmony ArkUI - ets_runtime启动流程源码解读-开源基础软件社区

这里的代码流程比较长… 具体调用过程见上图说明。讲几个主要的点:

  1. AceContianer初始化时会创建一个任务执行线程 FlutterTaskExecutor,这就是后续js代码的执行线程。 应用主线程把需要在js线程中执行的代码包装成task,放到FlutterTaskExecutor中去执行。
  2. 创建Js引擎时可以选择不同的引擎类型,这是在源码编译阶段由宏开关控制的。
    \foundation\arkui\ace_engine\frameworks\bridge\declarative_frontend\engine\declarative_engine_loader.cpp
RefPtr<JsEngine> DeclarativeEngineLoader::CreateJsEngine(int32_t instanceId) const
{
#ifdef USE_V8_ENGINE
return AceType::MakeRefPtr<V8DeclarativeEngine>(instanceId);
#endif

#ifdef USE_QUICKJS_ENGINE
return AceType::MakeRefPtr<QJSDeclarativeEngine>(instanceId);
#endif

#ifdef USE_ARK_ENGINE
return AceType::MakeRefPtr<JsiDeclarativeEngine>(instanceId);
#endif
}

宏开关在如下配置文件中定义:

foundation/arkui/ace_engine/adapter/ohos/build/config.gni。

engine_defines = [ "USE_ARK_ENGINE" ]
  1. ArkNativeEngine初始化时创建了NAPI层的各个重要组件(moduleManager, scopeManager, referenceManager, loop…)
  2. ArkNativeEngine向js运行环境中注册了一个"requireNapi()"方法,该方法是js应用import各种NAPI库的入口。
    js代码中的"import xxxx"在hap包编译阶段会改写为“requireNapi(xxx)”,当这行代码被js引擎解释执行时,即会调用到 ArkNativeEngine 中注册的requireNapi c++实现代码,通过NAPI的ModuleManager 模块完成 xxxNAPI模块lib库的加载。

阶段二:读取并执行js字节码文件

OpenHarmony ArkUI - ets_runtime启动流程源码解读-开源基础软件社区

在 AceContainer::RunPage() 流程中,会依次创建两个js线程的task, 分别读取 app.abc和index.abc文件。

细节1: JsiDeclarativeEngine::LoadJs()方法中是根据传入的*.js文件名去读取对应的*.abc

// foundation\arkui\ace_engine\frameworks\bridge\declarative_frontend\engine\jsi\jsi_declarative_engine.cpp
void JsiDeclarativeEngine::LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage)
...
const char js_ext[] = ".js";
const char bin_ext[] = ".abc";
auto pos = url.rfind(js_ext);
std::string urlName = url.substr(0, pos) + bin_ext; // 将文件名 xxx.js 替换成 xxx.abc

细节2:EcmaVM::InvokeEcmaEntrypoint() 方法中会执行index.abc中的入口函数func_main_0, 该函数在原始的index.js文件中并没有,是hap包编译后生成在index.abc文件中的。

想了解更多关于开源的内容,请访问:

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

责任编辑:jianghua 来源: 51CTO 开源基础软件社区
相关推荐

2022-05-26 14:50:15

ArkUITS扩展

2022-08-12 19:13:07

etswifi连接操作

2022-09-16 15:34:32

CanvasArkUI

2022-05-20 10:56:54

AbilityeTS FA调用

2022-10-24 14:49:54

ArkUI心电图组件

2022-11-02 16:06:54

ArkUIETS

2022-07-04 16:34:46

流光按钮Stack

2022-02-23 15:07:22

HarmonyOS常用控制ArkUI-eTS

2022-07-11 16:26:37

eTS计算鸿蒙

2021-11-26 10:08:57

鸿蒙HarmonyOS应用

2022-08-29 17:34:05

鸿蒙操作系统

2022-03-07 15:22:16

classHarmony鸿蒙

2022-01-07 09:56:16

鸿蒙HarmonyOS应用

2023-08-17 15:04:22

2022-06-07 10:33:29

Camera组件鸿蒙

2022-07-12 17:03:43

鸿蒙网络请求库

2021-07-26 11:07:34

主循环Cocos Creat源码

2022-08-23 16:07:02

ArkUI鸿蒙

2022-07-26 14:40:42

ArkUIJS

2023-12-14 13:28:00

Spring流程Web
点赞
收藏

51CTO技术栈公众号