Author: Men Liu

Hongmeng is a new generation of terminal operating system developed by Huawei, which can be applied to IoT, watches, mobile phones, pads, TVS and other types of devices. It has been criticized as a “domestic operating system”. In early June 2021, OpenHarmony 2.0 Canary was released, with more open source code for subsystems and support for devices with 128MB or more memory. Which contains the new version of THE JS UI framework, this article focuses on the analysis of this part of the code. (The content of this article is for reference only, if there is any inaccurate description of the content, thank you for the background message discussion and correction ~)

Overview of Hongmeng system

System architecture layering

For more information, visit OpenHarmony’s website [1]. Here is the official technical architecture:

It is divided into four parts: application layer, framework layer, system service layer and kernel layer. The kernel layer is mainly macro kernel Linux and micro kernel LiteOS, as well as various hardware drivers. The framework layer is closely connected with the system service layer, with horizontal framework and vertical service, subdivided into many relatively independent subsystems, including UI framework and Ability framework.

Note that this is OpenHarmony architecture, does not include GMS and HMS, does not include AOSP, and does not support Android APIS. There are some differences between HarmonyOS and Huawei phones.

Differences between HarmonyOS and OpenHarmony

Both are called “hongmeng” in Chinese, but there are some differences behind it. HarmonyOS is a commercial operating system developed by Huawei, and OpenHarmony is an open source version donated by Huawei to The OpenAtom foundation. There are overlapping parts and conceptual confusion between the two versions, so much of the discussion has been torn between “self-development” and “shell”.

I tried to sort out the relationship between the concepts, as shown in the figure below. Unofficial drawing, for reference only, all subject to the official caliber.

