OpenHarmony应用启动过程

314 篇文章 3 订阅
249 篇文章 5 订阅

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

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

应用启动整体流程

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

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

说明:应用启动时,appspawn 进程会 fork 出一个应用子进程,创建 AceAbility 实现类和 AceContainer。

AceContainer 初始化过程中会在 JS 线程中创建 JS 运行环境,包括 JsEngine、NativeEngin、ArkJSRuntime、JSThread、EcmaVM 等重要组件。

启动流程详解

appspawn 创建应用进程:

应用日志:

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.cAPPSPAWN_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)        }

应用主线程初始化 Ability:

应用的整体状态流转是由 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 运行环境。

③AceContainer 初始化

AceContainer 初始化可分为两个阶段:第一个阶段创建 JS 运行时环境(js_engine, native_engine, ets_runtime);第二个阶段调度 js_engine 开始读取 js 字节码文件(xxx.abc)。

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

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

AceContianer 初始化时会创建一个任务执行线程 FlutterTaskExecutor,这就是后续 js 代码的执行线程。应用主线程把需要在js线程中执行的代码包装成 task,放到 FlutterTaskExecutor 中去执行。

创建 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" ]

③ArkNativeEngine 初始化时创建了 NAPI 层的各个重要组件(moduleManager, scopeManager, referenceManager, loop…)

ArkNativeEngine 向 js 运行环境中注册了一个"requireNapi()"方法,该方法是 js 应用 import 各种 NAPI 库的入口。

js 代码中的"import xxxx"在 hap 包编译阶段会改写为“requireNapi(xxx)”。

当这行代码被 js 引擎解释执行时,即会调用到 ArkNativeEngine 中注册的 requireNapi c++实现代码,通过 NAPI 的 ModuleManager 模块完成 xxxNAPI 模块 lib 库的加载。

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

在 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.cppvoid 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 文件中的。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值