A container in the application-manager world describes an execution environment for an executable (either an app's binary or its runtime binary) in multi-process mode. This does not have to be something sophisticated like a Docker container, but can be as simple as an Unix process.

Predefined Containers

The application-manager comes with a single type of container built-in: the process container, which simply spawns a new Unix process to execute the requested binary.

In addition, a very basic integration of Pelagicore's software-containers is provided in examples/softwarecontainers. This can be used as a blueprint to either create a customer-specific production version of a softwarecontainers plugin, or to integrate another container solution.

Extending with Container Plugins

Custom container solution can easily be added via plugins. These plugins need not to be built as part of the application-manager, but they need to be built against a private Qt module to get the interface definition:

CONFIG += plugin
TARGET = mycontainer-plugin

QT += appman_plugininterfaces-private

The only thing you have to then implement are two classes that derive from ContainerInterface and from ContainerManagerInterface respectively, e.g.:

#include <QtAppManPluginInterfaces/containerinterface.h>

class SoftwareContainer : public ContainerInterface
    // ...

class SoftwareContainerManager : public QObject, public ContainerManagerInterface
    Q_PLUGIN_METADATA(IID AM_ContainerManagerInterface_iid)

    // ....

Please be aware that your container plugin has to support a few basic requirements in order to support UI clients in multi-process mode:

  1. The plugin has to be able to forward Unix local sockets into the container. This is needed for both the Wayland socket as well as for the private peer-to-peer D-Bus connection. If the plugin is not able to map these sockets to the exact same location within the container, it needs to alter the environment variables for the respective locations before passing them into the container. See below for a list of relevant environment variables.
  2. In order to support hardware OpenGL acceleration, the container needs to have access to the necessary devices: for GPUs following Linux standards (e.g. Intel), you have to make sure to have /c{/dev/dri/*} available within the container.
  3. If you want to make use of the application-manager's security features, you also have to implement PID mapping in your plugin (this is unnecessary if your container solution shares its PID namespace with the rest of the system). Every connection coming into the application-manager via the Wayland or D-Bus Unix local sockets is queried for the PID of the application requesting the connection. The application-manager will verify these PIDs against the PIDs of all running applications via ContainerInterface::processId(). Connections that will not match a PID will not be accepted. This behavior can be disable though by use of the --no-security command line option.

The application-manager will use these environment variables to communicate various settings to the application. A custom container plugin has to make sure to forward these or adjust them accordingly:

WAYLAND_DISPLAYThe path to the Wayland server socket. If your container uses its own filesystem namespace, you need to make sure that this socket gets forwarded accordingly.
QT_QPA_PLATFORMAlways set to wayland.
QT_IM_MODULENot really set, but explicitly unset by the application-manager. Make sure to not set it, if the automatic Wayland input method implementation should be used.
DBUS_SESSION_BUS_ADDRESSThe standard D-Bus session bus
AM_DBUS_PEER_ADDRESSThis variable holds the D-Bus socket identifier for the private peer-to-peer bus between the application-manager and the application. If your container uses its own filesystem namespace, you need to make sure that this socket gets forwarded accordingly.
AM_DBUS_NOTIFICATION_BUS_ADDRESSSince the org.freedesktop.Notifications interface could be on a different bus as the rest of the D-Bus interfaces, the application-manager needs to tell the application explicitly where to look for this interface.
AM_BASE_DIRThe current directory of the application-manager.
AM_RUNTIME_SYSTEM_PROPERTIESThe public part of the system properties, encoded as an YAML document.
AM_NO_DLT_LOGGINGTells the application to not use DLT for logging.


There are three parts to the container configuration:

  1. Configure which containers are available at all.
  2. Add specific settings for each available container integration.
  3. Configure which container solution is selected to run a specific application.

Load Container Plugins

In order to activate an existing container plugin for use in the application-manager, you need to add its full path to the list of plugins to load in the application-manager's config file:

  container: [ "/full/path/to/", "/another/" ]

Please note that the application-manager does not load plugins automatically if they are placed in a specific directory, since container plugins control the central security mechanism for separating applications.

Container Integration Configuration

Each container integration has an unique id, which can be used to add settings to the application-manager's config file, e.g.

    defaultControlGroup: "foo"
    bar: [ 1, 2, 3 ]

The process container accepts the following configuration settings:

controlGroupsobjectA two-stage mapping object to allow for more readable code when dealing with cgroups from the System-UI via Container::controlGroup. The top-level keys are readable group names that are used to interface Container::controlGroup, while the values are themselves maps between multiple low-level cgroup sub-system names and the actual cgroup names within those sub-systems, e.g.:
    memory: mem1
    cpu: cpu_full
    memory: mem2
    cpu: cpu_minimal
defaultControlGroupstringThe default control group for an application when it is first launched.

For other container plugins, please consult the respective documentation.

Container Selection Configuration

There are multiple ways to control which container integration is used when starting an application from within the application-manager:

  1. If the config file does not contain the key containers/selection, the container integration id will default to process
  2. If the aforementioned key exists, its contents will be parsed as a list of maps, where each map only has a single mapping (this is a bit awkward, but needed to preserve the order of the mappings). Each key is interpreted as a standard Unix wildcard expression that will be matched against the application id. The first match will stop this algorithm and the mapping's value will be used as the container integration id. If no matches are found, the resulting containter integration id will be the empty string.
      - com.pelagicore.*: "process"
      - com.navigation: "special-container"
      - '*': "softwarecontainers"  # a single asterisk needs to be quoted
  3. Afterwards, if the System-UI did set the ApplicationManager::containerSelectionFunction property to a valid JavaScript function, this function will be called with the first parameter set to the application's id and the second parameter set to the container integration id that resulted from step 1 and 2.
    ApplicationManager.containerSelectionFunction = function(appId, containerId) {
        var app = ApplicationManager.application(appId)
        if (app.capabilities.indexOf("non-secure") != -1)
            return "process"
            return containerId

© 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.