First of all, Hongmeng app is packaged into HAP (Harmony Ability Package format distribution, and android APK is a compressed Package, Package structure is similar. Once distributed to the end, unification is carried over by the Hongmeng (Concept) API and then separated into different modes. The hongmeng version pushed on Huawei phones, which is compatible with Android apps without feeling, must rely on AOSP. While the open source part is mainly aimed at low-end IoT devices, or watch bands and the like, even without a screen. In June 2021, the open source version just supports devices with more than 128MB of memory, which cannot independently support apps on mobile phones. These are two extreme scenarios of “casing” and “self-development”, neither of which is necessarily a stable final state. In between, the subsystems of the framework layer and the system service layer in the overall architecture are relatively independent and decouplable, which can be used in these scenarios at the same time, but their functions are not sound enough. Some of them are open source, such as microkernel and JS UI framework, and some are not open source. Compatibility with Android is not a long-term solution, the open source part of the function is simple, so the middle of the uncertain piece will be the future of the main link? Will Hongmeng really develop into a self-developed full-platform operating system in the future? Wait and see.

Try answering one of the most discussed questions in the community:

Is Hongmeng self-developed? There must be a proprietary component, and there must be some reliance on tripartite code. At this stage, it is unrealistic to require all the code to be self-developed. It can’t be completed in one or two years. We must first innovate on the shoulders of giants, and then further reduce dependence and deal with the agreement and copyright issues.

Does Hongmeng rely on AOSP? You can say dependent, you can say not dependent. HarmonyOS’s compatibility mode relies on AOSP, otherwise it wouldn’t work with Android apps; OpenHarmony is open source and does not rely on AOSP, but is currently used mainly on low-end IoT devices.

Unless otherwise noted, all of the “hongmeng” mentioned below refer specifically to OpenHarmony.

UI subsystem of Hongmeng

There is no Java UI in the open source version (at least I can’t find it). The framework for implementing JS UI is called ACE, which stands for Ability Cross-Platform Environment. There are two repositories: Ace_engine_lite [2] corresponds to the old ACE architecture, while ACe_ACe_engine [3] corresponds to the new ACE architecture. Their implementation principles and upper syntax are different.

Source directory structure

The OpenHarmony open source code is hosted on Gitee, and there are more than 200 repositories under the group. It is recommended to download the code according to the documents obtained from the official source code. The source directory structure and the corresponding relationship between the repositories can be refer to the manifest repository configuration file [4].

If your environment is already configured, execute the following two commands:

repo init -u https://gitee.com/openharmony/manifest.git -b master --no-repo-verify
repo sync -c
Copy the code

The whole process takes about 15 to 30 minutes. You can find the manifest configuration file after executing the first command and remove Linux and some third_party dependencies faster.

The directory structure of the abbreviated version is as follows (irrelevant directories are skipped and related parts are expanded only) :

├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # ├─ Application # │ ├─ Heavy Metal Guitar School - Ace # JS │ ├─ Heavy Metal Guitar School - Ace # JS ACE ace_ace_engine │ │ └ ─ ─ ace_engine_lite # 2.0, warehouse name: │ ├─ ├─ Interface │ ├─ ├─ pdk-2, pdk-2, pdk-2 ├── Heavy Exercises ── heavy Exercises ─ heavy exercises ─ heavy exercises ─ heavy exercisesCopy the code

Old and new ACE frames

The following is the architecture diagram of ACE framework [5]. Now the UI described in the document and supported in IDE is this set of UI, which provides DSL[6] development UI similar to small program, HML(HarmonyOS Markup Language) + CSS + JS.

Looks similar to the architecture of mainstream JS + native rendering frameworks. It provides compilation tools to compile source code into JS bundles. When running, there is a framework.min.js file executed by default after the JS engine starts, which implements node building logic. There are about 20 or 30 supported components.

In another repository without the lite suffix (ACe_ACe_engine), there is also an implementation of a UI system with a simpler architecture level and more advanced technology, which should be a new generation of UI framework. Here is the architecture diagram of the new ACE framework [7] :

The main body of this architecture is divided into application, framework, engine, and cross-platform adaptation. The application layer is the syntax for developers, and there are several modes, explained below. The framework layer implements the componentized, MVVM capabilities common to front-end frameworks, enabling responsive UI updates. Here is the JS engine, which uses QuickJS and should also support V8. Further down is the rendering engine, which contains the core rendering pipeline, animations, events, and various layout rendering algorithms.

The bottom porting Layer is the key to adapt to multiple platforms. It defines a platform-independent layer data structure that can be submitted to various compositors for rendering. From the perspective of the code, it is supposed to support the Flutter Engine.

Overall rendering process

Container creation and management

The basic unit of UI is FA (Feature Ability), which corresponds to an instance of AceAbility and provides a lifecycle hook that creates an AceContainer internally when OnStart() is executed. However, this AceContainer is not held directly by AceAbility, but is managed by a globally unique singleton called AceEngine.

AceContainer provides UI rendering capabilities, is a general management class, provides lifecycle and function scheduling interfaces, and is internally divided into many sub-modules:

  • Frontend: The execution environment of the front-end code, JS or JSON, which may support other scripting engines.
  • TaskExecutor: Task manager within a single thread, similar to TaskRunner in other rendering engines.
  • AssetManager: Resource manager for loading JS code, images, fonts, and other resources. Should also have caching capabilities.
  • PipelineContext: A management class for rendering pipelines that listens to vsync callbacks to refresh the layout, drawing, and rendering of internal dirty nodes.
  • AceView: Render the root UI node that can be pasted to the outer container.
  • PlatformResRegister: Registration and management of platform resources, as well as part of the communication interface, where the same layer rendering function can be implemented.

JS UI development framework

In the Frontend section, there are three different types of implementations: imperative UI based on rendering instructions, declarative UI, and UI rendered in JSON files without a scripting engine. Both the imperative UI and the declarative UI use QuickJS as the scripting engine. The declarative UI includes V8 abstractions, but they don’t seem to be open sourced.

JS Frontend (imperative UI)

“Imperative UI” is an engine implementation point of view, because the underlying rendering instructions are based, and the true syntax is open to developers, which can be interfacing with declarative and responsive front-end frameworks such as vue.js. The JS UI of hongmeng official website corresponds to JSFrontend. The syntax is similar to small programs, which should be inherited from the previous quick application. Each component corresponds to the template file of XX.hML, style file of XX.css, script file of xx.js and configuration file of XX.json.

<div class="container">
  <text class="title-text">{{headTitle}}</text>
</div>
Copy the code
/* xxx.css */
.container {
  flex-direction: column;
  margin-top: 20px;
  margin-left: 30px;
}
.title-text {
  color: #1a1a1a;
  font-size: 50px;
}
Copy the code
// xxx.js
export default {
  data: {
    headTitle: 'Capture the Beauty in This Moment'
  }
}
Copy the code

The above code will be packaged and compiled into a JS file for dynamic execution.

When initializing the JS execution environment, it first binds a series of native interfaces, then executes the built-in JS framework, and then dynamically loads the JS code of the executing user. In the qjs_engine.cpp [8] file of js frontend, you can see the interfaces registered with the JS environment:

Because QuickJS supports ES6 modules, these interfaces are registered with ace modules and can be imported with import. The environment also contains ace global environment:

DomCreateBody (0, 'div', {/* attrs */}, {/* styles */}, {/* events */})Copy the code

The code that actually sends the render instruction in ACE is in taskcenter.ts [9] of Third_party_JSFramework. The design of the interface and the format of the render instruction are basically the same as that of Alibaba/Weex’s Taskcenter.js. JS is also used to simulate the simplified DOM API, which is connected with the small program style DSL. There are a lot of practices in this kind of technology community, which will not be introduced.

Declarative Frontend UI

There is not much information publicly available on this. In terms of code, the UI is not built with HML + CSS, but with atomized layout functions like Flutter. Flutter uses widgets, and The declarative JS UI uses JSView. Jsproxyclass.js provides decorators/annotations to assist programming in the ECMAScript specification. It is estimated that the code will look like this:

@Component class MyDemo { Column( Text('Hello World! '), Text('Some text here') .fontsize(36) .color(Color.Red) ).center() }Copy the code

Here is the source code for JSView, tiled as shown below, there are not many varieties yet.

The advantage of this method is that the combination is good, the layout nodes do not affect each other like CSS, the layout algorithm is more efficient. But abandoned the front-end favorite HTML + CSS layout, the existing various front-end frameworks, component libraries, style libraries can not be directly transferred to the ecological construction will be a little difficult.

Card Frontend (no script UI)

It’s called CardFrontend, but it’s probably mostly used in card-like scenarios like masked desktop widgets. It does not rely on a script engine, but is driven by a JSON file in a specific format.

JSON file format is not yet clear document, here is a test case, the main body is divided into the template, the styles, the actions, the data of this a few parts, can be written in the template data binding of curly braces {{. Some data}}, can write simple JS expression inside, It’s not completely static. The CardFrontend class also has an UpdateData() interface, which updates the template data and provides dynamic capabilities.

Node construction process

The above three front-end frameworks correspond to different UI development methods, but the node construction and layout drawing algorithm of the latter half are all the same link, and are self-drawn and rendered by C++, independent of system UI, with good consistency. The complete node-building process can be drawn as follows:

The JSView of declarative UI is tied directly to the JS environment and is scheduled directly by page/card code. JSView has a large number of derived classes corresponding to the atomized style description. The JSView tree generates a Component tree with one-to-one nodes, such as JSGrid generating GridLayoutComponent and JSText generating TextComponent.

JSFrontend and CardFrontent are both composed of render instructions (C++), one generated by the front-end framework diff, one parsed directly from JSON, and then built inside a compact DOM tree (C++). Note that this so-called DOM tree is not bound to the JS environment and cannot be manipulated directly through the JS API. Each DOM node is regenerated as a Component node.

RenderComponent, a Component derivative, generates RenderNode directly, which is a shorter link. ImageComponent, for example, inherits from RenderComponent. Another derived class is ComposedComponent, which is composed of other components. Element is a similar data structure, derived from RenderElement and ComposedElement. Component can build Element and RenderNode. Element can build RenderNode. Frankly, I don’t understand the difference between these two trees.

RenderNode is the real layout node. Other rendering engines, called RenderObject or LayoutObject, derive many subclasses and implement a variety of layout algorithms, type designs and Flutter widgets. The RenderNode has its Porting Layer Tree Porting Layer[7]; it can be put in to different synthesizers to cross platforms.

Interestingly, hong Meng’s Third_Party has a flutter porting Layer and implements a FlutterSceneBuilder [10]. The porting layer has the same data structure as the flutter Engine’s layer. Flow also companies with added code called OHOS_Layers. In other words, the New ACE Framework may run on the Flutter Engine, and the Flutter Framework may run on the Flutter Graphic UI.

Layout rendering

The core class that implements the rendering pipeline is PipelineContext, which stores queues of dirty nodes. When a node property changes, it does not immediately trigger layout and drawing, but is added to a cached queue. At the same time, monitor vsync signal of the system, flush internal recorded dirty nodes in each frame in sequence, and perform animation detection, node reconstruction, layout, redrawing, cursor refresh and other processes in turn.

Each frame of vsync will trigger the OnVsyncEvent() callback. If the surface is already initialized, the internal dirty nodes will be refreshed in turn. If the animation is included, the next frame of vsync will be triggered by a RequestFrame() request. Dirty Elements will trigger Rebuild() to Rebuild RenderNode, and MarkNeedLayout() will be called to add it to the queue to be laid out. FlushLayout will flush the queue. Call the OnLayout() method of the node to calculate the layout, and then add itself to the queue to be drawn. Then FlushRender() calls the Repaint() method of the node in turn to redraw to generate the Layer Tree.

Discuss the development of Hongmeng

A graph posted at The Developer conference shows that the number of mobile, tablet and PC devices has not increased significantly in a long time and will not increase much in the next five years. However, IoT devices, such as watches, offline large screens, vehicles and other devices, are increasing, and the number of IoT devices is still in the stage of rapid development. Hongmeng judged that the future is the era of the Internet of everything, and the goal is to create a “multi-intelligent terminal, full scene distributed operating system”. Compared with AliOS, Hongmeng was born at the right time and has enough space.

The microkernel system, hardware drivers and subsystems of The Hongmeng system are pluggable, which can be well compatible with IoT devices from low-end to high-end with a wide range of forms. Another feature is the cross-device flow of Ability, which gives full play to Huawei’s advantages in communication technology. Multiple hardware devices can be directly connected at the system layer, which may give rise to some new gameplay.

For the emerging things, we always compare the old things, and only see the same parts with the old things. What we don’t see is the real value. If Hongmeng is only compatible with Android, there is no differentiation of functions, there is no great development significance, only to solve the “localization” feelings. It is also hard to say that Android/iOS is a revolutionary technology subversion compared to the previous generation of Nokia and MOTOROLA, and there are some bright points in Hongmeng’s design concept. System-level capability innovation requires a process to be perceived by the application layer. Hong Meng may be just the beginning. It may take someone like Steve Jobs to translate new systems capabilities into a new generation of interactions, a new generation of products, to bring about an explosion. Considering the trend of national policy and technology research, the future is promising.

* References

  • OpenHarmony website: www.openharmony.cn/
  • ACE Lite: gitee.com/openharmony…
  • ACE Engine: gitee.com/openharmony…
  • Configuration file: gitee.com/openharmony…
  • ACE architecture diagram: gitee.com/openharmony…
  • A small program that class DSL:device.harmonyos.com/en/docs/api…
  • New ACE architecture diagram: gitee.com/openharmony…
  • Qjs_engine. CPP: gitee.com/openharmony…
  • TaskCenter. Ts: gitee.com/openharmony…
  • FlutterSceneBuilder: gitee.com/openharmony…

Follow us every week for 3 mobile dry goods & Practices to give you thinking!