Single-Process vs. Multi-Process Mode
The application manager can run the System UI and QML applications in two different modes:
- Single-process mode: where the System UI and QML applications are all run in one, single process, that belongs to the System UI. This mode is only supported by QML applications - applications that use the
- Multi-process mode: where the System UI and QML applications all run in their own, dedicated process.
Internally, for every Qt application, which is ultimately a process, you can have only one Qt Platform (QPA) Plugin. To interact with the underlying window system, Qt needs to load this plugin first. The QPA plugin decides how many top-level windows you can open; but Qt can only load one such plugin at any point and it cannot be switched out at runtime. If you are using a low-level plugin, one that does not talk to a windowing system, such as EGL full-screen on an embedded device, you can only open one full screen window: the System UI.
Now, each top-level window can have only one scene graph, and each tree of QtQuick items needs to be ties to only one scene graph. Consequently, you will always have only one window, one scene graph, and one QML engine in your System UI; no matter whether applications run within the System UI's process, or in separate processes.
The single-process mode allows for:
- Specific system applications to run with maximum performance, with no compositing
- Scaling down your system to target hardware that lacks RAM/GPU resources to run in multi-process mode
- Development on platforms that do not yet support multi-process mode, such as Windows, macOS, Android, QNX, as well as targets with broken Wayland drivers
However, the cost of using single-process mode is reduced stability and testability: you cannot test your components in isolation, which makes it difficult to diagnose errors or crashes.
In operating systems, the concept of a process is intertwined with the concept of isolation. Processes cannot easily affect each other - the operating system ensures this to the best of its ability. This isolation is crucial, both from a security standpoint and for stability. If a process crashes, it won't take down another process along the way, for example.
Sometimes, this isolation can hinder you, as a developer, if you need to cross this boundary to communicate with another process. Then, you need to make an effort to do this correctly, by using dedicated inter-process communication mechanisms, typically available as APIs.
If all your code runs within the same process, then you can avoid the use of tedious and asynchronous inter-process communication channels. Instead, you can directly access variables and call functions that you need.
Since single-process mode only has one QML engine, shared amongst the System UI and all applications, any QML import paths provided, for example via
am-config.yaml, is taken into consideration when the engine is resolving import statements. Import statements provided by the application manifest file,
info.yaml, are only considered once the application has started, but is still loaded even after the application has stopped.
In multi-process mode, only import paths specific to an application are considered. Additionally, absolute import paths cannot be used in
info.yaml files, due to potential restrictions imposed by containers and for security reasons.
In general, paths defined in the configuration might be provided to QML as absolute paths in single-process mode; but as relative paths in multi-process mode.
Similarly, a custom
pluginPath as part of
info.yaml behaves differently in single-process mode, than in multi-process mode. When a new process starts in multi-process mode, the new
pluginPath can be added to Qt very early on, before most systems are initialized. This ensures that when a QPluginLoader is used, the
pluginPath is correct. In comparison, with single-process mode, we need to add an additional
pluginPath to the QApplication already running. Whether this change has any effect depends on how the plugin is loaded: if the
pluginPath is reevaluated whenever a new plugin needs to be loaded.
Note: In single-process mode, some configuration options have no effect, such as:
crashAction, and so on.
The application manager is built with multi-process support, as long as Qt's Wayland compositor module is available. To disable multi-process support, explicitly specify the
-config force-single-process option. If you specify the
-config force-multi-process option, and the compositor is not available, the configuration step fails.
If the application manager supports single-process mode only, QML applications that use the
qml runtime will always run in the same process as the System UI. In this case, native applications are omitted, since they can only run in a dedicated process. This difference is the entry point:
native runtimes have an executable and
qml runtimes have a main QML file. For the latter the application manager provides the executable (
appman-launcher) in multi-process mode.
If the application manager is built with multi-process mode, you can still force it to run in single-process mode by passing
--force-single-process on the command line. This results in the same runtime behavior as described above. Even when running the application manager in multi-process mode it does not necessarily mean that QML applications get a dedicated process: if they use the
qml-inprocess runtime they will execute in-process within the System UI.
A key point to note is that, when an application in single-process mode crashes, it terminates the entire program. In contrast, when an application in multi-process mode crashes, the System UI and other applications keep on running. In multi-process mode the System UI is even notified when an application crashes and can react on it, for example by restarting the application.
The usage of QML singletons in an application has some implications. In QML, singletons live in their own private, but global context - they are even shared between multiple QML engine instances. Singletons are instantiated once and for all, on first use, and remain as long as the process exists. This means that if an application is terminated in single-process mode, any singleton that was already instantiated will persist and keep its current state. Consequently, when the application is restarted again, the singleton's state may differ from the multi-process case, where the singleton is instantiated anew.
Windows are represented differently, whether you run your application in single-process or multi-process mode. Windows are exposed from the application to the System UI through WindowManager::windowAdded. For convenience and to serve as a replacement for Qt's standard
qml tools, it is possible to use plain QML Windows in applications or even an Item as the root element. However, if you require close resemblance between single-process and multi-process mode for your application, you have to use an ApplicationManagerWindow. There are also other benefits to using an ApplicationManagerWindow, such as window properties.
In multi-process mode an ApplicationManagerWindow derives from Window; unlike in single-process mode which derives from QtObject. As a result, several properties coming from Window won't have any effect in single-process mode, although ApplicationManagerWindow still defines them for compatibility. The following are some examples:
- An ApplicationManagerWindow is exposed to the System UI in two different ways.
- In multi-process mode, a handle to the window's content surface is sent over the process boundary via the Wayland protocol. The System UI gets this as a surface Item, which is hierarchically independent from the application's window.
- In single-process mode, the ApplicationManagerWindow provides its
contentElementItem directly to System UI. Consequently, it's possible for an application to gain access to Items from System UI itself or from any other running application as they are all sharing the same QML scene.
- Many properties, functions, and signals defined in a Window are not yet reimplemented in the single-process version of ApplicationManagerWindow.
- An error encountered in a code block due to properties or methods described above will cause subsequent statements not to be evaluated in multi-process mode; but this is not the case in single-process mode.
CPU usage on a multi-core system may be more efficient in multi-process mode, since the OS can schedule more processes and potentially better utilize the cores.
However, the memory consumption per application in multi-process mode is higher compared to single-process mode. The GPU needs more memory, to allocate additional window surface buffers. Also, textures that hold application assets are not shared. If two applications render the same image file, two textures are created in multi-process mode; instead of one only one in single-process mode.
The CPU memory consumption per application is higher due to additional data structures. For instance, if one application is running, there are two instances of the QML engine in multi-process mode: one for the System UI and one for the application. In single-process mode there is only one instance since everything is running within the System UI. Also assets might be duplicated in multi-process mode. This can be mitigated though, by using shared image providers or by removing images from CPU memory once they are uploaded to GPU memory, via the QSG_TRANSIENT_IMAGES environment variable.
On the other hand, multi-process mode comes with the big advantage, that applications which are not needed any more can be terminated and hence will free their allocated resources. In single-process mode applications are never really terminated, so their memory is not freed, causing the total consumption to grow steadily with each application starting, no matter, whether they have been stopped. The QML engine doesn't allow you to unload parts of the object hierarchy.
If your application needs to support both, single-process mode and multi-process mode, you must define a set of Inter-Process Communication (IPC) interfaces between the application and System UI, and always stick to them. Consider making these interfaces part of your review policy. While you can use any IPC mechanism that suits your use case, the application manager includes an IPC mechanism that fully abstracts the single-process vs. multi-process difference. This mechanism also makes it easy to create new interfaces for QML developers.
Be aware that the application manager's IPC is not suitable to interface your entire middleware. Its sole purpose is to avoid a situation where there is a large number of one-off daemons that need to be kept track of, involving various pieces of state information that need to be shared between the System UI and some or all applications.
© 2019 Luxoft Sweden AB. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.