CodeHub#7 officially ended, technical expert “jing jun” from ant group shared with developers of nuggets community the new card stack of “alipay” — rubik’s Cube.
Jing jun explains the rendering and production process of Cube technology around the architectural logic, and guides developers through the initial technical debugging.
▶ click play to view CodeHub#7 in its entirety; The public account mPaaS replies to “Cube” to obtain the lecturer’s complete PPT.
Dynamic card background
Application ICONS have been the main entry point for users since the Windows era and have continued into the mobile era. Icon is the way of entry, the disadvantage is not intuitive, at least one click to access the desired information. In this context, the iOS system and some Android systems have implemented cards that pre-place content and services, as shown in the figure below:
In addition, the Hongmeng system also proposed a similar card scenario as a kind of traffic entrance. In fact, it is more common to use cards as content display and service entrance inside the app, such as alipay’s home page and CMB’s wealth management page, where each small rectangle is a card. For operations, the card style and content can be configured at any time, without waiting for the application version to upgrade, and is also something of a necessity.
Summary of the Cube
** Rubik’s Cube card (Cube) ** is a set of cross-platform dynamic card solution developed by Ant Group itself. It serves the regional dynamic technology within the application page, is content-oriented operation, and helps product technology improve development efficiency and operation efficiency. Each Rubik’s Cube is embedded in an area of the native page independently, and the content of the area is displayed through the card template.
So let’s expand on high performance. The Cube seeks to be close to a native experience. We define two dimensions:
One is extreme performance. Based on the Cube applets, we removed some complex CSS capabilities, such as pseudo-class pseudo-elements, inline/block, etc., and also limited JS capabilities (Rubik’s Cube cards use QuickJS as the script engine). In addition, we made some optimizations to QuickJS, including but not limited to offline Atom compilation optimizations, asynchronous GC optimizations, etc. We also introduced WAMR as a quickJS “coprocessor” that allows users to develop with a mixture of javascript and AssemblyScript. This allows users to use AssemblyScript for some hotspot functions or modules.
Another dimension is extreme memory. Infinite drop down in information waterfall scenario, rubik’s Cube card memory growth close to Native card. We have refined the capabilities of the cards to reduce runtime memory consumption by configuring them at development time. The image below shows a simple card, the project catalog of the Rubik’s Cube card as shown, and the actual code and performance of a card in the wallet.
Production of Cube cards & workflow
-
Research and development phase
-
- Local development
Cube is equipped with independent development tools, supporting card compilation, log output, real-time preview and other functions. Vue, as the DSL language of the current development template, supports JS and CSS to edit card styles.
-
- Card management
After the local development of the card is completed, the compiled product of the card can be uploaded and released through the card management background. The version management of the card can be carried out. After the release of the card, the dynamic update of the card can be carried out in the client.
- The run-time
In order to facilitate the access of endservices to Rubik’s Cube cards, we introduce the concept of a Rubik’s Cube container (CardSDK). CardSDK encapsulates some of the common capabilities associated with the business layer/server. For example, we pull cards and business data from the server through the CubeCardSdk. In addition, CardSDK is also responsible for the common JSAPI, third-party components access. In this way, rubik’s Cube cards can be more focused on the product itself.
Core System Architecture
The system architecture of rubik’s Cube mainly includes JSEngine, CardEngine, RenderEngine and Platform, and most of the code is C++.
- JSEngine
Mainly responsible for card JS logic execution and card data change monitoring, so as to support developers to write some business logic ability in the card to achieve dynamic changes of card content and style.
Because the card scenario has high performance requirements, considering package size and performance, we chose QuickJS as our BASIC JS engine library and implemented a very small JS responsive framework (JSFM) to support the logical code capabilities in the card.
- CardEngine
Mainly responsible for card data parsing and binding, card logic rendering, DOM instruction construction, JSAPI management, JSBinding, Native event communication, etc.
The initial construction process of card DOM tree, we did not put it in js runtime, but in the card instance initialization link directly through C++ instruction generation and tree construction, on the one hand, in order to keep js framework smaller and faster, on the other hand, C++ operation efficiency is higher.
- RenderEngine
Back-end rendering base, responsible for card layout calculation, style analysis, Layer calculation, self-drawing components, the same Layer rendering, raster screen and other processes, as well as gestures, dynamic effects and other interactive effects.
- Platform
Platform related interfaces, including atomic View encapsulation, Canvas API, three-party component extension protocol, animation API, etc.
Thread model and data model
Threading model
The main threads in the life cycle of rubik’s Cube card include business threads and engine threads. Business threads are the initialization stage of card data initiated and executed by business, and are the beforeCreate stage of the life cycle of the card. The engine thread is common to all the running phases of the card life cycle, including the Bridge thread, Render thread, Paint thread, and UI main thread.
- Bridge, thread
Js runtime thread is also the Dom node data query and processing thread. Based on the small and fast positioning of the Rubik’s Cube card, JS logic is only an auxiliary capability of the card and does not have the ability of overly complex business logic. Therefore, Bridge thread is relatively light and designed as a single thread mode.
- Render threads
Render related data calculation threads, including rendering tree construction, node hierarchy calculation, Layer layered rendering calculation, gesture data calculation and rendering task construction, Render process mainly involves the recursive calculation process of the tree, relatively short time consuming rendering process, designed for a single thread mode.
- Paint thread
Drawing thread, perform card node hierarchical drawing and raster tasks. The Paint thread is not a fixed thread. Depending on the current task model, the Paint thread may be the main thread or a child thread in a thread pool. In synchronous rendering mode, the Paint thread is directly the main thread; In asynchronous rendering mode, concurrent rendering of Paint tasks via a thread pool improves rendering efficiency, such as in list-sliding scenes.
- UI is the main thread
UI operation main thread, which is the current platform thread, mainly includes gesture recognition, UI screen and data update of tripartite extension components, etc.
In addition to the main threads mentioned above, there are also background threads related to playground, which have a low overall priority. Overall thread model design, minimize the UI main thread pressure, improve the efficiency of card concurrent rendering. However, there are still some shortcomings, including frequent UI thread switching and increasingly heavy Bridge threads. We will continue to optimize the threading model in the future.
The data model
The data model corresponding to the thread model mainly includes three trees: NodeTree, RenderTree and LayerTree. In addition, there is also a temporary PaintTree.
- NodeTree
The original NodeTree of the card corresponds to the front-end Dom tree. The engine will perform style analysis and layout calculation according to NodeTree.
- RenderTree
Rendering data tree, which is a deformed tree, in many cases has the same tree hierarchy as NodeTree. In fact, when we were designing and defining the engine data model, we discussed whether we should have this tree, whether there was a need for such a tree, and we ended up keeping it. The reason is that this tree can be flexibly adjusted tree relationship, if the card is divided into layout stage and rendering stage, then this tree is the rendering stage of the source tree.
Facts have proved that our decision is right, we support zindex/static ability, all because of the existence of this tree can be very good to support the engine layer, rather than in the platform layer model to implement this change ability which can lead to very limited support the scene, including later we do rendering snapshot technology is also from the tree to consider.
- LayerTree
As the name implies, LayerTree is a hierarchical tree. Based on RenderTree, nodes of the same layer are rasterized in the same rendering task pipeline. Different layers are independent from each other and can be concurrently rendered.
- PaintTree
PaintTree is a temporary tree, in fact, strictly speaking, it is a copy tree. It copies a sub-tree through RenderTree, which is generated temporarily every time the rendering occurs. Of course, some node optimization will also be done, for example, the nodes that are completely covered will be optimized and adjusted to avoid repeated rendering. There is a PaintTree on each layer, through which nodes are drawn to generate raster instructions or bitmaps.
High performance list rendering
For scenarios where cards are used in the list, the main consideration is the lag effect, especially for mid – and low-end machines. Rubik’s Cube card (Cube) supports asynchronous rendering, so it can be very smooth in the list scene. At the same time, because of the support of multi-thread concurrency, multiple cards can be concurrently rendered, so there will be no obvious white screen effect in the asynchronous rendering condition.
Native technology optimization
We expect cards to serve the dynamic presentation of localized content within the page and simple business logic, and more for mobile developers. Even though the card DSL language we use is described as a front-end language, we want to be able to restrict the use of CSS and support limited CSS capabilities, but we also want to cover as many CSS capabilities as possible that developers commonly use.
Therefore, we did a special work for CSS ability, and made the Cube CSS ability specification together with the technical students of the front end team, which restricted the CSS ability. Even so, in the Native rendering engine, there are many difficulties in supporting these capabilities, including zIndex support, overflow, etc., so we have also optimized the processing based on some platform capabilities we rely on.
Layer container
We introduce the concept of Layer container. When we introduced the data model earlier, we mentioned LayerTree. Each Layer node is an independent rendering container, and the platform View serves as the Layer container to render other virtual nodes. If a View corresponds to a rendering container according to the conventional practice, we combine two views into a Layer container (iOS CALayer), separating the content Layer from the logical Layer. This has many benefits, such as the limitation of shadow drawing of Layer nodes and the optimization of canvas cutting of the content Layer.
Gestures to transform
Gesture optimization is mainly to solve the limitation of gesture distribution ability of platform system. No matter Android platform or iOS platform, the system has some limitations on gesture distribution processing, for example, brother nodes cannot distribute events (iOS), cannot receive events beyond the parent node area (affecting overflow capacity), etc. So the gesture needs to be modified.
Because card rendering extension support the three components, in order not to influence extended component incident response, we based on Layer container gestures behavior modification system, internal gesture to distribute and manage the container node, there exist three party components for hybrid rendering of scenes, Layer containers and gesture of tripartite between components distribution system behavior.
rasterizer
The Rubik’s Cube rendering process consists of two rendering modes, instruction rendering and bitmap rendering, which switch between different scene conditions to optimize performance in different scenes, such as frame rate and memory. Bitmap rendering is relatively complex on Android. The default is to use Bitmap as the cache for offline rendering. The disadvantage is that an extra CPU/GPU memory copy is introduced and GPU resources cannot be fully utilized. The advantage is good compatibility. We tried using TextuReview as an offline rendering buffer and found serious compatibility issues with devices below 6.0, as well as huge stability differences between devices.
Meanwhile, rasterization ability depends on Canvas API of platform system, and some advanced methods involve limitations of hardware acceleration, including shadow API and system restrictions on glRender Buffer (Android platform). We also perform view cutting segmentation rendering for large Canvas scenes to ensure rendering performance. We are also working on replacing the Canvas API at the platform level with the Skia Canvas API.
The render tree
Cube takes tripartite components as an independent layer for data update, which can be very convenient and efficient access to extended tripartite components. System-based UI capabilities that enable extension components to render uniformly within the card. It also supports the reuse of components on different cards. In real business scenarios, same-layer rendering also presents additional problems. Components such as maps/videos/animations tend to have a high performance memory overhead. This overhead can have a negative impact on card rendering, especially when the list is scrolling. For the map/video component, we worked with the component provider case by case to solve the problem and tried to set the card point when the card went live. For animation components, Cube continues to extend property animation/frame animation capabilities with built-in Canvas capabilities.
Status quo and planning of Cube
At present, Cube has served the home page, securities (stocks), card packages, travel and other 20+ business scenarios of “Alipay”, with daily PV of more than 10 billion. In a long time to come, the internal business scene of “Alipay” will gradually Cube the stock of native cards and H5 cards.
So, on the one hand, we will continue to make the developer experience good, such as the development debugging tool chain; On the other hand, we will continue to improve the base performance, such as pursuing smaller package sizes, lower memory, etc.
Meanwhile, Cube Beta has launched mPaaS for the use of mobile developers. During the public Beta, log in to the mPaaS console and immediately give ten card templates for free use. > > Click here < < experience the Rubik’s Cube card.
Another direction in card’s future plans is application development stacks for iot devices such as RTOS. Not exactly a Rubik’s cube card, but something in between a card and a mini-program.
Iot devices tend to have simple, card-like interfaces; However, the routing capability between multiple cards is required, which is similar to the application mode. Such a hybrid form can not only retain the advantages of Cube in memory/performance/package size, but also meet the demands of iot device application development.
According to our research, most OF the RTOS application development environment is still stuck in the traditional C language, the efficiency and dynamics are not ideal. Therefore, Cube may be a good choice for developers.
Recommended reading: “Cube technology read | alipay, a new generation of dynamic technical architecture and selection review
> > Click here < < experience the Rubik’s Cube card.