OpenHarmony 源码解析之ACE (JavaScript运行环境初始化) 原创 精华
作者:张亮亮
1 简介
JS UI框架ACE全称Ability Cross-platform Environment,是OpenHarmony标准系统上的UI框架。
ACE: 结合了OpenHarmony系统的基础组件Ability,开源jsframework框架,开源js引擎quickjs,开源跨平台UI框架flutter,开源渲染引擎skia以及各种平台能力API等共同构筑了OpenHarmony标准系统javacript应用开发的基础。
1.1 OpenHarmony 架构图
1.2 ACE UI框架图
1.3 ACE 主要构成
-
目前OpenHarmony标准系统采用主流的类Web范式,对开源的Weex框架中的jsframework做定制化,采用ts开发,主要包括编程模型MVVM,组件,API,页面路由以及事件处理。
-
目前OpenHarmony标准系统使用的是开源quickjs引擎,提供JS语言运行时和执行上下文,提供js的解析和jsframework的加载。
-
中间转换层也就是JS桥接层,实现前端开发框架到UI后端引擎和JS引擎的对接。
-
由C++构建的UI后端引擎,包括UI组件、布局视图、动画事件、自绘制选软管线。
-
目前OpenHarmony标准系统复用了开源跨平台UI框架flutter引擎提供基础的图形渲染能力。
-
目前OpenHarmony标准系统的适配层完成了ohos平台和IDE的previewer的适配,将平台依赖聚焦到平台相关的画布、通用线程以及事件处理机制等少数接口上,为跨平台提供相应的基础设施,实现跨平台一致化的UI渲染。
-
为扩展ACE能力提供的插件机制,平台其他子系统可以利用插件机制开发相关能力的js接口,为应用层提供相应的能力支持。通过napi提供引擎无关的插件实现机制,保证接口的ABI兼容性。
2 基础知识
2.1 代码结构
2.2 ACE框架类图
2.3 线程模型
ACE JS应用启动时会创建一系列线程,形成独立的线程模型,以实现高性能的渲染流程。
- **Platform线程:**当前平台的主线程,也就是应用的主线程,主要负责平台层的交互、应用生命周期以及窗口环境的创建
- **JS线程:**JS前端框架的执行线程,应用的JS逻辑以及应用UI界面的解析构建都在该线程执行
- **UI线程:**引擎的核心线程,组件树的构建以及整个渲染管线的核心逻辑都在该线程:包括渲染树的构建、布局、绘制以及动画调度
- **GPU线程:**现代的渲染引擎,为了充分发挥硬件性能,都支持GPU硬件加速,在该线程上,会通过系统的窗口句柄,创建GPU加速的OpenGL环境,负责将整个渲染树的内容光栅化,直接将每一帧的内容渲染合成到该窗口的Surface上并送显
- **IO线程:**主要为了异步的文件IO读写,同时该线程会创建一个离屏的GL环境,这个环境和 GPU线程的GL环境是同一个共享组,可以共享资源,图片资源解码的内容可直接在该线程上传生成GPU纹理,实现更高效的图片渲染
3 Javascript运行环境初始化
3.1 时序图
3.2 源码解析
-
OnStart()
-
AceAbility继承自Ability,当应用启动时首先应用程序框架会调用AceAbility的生命周期函数OnStart();
-
通过Ability的api获取Hap包的路径,通过读取配置文件manifest.json获取应用程序配置的前端的类型;
-
当前我们只关注JS前端,目前支持的前端类型包括
enum class FrontendType { JSON, JS, JS_CARD, DECLARATIVE_JS }
; -
根据前端类型调用ACE核心聚合类AceContainer的静态方法CreateContainer,这个类是ACE框架平台适配层的核心类,接下来的前端核心类和JS引擎的创建都是在其中完成的。
-
- CreateContainer
- 在AceContainer::CreateContainer中,首先创建了AceContainer对象;
- 在构造函数中创建了FlutterTaskerExecutor对象用于多线程的任务管理;
- 此处主要关注JS线程的创建和初始化,在InitJsThread()中创建了JS线程并获取保存了jsRunner_用于JS任务的派发;
-
JsFrontend
-
完成JS线程的初始化后,如果前端类型不是DECLARATIVE_JS,会调用InitializeFrontend()对前端进行初始化。
-
首先创建前端对象,Frontend::Create定义在js_frontend.cpp中,创建的是JsFrontend实例;
-
然后通过JsEngineLoader::Get()动态加载QjsEngineLoader;
-
再通过QjsEngineLoader创建QjsEngine并设置给JsFrontend;最后对JsFrontend对象做初始化;
-
JsFrontend是ACE框架从后端进入前端的唯一入口,AceAbility、AceContainer和JsFrontend是一一对应的关系;
-
-
QjsEngine
-
接下来我们继续分析一下JS引擎管理对象的创建;
-
首先通过dlopen动态加载libace_engine_qjs.z.so通过入口函数创建获取QjsEngineLoader单例对象;
-
然后通过QjsEngineLoader::CreateJsEngine()创建QjsEngine;
-
-
JS线程
-
在完成了QjsEngine的创建并设置给JsFrontend后,调用JsFrontend::Initialize();
-
这里主要完成了FrontendDelegateImpl对象的创建和初始化将对JS引擎的相关操作委派给这个对象;
-
以及Post JS引擎初始化的任务到JS线程的TaskRunner的message queue;
-
-
jsframework
-
在JS线程执行QjsEngine对象的初始化,初始化JS运行环境;
-
初始化JS引擎运行时上下文和初始化JavaScript框架层jsframework;
-
-
ACE模块
-
初始化JS引擎运行时上下文是在InitJsContext完成;
-
其中初始化Ace模块并将模块导入JS运行时上下文中,为jsframework框架层提供了ACE功能相关的接口;
-
jsframework可以通过调用ACE模块的接口完成Page上Dom元素到后端声明式UI元素节点的创建;
-
同时往JS运行时上下文全局对象挂载了日志打印的函数用于对接平台日志打印功能;
-
-
初始化完成
-
完成JS运行时上下文初始化之后,紧接着加载初始化jsframework,为JS应用程序提供javascript应用框架;
-
这个地方使用quickjs的运行bytecode的方法,在编译时通过qjsc(quickjs编译器)将jsframework编译成c文件;
-
c文件的内容就是一个bytecode的组数和数组大小,指定了jsframework的入口函数;
-
在这里对应jsframework/runtime/preparation/index.ts 中的initFramework()完成jsframework的初始化;
-
jsframework初始化完成的工作主要包括挂载到js运行时上下文全局对象上提供给native调用的jsframework函数,注册到jsframework的ACE提供的模块及其中的方法和jsframework提供的与native一一对应的组件及其方法;
-
4 总结
以上内容首先对OpenHarmony标准系统上JS UI框架ACE的逻辑架构及相关模块进行了简单的介绍,给出了ACE架构中相关模块涉及的部分类的类图,结合本次重点分析的Javascript运行环境初始化的时序图详细分析了Javascript运行环境初始化的整个流程。
更多原创内容请关注:开鸿 HarmonyOS 学院
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
MCU GUI上如何使用这套框架?
亮仔加油
果然是这条gai最靓的仔
MCU应该是L0的设备,目前暂不支持ACE框架。这部分讲的是OpenHarmony标准系统上的ACE框架,适用L2以上设备;L1的设备使用ACE Lite框架
正在学习 OpenHarmony 源码, JS 框架层这部分网上的资料不多.
难得有这么清晰详尽的解析, 感谢博主的分享!
正在研究ACE框架,面对大把的代码看的云里雾里,这篇文章的出现帮忙我详细地梳理出框架脉络,有种拨云见日、豁然开朗的感觉,那叫一个通透!
刚接触OpenHarmony中JS方面的知识,这篇文章分享了不少鸿蒙JS方面的知识,思路清晰,代码详细
ace跨平台这块一直有疑惑,没搞清跨平台机制,感谢博主分享,主线清晰明了,受益匪浅,期待后续分享
lite wearable(例如watch GT2 pro)这样的可以啊,不过一直没找到具体教程
感谢关注,专栏会有持续输出更多的内容
感谢关注,专栏会有持续输出更多的内容
关注专栏,还有持续输出的
支持支持。。。收藏学习了
这个要看是a核还是m核,a核做了适配,m核没有
要更新啦
类图,时序图很清晰啊,加上代码,发现更容易看懂和上手。
用的是性能一般的MCU, 想看ace_engine_lite的剖析
这么说的话,鸿蒙其实是有个js解释器么?
这个quickJS应该就是解释器吧,可之前鸿蒙在java那边宣称的一大优势就是:”不用AOT和JIT,直接把代码编译为机器码,提高运行速度“。
看来这个优势在js前端是不存在的