HybridOS Specification 01-A
Topic: HybridOS App Framework
Author: Vincent Wei
Category: App Framework
Date: November 2018
Copyright (C) 2019 FMSoft Technologies
All Rights Reserved.
Table of Contents
- Window, Activity, and Intent
- Data Exchange
Only a new app framework can define a new operating system.
Per a HybridOS app, because it can run on device side and client side, the app framework should be platform independent.
Generally, a HybridOS app consists of zero, or more activities, and zero, or more request responders. But a HybridOS app at least consists of one activity or one request responder.
An activity shows a rendered content page to the end user, the user interacts with the app to complete some tasks.
A request responder executes a request and feeds the result data to various system services or requests from network and other HybridOS apps.
The app framework should hide the details of the different runtime platforms. For example, on a platform that supports multiple processes, a request responder of an HybridOS App may run in a separate process on that platform, but on a platform that supports only multithreading, the request responder may run in a thread.
Moreover, the app framework needs to provide a consistent API for different app running environments, such as device-side, client-side, and simulator, thus greatly reducing the cost of development.
The app framework should also hide the details of the different application protocols, so the app can use one request responder to serve a request in different protocols, for example, HTTP, CoAP, or MQTT.
In order to achieve the above goals, we use data bus as an infrastructure, which interchanges the data between different activities and services in JSON format, and use URI to determine the identity of a resource, regardless it is located in other thread of the same process, other process, other device, other client, or other remote server.
GUI Programming Model
A new app framework defines a new operating system, while the new app framework first needs a new GUI programming model.
In GUI programming model, the event-driven programming model has gained popularity. Event-driven programming is structured around the concept of decoupled relationships between event producers and event consumers.
Currently, almost all mature GUI support systems are event driven. In order to facilitate development, these GUI support systems, including Gtk+, Qt, MiniGUI, Windows, Android, iOS basically adopt concepts such as Toolkit, Widget, or Control. The developer puts various widgets on a window or an activity, and manipulates the widgets or handles the events generated by them.
However, the traditional widget-based programming mechanism does not provide a good solution for decoupling data and rendering relationships.
On the other hand, the development of Web technologies, especially the development of HTML5 and CSS 3, makes webpages more interactive, and provides a simple, easy to use and flexible coding and implementation mechanism, especially on decoupling the data and rendering relationships.
The key features follow:
The developer always use HVML (HybridOS View Markup Language, which defines a few new tags based on HTML 5.3) and CSS 3 to define the structure, styles, and layout of the elements and GUI.
The user agent of HVML ('HybridOS App Engine',
We think that this is a universal solution for the GUI programming framework, and never be out of date.
Window, Activity, and Intent
The concept of
intent is almost the same ones like
other platform, such as Android.
In HybridOS, a window in HybridOS will keep active/visible constantly on the screen, while one activity is a special window instance which can be hung up, and there is only one active/visible activity in the whole system.
Whether it is a window or an activity, it renders and shows HVML documents. Generally, a window or an activity can be created by the desktop or from the following HTML code:
<a href="foo/bar.hvml" target="_blank">Link</a> <form action="foo/bar.hvml" target="_blank"> First name: <input type="text" name="fname" /><br /> Last name: <input type="text" name="lname" /><br /> <input type="submit" value="Submit" /> </form>
Per a HVML document, we may get a dynamic HVML content by sending a request to the HTTP server with different parameters. In HybridOS, the dynamic content of an activity is obtained by using the intent, the external separate data source, and the new tags introduced by HybridOS View Markup Language. This is a feature introduced by HVML to support dynamic content locally.
When you launch an activity, you can pass the intent as the GET parameters to the HVML document:
Or pass the intent as a JSON object to the HVML document.
HAE will use the intent data to get JSON data from a data source, and the HVML parser will generate some new HVML elements by using the JSON data. Indeed, the HVML document acts as a template under this situation.
When the user submits a form in an activity, HybridOS will pass the data in JSON format to the next HVML page as the intent. In this way, a HybridOS app will run like a web app without the HTTP server.
Note that HybridOS also provides the traditional way to fetch a HVML file from a remote HTTP server. In this situation, the data will be included in the HVML file.
In HybridOS, there will be a task running as the desktop of the system. It manages the windows, activities, including the system windows such as launcher, screen lock, status bar, notification page, and control center (imagining a smart phone).
In HybridOS, the desktop is a special HAE, it launches the windows and
activities and shows the rendered content of the activities in
elements of a virtual HVML document, which represents the layout of
all active and/or historical activities in the system.
As described in HybridOS View Markup Language,
we can design a special
view type, which renders screens in an activity
in a separate process if the underlying kernel supports multi-process.
Therefore, the desktop and the activities (the almost same for windows) can interact each other in the following way:
- The desktop uses a
hiviewelement to represent an activity in the system.
- The HVML engine creates a shared frame buffer for a
viewelement, and launches the app in a separate process.
- The activity attaches to the shared frame buffer and renders content of HVML documents to the frame buffer.
- The desktop copies the rendered content from the shared frame buffer to the rendered HVML page of the desktop.
- The desktop collects the input events from the device drivers and passes the input events to the app process via pipe or socket.
- The desktop listens for requests from the activities and responds appropriately, e.g., launching a new activities with the intent data.
Obviously, the desktop acts the role like Wayland of Linux desktop system. However, we can manage the activities by using the Web technologies (as well as the extensions introduced by HVML):
- We can use HVML and CSS to define the layout of activities and windows.
- We can use animation and transition of CSS to define the special effects to launch an activity, close an activity, and switch between activities.
- We run the app (also activities and windows) in separate processes and even in sandboxes to get the best security.
Obviously, we can also render an activity or a window which are described in
HVML and CSS by using HAE. That is, multiple HAE instances
run in a bigger
HAE instance (desktop). The HAE for desktop and activities/windows differ
only in the two ways:
- The HAE for desktop renders content to screen, and the HAE for activities renders content to the shared frame buffer.
- The former gets the input events from the hardware directly, and the latter gets the input events from the desktop.
It is essential that, in our HybridOS app framework, we can render an activity or a window in a native graphics app, for example, a MiniGUI app or a OpenGL ES app written in C/C++ language.
For example, the virtual HVML document of the desktop will look like as follows if there is a running calculator activity:
<hvml> <head> ... </head> <body> <hiview type="window" design="default" class="screenlock" id="screenlock" width="768" height="1024"> <param name="app" value="cn.fmsoft.hybridos.system" /> <param name="entry" value="screenlock" /> </hiview> <hiview type="window" design="default" class="statusbar" id="statusbar" width="768" height="24"> <param name="app" value="cn.fmsoft.hybridos.system" /> <param name="entry" value="statusbar" /> </hiview> <hiview type="window" design="default" class="notification" id="notification" width="768" height="1024"> <param name="app" value="cn.fmsoft.hybridos.system" /> <param name="entry" value="notification" /> </hiview> <ul class="activities normal"> <li class="active"> <hiview type="activity" design="default" class="active" id="act1234" width="768" height="1024"> <param name="app" value="cn.fmsoft.hybridos.calculator" /> <param name="entry" value="" /> </hiview> </li> </ul> <hiview type="window" design="default" class="launcher" id="launcher" width="768" height="1024"> <param name="app" value="cn.fmsoft.hybridos.system" /> <param name="entry" value="launcher" /> </hiview> <hiview type="window" design="default" class="background" id="background" width="768" height="1024"> <param name="app" value="cn.fmsoft.hybridos.system" /> <param name="entry" value="background" /> </hiview> </body> </hvml>
The goal of a service of one HybridOS app is providing data for other components of HybridOS.
As described in HybridOS Architecture, one HybridOS app can register a request handler at a specific endpoint. When there is a request on this endpoint which comes from HybridOS HTTP, MQTT, or CoAP servers, the server forwards the request to this app via hiBus, the app handles the request and returns the response data to the server.
For example, a HTTP request may be sent to the device:
foo is the host name of the HybridOS device,
bar is the
app name, while
values is the endpoint registered by the app.
The HTTP server running in HybridOS will get the request. It translate
and dispatch the request in JSON format to
bar app via hiBus.
bar app handles the request and returns the response data in
JSON format. After get the response data returned by
bar app, the
HTTP server convert the response data in JSON to a HTML document
and send the reply content to the remote.
On a traditional OS, the request handlers commonly are implemented by centralized Python scripts. On HybridOS, the request handlers will be implemented by individual HybridOS apps.
The implementation of a service is called
a request responder.
Generally, a request responder will be implemented in a separate
executable of an app. The hiBus daemon launches the executable
as a separate process if it is not running (the daemon should
make sure there is only one instance), and feed the request data
to the process. The process handle the request and send the response
data to hiBus daemon, the daemon then transfers the response data
to the caller.
Representation of Response Data
For different protocols, the response data may need to be represented in different forms. For example, a HTTP request may expect to get a HTML document instead of a raw JSON data.
Therefore, the HybridOS app framework should provide a way to convert the response data in JSON to a specific representation form.
We can use the dynamic content generation technology introduced by HVML. By using HVML, the HTTP server can easily generate a dynamic HTML document by using a HVML document (a template) and the JSON data.
Therefore, the response data may contain a field to indicate the template document for HTML or other content types.
On device, except for the system daemons, servers, and the desktop, all apps will run in Linux sandbox when the kernel is Linux.
For more information, please refer to HybridOS Security Design.
The system will extract the App package under
prepare the directories for sandbox. The following tree gives the
layout of the sandbox for the app
app/ └── cn.fmsoft.hybridos.system ├── bin ├── dev ├── etc ├── hae │ ├── activity │ │ └── settings │ │ └── index.hvml │ ├── asset │ │ ├── default.css │ │ └── default.js │ ├── main.js │ ├── manifest.json │ ├── service │ │ ├── bar.js │ │ └── foo.js │ └── window │ ├── controlcenter │ │ └── index.hvml │ ├── index.hvml │ ├── launcher │ │ └── index.hvml │ ├── notification │ │ └── index.hvml │ ├── screenlock │ │ └── index.hvml │ └── statusbar │ └── index.hvml ├── lib ├── usr └── var ├── data │ └── settings.db └── run ├── hibus.sock └── hiwebkit-view.sock
For example, we refer to the control center activity by using the following URI:
and refer to the foo service by using the following URI:
After an app was started, it will register some endpoints to serve the requests from remote devices. The system server will build a map between the external URIs and internals URI like follows,
- registered endpoint:
- external URI:
- internal URI:
- external URI:
- registered endpoint:
- external URI:
- internal URI:
- external URI:
Note that, all internal requests should be sent and served via hiBus in JSON format.
HAE will provide a global
- connect to hiBus and register services for the external endpoints.
- connect to other global remote services via MQTT or WebSocket.
- response to the requests from hiBus, or generate events to the whole system.
- read or write data from/to the local files.
- launch the default activity.
Like Android, an app will be packaged in gzip format with the public key and the digital signature signed by the private key.
To be continued.
Interacting with System Daemons
One HybridOS apps can interact with the system daemons by using hiBus in two ways:
- Listen to system events. For example, the changes of WiFi signal strength.
- Send a commend to a system daemon synchronously or asynchronously. For example, connect to a WiFi hotspot.
For security, one HybridOS app which want to listen or talk to a specific system daemon needs to get an access token from the security daemon first. If the app does not have the corresponding permission, or the access token is expired, the daemon will deny the access.
The access token are bound to the signature of a HybridOS app. For more information, please refer to HybridOS Security Design.
Interacting with App Services
One HybridOS apps can interact with any service of other app by using hiBus in two ways:
- Listen to customized app events.
- Send a commend to an app service synchronously or asynchronously.
However, unlike system daemons, an app service only runs on demand. The system will start an app service only if there is a request to it, and will kill the app service when there is no request to it for a particular time since last response.
hiBus provides a secure data bus mechanism for communication between different modules of the system. One HybridOS app can send commands to the specified system daemons or a service of a particular app via hiBus.
One HybridOS app can listen for certain types of events, and the underlying daemon sends events to the app via hiBus.
For more information, please refer to hiBus.
hiWebKit also provides a set of C-based APIs to develop the built-in view renderers. The developer can use the APIs to render view elements by using the internal graphics functions of hiWebKit.
HAE (HybridOS app engine) is the real executable image to run any HybridOS app.
For a long time, the development of an embedded or IoT apps is basically a loop of the following steps:
- Write code on the host;
- Cross compilation on the host;
- Transfer the image to the development board;
- Run the program on the development board;
- If encountered any problem, go to the first step.
Through high-level abstraction, HybridOS isolates apps, servers, and the underlying details of system. As a result, most of the debugging work can be done on the host. Not only that, HybridOS's device emulation environment can also simulate the underlying communication protocols such as mobile/wireless networks (NB-Iot, 4G/LTE, Bluetooth, WiFi) and other peripherals. This will greatly reduce the development complexity of HybrdiOS apps and help the developers focus on business code rather than system code.
For more information, please refer to HybridOS Device Simulation Environment.
For a HybridOS app running in a device, most of resource assets of it should be stored locally, either on file system or embedded into the program image.
You can use the URL scheme
file to locate an asset, for example,
an image, which is stored on file system. However, HybridOS provides
more flexibility to support assets which are embedded in the
program image. We call this type of asset as
For such assets, a HybridOS app can still use
file to refer to
them. But the app don't have to worry about whether the asset comes
from a local file system or is data embedded in the program image.
In HybridOS, HVML files, image files, media files, GNU gettext
mo files are all assets of a HybridOS app.
hybrid.js provides APIs for the desktop of HybridOS to launch activities, like the window manager for HybridOS.
For more information, please refer to [hybrid.js].