summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Holland <dominik.holland@qt.io>2019-10-11 17:03:03 +0200
committerDominik Holland <dominik.holland@qt.io>2019-10-11 17:23:26 +0200
commit0120c4c892c3765fba18b15e3a28d446bf1a3f38 (patch)
treee43eb152fa71d5eb99c4d4c89af8d317b1560429
parenta8e9fa8d30c3298ac90e1c539d8f62bcc99c7107 (diff)
parent5f05117fb8c31ad58937d6b5bd55139a697c2673 (diff)
Merge remote-tracking branch 'origin/5.13' into dev
-rw-r--r--doc/configuration.qdoc11
-rw-r--r--doc/container.qdoc22
-rw-r--r--doc/index.qdoc4
-rw-r--r--doc/manifest.qdoc7
-rw-r--r--doc/singlevsmultiprocess.qdoc8
-rw-r--r--doc/systemui.qdoc197
-rw-r--r--doc/write-applications.qdoc (renamed from doc/apps.qdoc)2
-rw-r--r--examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.h2
-rw-r--r--examples/applicationmanager/softwarecontainer-plugin/README.md72
-rw-r--r--examples/applicationmanager/softwarecontainer-plugin/doc/src/softwarecontainer-plugin.qdoc106
-rw-r--r--src/main-lib/defaultconfiguration.cpp10
-rw-r--r--src/main-lib/defaultconfiguration.h1
-rw-r--r--src/main-lib/main.cpp1
-rw-r--r--src/manager-lib/application.h2
-rw-r--r--src/manager-lib/processstatus.cpp2
-rw-r--r--src/manager-lib/qmlinprocessruntime.cpp11
-rw-r--r--src/plugin-interfaces/containerinterface.cpp9
-rw-r--r--src/tools/launcher-qml/launcher-qml.cpp44
18 files changed, 397 insertions, 114 deletions
diff --git a/doc/configuration.qdoc b/doc/configuration.qdoc
index 1a60184c..972d866a 100644
--- a/doc/configuration.qdoc
+++ b/doc/configuration.qdoc
@@ -222,6 +222,10 @@ or across multiple config files, the final value is resolved based on these rule
\li array<string>
\li Adds additional QML import paths to the System UI.
\row
+ \li [\c ui/pluginPaths]
+ \li array<string>
+ \li Adds additional Qt plugin paths to the System UI.
+ \row
\li [\c ui/style]
\li string
\li If set, the given style is used by QtQuickControls 2.
@@ -524,7 +528,12 @@ an additional column specifying which runtime a configuration option applies to:
\li \c importPaths
\li qml
\li array<string>
- \li Adds an additional QML import path for apps started via this runtime.
+ \li Adds additional QML import paths for apps started via this runtime.
+ \row
+ \li \c pluginPaths
+ \li qml
+ \li array<string>
+ \li Adds additional Qt plugin paths for apps started via this runtime.
\row
\li \c plugins
\li qml
diff --git a/doc/container.qdoc b/doc/container.qdoc
index fd7070e4..cbb8d182 100644
--- a/doc/container.qdoc
+++ b/doc/container.qdoc
@@ -38,13 +38,15 @@ simple as a Unix process.
\section1 Predefined Containers
-The application manager comes with a one built-in container type: the \c process container,
+The application manager comes with one built-in container type: the \c process container,
that spawns a new Unix process to execute the requested binary.
In addition, you can find a basic integration of Pelagicore's
-\l{https://github.com/Pelagicore/softwarecontainer}{software-containers} in \c
-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.
+\l{https://github.com/Pelagicore/softwarecontainer}{SoftwareContainer} in \c
+examples/applicationmanager/softwarecontainer-plugin. For more information, see
+\l{SoftwareContainer Plugin Example}. This example can be used as a blueprint to either create a
+customer-specific production version of a SoftwareContainer plugin, or to integrate another
+container solution.
\section1 Extend with Container Plugins
@@ -60,8 +62,8 @@ TARGET = mycontainer-plugin
QT += appman_plugininterfaces-private
\endcode
-Then, you only have to implement two classes that derive from \c ContainerInterface
-and from \c ContainerManagerInterface respectively:
+Then, you only have to implement two classes that derive from \l ContainerInterface
+and from \l ContainerManagerInterface respectively:
\code
#include <QtAppManPluginInterfaces/containerinterface.h>
@@ -91,8 +93,8 @@ in multi-process mode:
locations before passing them on to the container. The table below lists the relevant
environment variables.
\li To support hardware OpenGL acceleration, the container needs to have access to the necessary
- device. For GPUs that follow Linux standards, such as Intel, make sure to have /c{/dev/dri/*}
- available within the container.
+ devices. For GPUs that follow Linux standards, such as Intel, make sure to have
+ \c{/dev/dri/*} available within the container.
\li You have to implement PID mapping in your plugin; unless your container solution shares its
PID namespace with the rest of the ssytem. This is necessary if you want to make use of the
application manager's security features. Each connection coming into the application manager
@@ -119,7 +121,7 @@ the application. A custom container plugin must forward these variables or adjus
\li Always set to \c{wayland}.
\row
\li \c{QT_IM_MODULE}
- \li Not set, but explicitly unset by the application manager. Make sure to leave it unset it, to
+ \li Not set, but explicitly unset by the application manager. Make sure to leave it unset, to
use the automatic Wayland input method implementation.
\row
\li \c{DBUS_SESSION_BUS_ADDRESS}
@@ -233,7 +235,7 @@ control which container integration is used:
each map has a single mapping only. While this single mapping is awkward, it is necessary to
preserve the order of the mappings. Each key is interpreted as a standard Unix wildcard
expression that is matched against the application ID. The first match stops the algorithm
- and the mapping's value is used as the container integration ID. If no matches are found,=
+ and the mapping's value is used as the container integration ID. If no matches are found,
the resulting containter integration ID is an empty string.
\badcode
diff --git a/doc/index.qdoc b/doc/index.qdoc
index d66b10ee..eea6a238 100644
--- a/doc/index.qdoc
+++ b/doc/index.qdoc
@@ -45,9 +45,7 @@ For a high-level overview, see \l{The Qt Application Manager}{Introduction to th
\li \l{Installation}
\li \l{Configuration}
\li \l{Troubleshoot}
- \omit
- \li \l{How to write a System-UI}
- \endomit
+ \li \l{The System UI}
\li \l{Write Applications}
\li \l{Application Installer}
\li \l{Logging and Debugging}
diff --git a/doc/manifest.qdoc b/doc/manifest.qdoc
index d38a4d00..b73310fa 100644
--- a/doc/manifest.qdoc
+++ b/doc/manifest.qdoc
@@ -278,6 +278,13 @@ that specifies which runtime a configuration option applies to:
resources \l{Compiled-In Resources}{compiled-in} and registers them within the application
process. Resources can be accessed with the ":" or "qrc://" file path prefix.
\row
+ \li \c pluginPaths
+ \li qml, qml-in-process
+ \li array<string>
+ \li A list of paths to add to Qt's library paths, which are used to find plugins. Use of this
+ parameter is equivalent to setting \c QT_PLUGIN_PATH for a program started from the command
+ line.
+\row
\li \c arguments
\li native
\li array<string>
diff --git a/doc/singlevsmultiprocess.qdoc b/doc/singlevsmultiprocess.qdoc
index f4000092..767aa099 100644
--- a/doc/singlevsmultiprocess.qdoc
+++ b/doc/singlevsmultiprocess.qdoc
@@ -97,6 +97,14 @@ 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 \c pluginPath as part of \c info.yaml behaves differently in single-process
+mode, than in multi-process mode. When a new process starts in multi-process mode, the new \c
+pluginPath can be added to Qt very early on, before most systems are initialized. This ensures that
+when a QPluginLoader is used, the \c pluginPath is correct. In comparison, with single-process
+mode, we need to add an additional \c pluginPath to the QApplication already running. Whether this
+change has any effect depends on how the plugin is loaded: if the \c pluginPath is reevaluated
+whenever a new plugin needs to be loaded.
+
\note In single-process mode, some configuration options have no effect, such as: \c quicklaunch,
\c quicklaunchQml, \c crashAction, and so on.
diff --git a/doc/systemui.qdoc b/doc/systemui.qdoc
index 334e940c..170cdbbb 100644
--- a/doc/systemui.qdoc
+++ b/doc/systemui.qdoc
@@ -26,21 +26,194 @@
**
****************************************************************************/
-/*
- We should mention some peculiarities, once this is documented:
+/*!
- If the root element of the System-UI is an Item, the application-manager will create a
- QQuickWindow for it and set the Item as its root Item.
+\page system-ui.html
+\title The System UI
- If the root element of the System-UI is a Window (or an Item, which will be wrapped in a
- Window, see above), the window will be shown initially, regardless of its visible property.
- Also, it will be registered as a compositor view. All other windows have to be registered
- manually.
-*/
+The System UI is the part of a UI which starts and stops any application, on a device. It's
+responsible for managing the application windows and compositing them in a specific way. For
+example, to display the applications in full-screen, or to allow multiple windows to be displayed
+from different applications at the same time.
-/*!
+On desktop systems, the System UI is akin to the Microsoft Windows' Shell, or KDE's Plasmashell
+plus the KWin compositor.
+
+The System UI has the following tasks:
+\table
+ \header
+ \li Task
+ \li Description
+ \row
+ \li Compositing
+ \li Manage multiple applications' surfaces, known as windows. \br
+ Arrange these windows on one or more physical screens, according to the required
+ design. \br
+ Handle window decoration, transition effects and other system-wide user experience.
+ \row
+ \li Communication Interface
+ \li Act as a channel to exchange information between applciations and itself, such as to
+ switch the language.
+ \row
+ \li Input Handling
+ \li Switch focus between input events, according to the user's current focus. \br
+ Provide system input services, such as launch a virtual keyboard for touch-based
+ systems.
+ \row
+ \li Manage system-wide applications and services
+ \li Manage the application life-cycle, by starting applications upon user interaction and
+ stopping them in critical situations, such as low memory. \br
+ Provide a central UI to monitor the UI performance and all applications that have
+ started, by showing statistics such as frame rate, the amount of CPU currently used,
+ and memory resources.
+ \row
+ \li Manage idle time and display the \uicontrol{Home Screen}
+ \li Display the default view to the user after startup. \br
+ Display essential data, such as the current time. \br
+ Display a view composed of several selected applications.
+\endtable
+
+\section1 Implement a System UI
+
+The System UI's main feature is its ability to manage multiple applications and windows.
+Consequently, Linux-based systems are the recommended development environment, where multi-process
+mode is enabled. On other Operating Systems, you can use the single-process mode. For more
+information on the difference between single-process and multi-process, see
+\l{Single-Process vs. Multi-Process Mode} and \l{Wayland and Qt}.
+
+\section2 Window Management
+
+The System UI's central role is to handle application windows. On the client side, you need to use
+an \l{ApplicationManagerWindow}. On the System UI side, you need to implement a handler for
+WindowManager::windowAdded. Whenever a client window becomes visible, the WindowManager::windowAdded
+signal is emitted. The signal has one parameter, WindowObject, which is the System UI side
+representation of the client side ApplicationManagerWindow.
+
+To differentiate between client windows, you should use window properties. For instance, you could
+attach a \c type property to a client window, to tell the System UI, whether it's a top-level
+window, a popup, or something else. Both client and server side window representations can access
+these properties. Typically, they are always in-sync; but the underlying Wayland protocol is
+entirely asynchronous.
+
+To include the WindowObject in the System UI's render tree, set the WindowObject as the \c window
+property for a WindowItem. The WindowItem acts as a container \l{Item} for WindowObjects.
+Consequently, the WindowItem determines the position, visibility, and so on, of the client window
+in the System UI.
+
+One example of a simple System UI is the one written for the "Hello World!" System UI Example:
+
+\quotefromfile ../examples/applicationmanager/hello-world/system-ui.qml
+\skipto Item {
+\printuntil window: model.window } } } }
+
+\section2 Notifications
+
+In cases where you'd like to display notificiations or pop-ups, applications or clients can
+create these with \l{ApplicationInterface.createNotification()}. They are then made available
+on the System UI via the \l{NotificationManager}.
+
+The code snippet below is part of the \l{Desktop System UI Example} that illustrates how to
+display pop-ups.
+
+\quotefromfile ../examples/applicationmanager/minidesk/system-ui/main.qml
+\skipto System-UI for a notification
+\printto Handler for WindowManager signals
+
+\section2 Intents
+
+The System UI and other applications can send and receive intents. This is exposed via the
+\l{Intent} and \l{IntentServer} QML types. The Intent represents a single intent definition on
+the System UI; the IntentServer is the singleton on the System UI-side that represents the
+intents sub-system.
+
+For more details on implementing support for intents, see the
+\l{Intents System UI and Applications Example}.
+
+\section2 Life-Cycle
+
+The \l{ApplicationManager} provides APIs to start and stop an application. However, the
+recommended approach is to use \l{ApplicationObject::start()} and \l{ApplicationObject::stop()}.
+Optionally, you can also pass a \c documentUrl in the \l{ApplicationObject::start()}{start()}
+function. Then, when you call \c{start()} several times, with a different \c documentUrl()
+each time, you won't be restarting the application; but only triggering the
+\l{ApplicationInterface::openDocument()} on the application or client side.
+\l{ApplicationInterface::stop()} triggers \l{ApplicationInterface::quit()} on the application
+side. The application should do all the necessary clean-ups and then confirm that it can be
+terminates with \l{ApplicationInterface::acknowledgeQuit()}.
+
+You can implement other life-cycle management features that are tailored to the specific
+requirements of IPC mechanisms like window properties, \l{ApplicationInterfaceExtension},
+or proprietary IPCs.
+
+For more information, see the \l{Desktop System UI Example}.
+
+\section2 Monitoring
+
+To monitor your application, you can use the \l{MonitorModel} to fetch data from various
+sources at intervals and store a history of these values. You can use this data for analytical
+purposes, such as to plot its previous values over time. For more information, see the
+\l{Display Information about Application Processes Example}.
+
+\section2 Application Installer
+
+The \l{ApplicationManager} provides a list of all available applications in the
+\l{ApplicationModel}. In addition to applications bundled with the System UI,
+\e{system applications}, the ApplicationManager also provides a way to install new applications
+at runtime. These applications are maintained by the \l{ApplicationInstaller} singleton.
+
+To start an installation, use \l{ApplicationInstaller::startPackageInstallation}. Once all
+metadata from the application's package is extracted, the
+\l{ApplicationInstaller::taskRequestingInstallationAcknowledge} signal is emitted. This signal
+can be used to give you more information about the package, such as the name, size, or
+permissions. This installation needs to be confirmed using
+\l{ApplicationInstaller::acknowledgePackageInstallation}. After the installation is complete,
+you can start the new application, as described in the \l{Life-Cycle}. To remove applications
+that have been installed, use \l{ApplicationInstaller::removePackage}.
+
+For more information, see \l{Application Installer}.
+
+\section1 Best Practices When You Write a System UI
+
+Below are some key practices to consider when you write a System UI:
+
+\list
+ \li \b{Always test your System UI and its applications on the target as early as possible.}
+ This is especially useful because the combination of your target hardware and the
+ asynchronous Wayland protocol may result in some timing constraints on some parts of
+ the system. For example, when are window properties available to the System UI, after
+ an application has started. These constraints are best identified as early as possible.
+ To be able to run a fluent UI, hardware acceleration is necessary for the System UI as
+ well as for applications (or Wayland clients). This fluency is achieved via hardware
+ specific texture sharing mechanisms. Now, these mechanisms are hardware specific and
+ it's likely that a different mechanism is used on the target platform, compared to your
+ development machine. Testing on the target hardware as early as possible can help to
+ bring forward any issues with the sharing mechanism or side effects from other graphic
+ intense elements, such as shader effects or 3D engine integrations.
+ \li \b{Allow the System UI to stop applications that take up too much memory or CPU.}
+ Design your system in such a way that lets the System UI stop applications when necessary,
+ particularly in situations where hardware resources like memory or CPU is low. This
+ provides better scalability.
+ \li \b{Always use two different plugin folders.}
+ One folder for System UI-specific or privileged applications. Another folder for other
+ applications that contain base elements, such as your UI style or the Items for your
+ different window types.
+\endlist
+
+
+\section1 Notes on The Root Element
+
+\list
+ \li If the root element of the System UI is an Item, the application manager creates a
+ QQuickWindow for it and sets the Item as its root Item.
+ \li If the root element of the System UI is a Window -- or an Item that is wrapped in a Window
+ -- the window is shown initially, regardless of the value of its \c visible property.
+\endlist
+
+\section1 Related Information
-\page howto-sysui.html
-\title How to write a System-UI
+\list
+ \li \l{Write Applications}
+ \li \l{QtApplicationManager.SystemUI QML module}
+\endlist
*/
diff --git a/doc/apps.qdoc b/doc/write-applications.qdoc
index 49d5f708..8c0c590a 100644
--- a/doc/apps.qdoc
+++ b/doc/write-applications.qdoc
@@ -44,7 +44,7 @@ stand-alone QML application, except for these three additional tasks:
\section2 The Root Element
-It is recommended to use either an ApplicationManagerWindow or a QtObject as the root of your QML
+It's recommended to use either an ApplicationManagerWindow or a QtObject as the root of your QML
application. This is especially important if you require similar behavior in single-process and
multi-process mode. If you use a QtObject, any visible base elements should still be
\l{ApplicationManagerWindow}{ApplicationManagerWindows}. Nevertheless, other root elements are
diff --git a/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.h b/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.h
index d8fabbf9..5d59d6ea 100644
--- a/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.h
+++ b/examples/applicationmanager/application-features/imports/terminator2/qmlterminator2.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
** Commercial License Usage
diff --git a/examples/applicationmanager/softwarecontainer-plugin/README.md b/examples/applicationmanager/softwarecontainer-plugin/README.md
deleted file mode 100644
index d599c854..00000000
--- a/examples/applicationmanager/softwarecontainer-plugin/README.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# SoftwareContainer Plugin
-
-This is a very basic PoC integration of Pelagicore's Software-Containers
-
-[https://github.com/Pelagicore/softwarecontainer][]
-
-Please also read the "Containers" page in the official Qt Application Manager
-documentation:
-[https://doc-snapshots.qt.io/qtapplicationmanager/containers.html]
-
-Parts of the container configuration are hardcoded in `softwarecontainer.cpp`,
-while all of the capability definition is in the JSON manifest at
-`service-manifest.d/io.qt.ApplicationManager.Application/`.
-
-The Wayland/OpenGL pass-through is tested against Intel GPUs and VMware's
-virtual GPU.
-
-The softwarecontainer-agent needs to be started as root. By default it will
-register itself on the system D-Bus, so a policy file must be in place,
-allowing it to register itself on the system-bus. If you want to run the
-agent on the session bus instead (via the `--session-bus` parameter), you
-have to add the following to one of your config.yaml files:
-```
-containers:
- softwarecontainer:
- dbus: 'session'
-```
-
-Passing the service-manifest directory that comes with the plugin via
-`-m` is mandatory - otherwise the container setup will fail due to the
-missing `io.qt.ApplicationManager.Application` capability.
-
-You have to make sure that the agent has access to the same session-bus
-that the application-manager is using, if you intend on forwarding this
-bus. This is a bit tricky if the agent is run as root and the application-
-manager as non-root user, since the default session-bus policy in most
-distros disallows root to access user session-busses: the workaround is to
-add a `<allow user="root"/>` policy within the `<policy context="default">`
-element in `/etc/dbus-1/session.conf`.
-
-Please do also not forget to tell the agent about your environment, when
-running it via sudo:
-```
-sudo XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR
-DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS softwarecontainer-agent -m
-/path/to/application-manager/examples/softwarecontainer-plugin/service-manifest.d/
-```
-
-On the AM side, you need to activate the plugin by adding something like
-this to one of your config.yaml files:
-```
-plugins:
- container: [ "/path/to/libsoftwarecontainer-plugin.so" ]
-```
-In order to actually run apps within softwarecontainers, you have to add a
-container selection configuration:
-[https://doc-snapshots.qt.io/qtapplicationmanager/containers.html#container-selection-configuration][]
-
-
-Please be aware that for easier development on the desktop, you normally want
-your $HOME directory mounted into the container in read-only mode, so you do
-not have to install your application-manager into /usr/ after every build
-(given that your build directory is somewhere in $HOME, the container would
-not see the appman-launcher-qml binary).
-This is *not* done by default, but you can activate this behavior by adding
-this to one of your config.yaml files:
-
-```
-containers:
- softwarecontainer:
- bindMountHome: yes
-```
diff --git a/examples/applicationmanager/softwarecontainer-plugin/doc/src/softwarecontainer-plugin.qdoc b/examples/applicationmanager/softwarecontainer-plugin/doc/src/softwarecontainer-plugin.qdoc
new file mode 100644
index 00000000..b920b4fb
--- /dev/null
+++ b/examples/applicationmanager/softwarecontainer-plugin/doc/src/softwarecontainer-plugin.qdoc
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:FDL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\example applicationmanager/softwarecontainer-plugin
+\brief Learn how to integrate Software Containers with the Application Manager.
+\ingroup applicationmanager-examples
+\title SoftwareContainer Plugin Example
+
+\section1 Introduction
+
+This example shows how to integrate \l{https://github.com/Pelagicore/softwarecontainer}
+{Pelagicore's SoftwareContainers} with the Application Manager.
+
+\note As a prerequisite, familiarize yourself with \l{Containers} beforehand.
+
+In \c softwarecontainer.cpp, parts of the container's configuration is hardcoded; all of the
+capability definition is in the JSON manifest file located in
+\c{service-manifest.d/io.qt.AppliciationManager.Application/}.
+
+The Wayland/OpenGL passthrough is tested against Intel GPUs and VMWare's virtual GPU.
+
+\section1 Run the SoftwareContainer Agent
+
+To run the softwarecontainer-agent, you must start it as root. By default, this agent registers
+itself on the system D-Bus. So, you need to have a policy file in place, to allow the agent to
+register itself on the system-bus.
+
+If you want to run the agent on the session bus instead, via the \c{--session-bus} parameter,
+then you have to add the following lines to one of your \c config.yaml files:
+
+\badcode
+containers:
+ softwarecontainer:
+ dbus: 'session'
+\endcode
+
+It's mandatory to pass the service manifest directory that comes with the plugin via \c{-m}.
+Otherwise, the container setup fails due to the missing \c{io.qt.ApplicationManager.Application}
+capability.
+
+Make sure that the agent has access to the same session bus that the application manager uses,
+if you intend on forwarding this bus. If the agent is run as root, but the application manager
+isn't, this can be tricky -- since the default session bus policy in most Linux distros
+disallows root to access user session busses. However, you can workaround this issue by adding
+an \c{<allow user="root"/>} policy within the \c{<policy context="default">} element in
+\c{/etc/dbus-1/session.conf}.
+
+Additionally, make sure to tell the agent about your environment, when running it via sudo:
+
+\badcode
+sudo XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR
+DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS softwarecontainer-agent -m
+/path/to/application-manager/examples/softwarecontainer-plugin/service-manifest.d/
+\endcode
+
+On the Application Manager side, you need to activate the plugin by adding a line similar to the
+one shown below, to one of your \c config.yaml files:
+
+\badcode
+plugins:
+ container: [ "/path/to/libsoftwarecontainer-plugin.so" ]
+\endcode
+
+To actually run applications within software containers, you have to add a container selection
+configuration. For more information, see \l{Container Selection Configuration}.
+
+To simplify developing on the desktop, normally, you want your \c $HOME directory mounted into
+the container in \c read-only mode. This way, you don't have to install your application manager
+into \c{/usr/} after every build. This behavior only works, given that your build directory is
+located somewhere in \c{$HOME}, otherwise the container won't see the appman-launcher-qml binary.
+This behavior is \b not enabled by default; but you can activate it with the following lines in
+one of your \c config.yaml files:
+
+\badcode
+containers:
+ softwarecontainer:
+ bindMountHome: yes
+\endcode
+
+*/
diff --git a/src/main-lib/defaultconfiguration.cpp b/src/main-lib/defaultconfiguration.cpp
index 3974f128..49fe47aa 100644
--- a/src/main-lib/defaultconfiguration.cpp
+++ b/src/main-lib/defaultconfiguration.cpp
@@ -262,6 +262,16 @@ QStringList DefaultConfiguration::importPaths() const
return importPaths;
}
+QStringList DefaultConfiguration::pluginPaths() const
+{
+ QStringList pluginPaths = value<QStringList>(nullptr, { "ui", "pluginPaths" });
+
+ for (int i = 0; i < pluginPaths.size(); ++i)
+ pluginPaths[i] = QFileInfo(pluginPaths.at(i)).absoluteFilePath();
+
+ return pluginPaths;
+}
+
bool DefaultConfiguration::verbose() const
{
return value<bool>("verbose") || m_forceVerbose;
diff --git a/src/main-lib/defaultconfiguration.h b/src/main-lib/defaultconfiguration.h
index 686f8b5a..25129719 100644
--- a/src/main-lib/defaultconfiguration.h
+++ b/src/main-lib/defaultconfiguration.h
@@ -77,6 +77,7 @@ public:
bool noFullscreen() const;
QString windowIcon() const;
QStringList importPaths() const;
+ QStringList pluginPaths() const;
bool verbose() const;
void setForceVerbose(bool forceVerbose);
bool slowAnimations() const;
diff --git a/src/main-lib/main.cpp b/src/main-lib/main.cpp
index e66a3710..1dcfa10f 100644
--- a/src/main-lib/main.cpp
+++ b/src/main-lib/main.cpp
@@ -255,6 +255,7 @@ void Main::setup(const DefaultConfiguration *cfg, const QStringList &deploymentW
if (!cfg->disableIntents())
setupIntents(cfg->intentTimeouts());
+ setLibraryPaths(libraryPaths() + cfg->pluginPaths());
setupQmlEngine(cfg->importPaths(), cfg->style());
setupWindowTitle(QString(), cfg->windowIcon());
setupWindowManager(cfg->waylandSocketName(), cfg->slowAnimations(), cfg->noUiWatchdog());
diff --git a/src/manager-lib/application.h b/src/manager-lib/application.h
index 9556cc3e..f7ddeae5 100644
--- a/src/manager-lib/application.h
+++ b/src/manager-lib/application.h
@@ -157,7 +157,7 @@ signals:
void lastExitStatusChanged();
void activated();
void stateChanged(State state);
- void runStateChanged(Am::RunState state);
+ void runStateChanged(QT_PREPEND_NAMESPACE_AM(Am::RunState) state);
void blockedChanged(bool blocked);
private:
diff --git a/src/manager-lib/processstatus.cpp b/src/manager-lib/processstatus.cpp
index 25ce85b1..2445b030 100644
--- a/src/manager-lib/processstatus.cpp
+++ b/src/manager-lib/processstatus.cpp
@@ -190,7 +190,7 @@ void ProcessStatus::setApplicationId(const QString &appId)
qmlWarning(this) << "Invalid application ID:" << appId;
} else {
m_application = ApplicationManager::instance()->application(appIndex);
- connect(m_application, &Application::runStateChanged, this, &ProcessStatus::onRunStateChanged);
+ connect(m_application.data(), &Application::runStateChanged, this, &ProcessStatus::onRunStateChanged);
}
}
determinePid();
diff --git a/src/manager-lib/qmlinprocessruntime.cpp b/src/manager-lib/qmlinprocessruntime.cpp
index b4a3beb4..86740662 100644
--- a/src/manager-lib/qmlinprocessruntime.cpp
+++ b/src/manager-lib/qmlinprocessruntime.cpp
@@ -123,6 +123,17 @@ bool QmlInProcessRuntime::start()
loadQmlDummyDataFiles(m_inProcessQmlEngine, QFileInfo(m_app->info()->absoluteCodeFilePath()).path());
}
+ const QStringList pluginPaths = variantToStringList(configuration().value(qSL("pluginPaths")))
+ + variantToStringList(m_app->runtimeParameters().value(qSL("pluginPaths")));
+
+ if (!pluginPaths.isEmpty()) {
+ const QString codeDir = m_app->codeDir() + QDir::separator();
+ for (const QString &path : pluginPaths)
+ qApp->addLibraryPath(QFileInfo(path).isRelative() ? codeDir + path : path);
+
+ qCDebug(LogSystem) << "Updated plugin paths:" << qApp->libraryPaths();
+ }
+
const QStringList importPaths = variantToStringList(configuration().value(qSL("importPaths")))
+ variantToStringList(m_app->runtimeParameters().value(qSL("importPaths")));
if (!importPaths.isEmpty()) {
diff --git a/src/plugin-interfaces/containerinterface.cpp b/src/plugin-interfaces/containerinterface.cpp
index 564bff94..58fc5228 100644
--- a/src/plugin-interfaces/containerinterface.cpp
+++ b/src/plugin-interfaces/containerinterface.cpp
@@ -296,8 +296,9 @@ ContainerManagerInterface::~ContainerManagerInterface() { }
The application-manager will only ever call this function once for any given instance.
This function should return \c true in case it succeeded or \c false otherwise. In case it
- returns \c true, the implementation needs to either emit the started() or errorOccurred() signal
- (can be delayed) in response to this call.
+ returns \c true, the implementation needs to either emit the started() or
+ \l{QProcess::errorOccurred()}{errorOccurred()} signal (can be delayed) in response to this
+ call.
\sa QProcess::start()
*/
@@ -326,7 +327,7 @@ ContainerManagerInterface::~ContainerManagerInterface() { }
/*! \fn void ContainerInterface::kill()
- Called by the application-manager, if it wants to kills the current process within the
+ Called by the application-manager, if it wants to kill the current process within the
container, causing it to exit immediately.
On Unix, the equivalent would be sending a \c SIGKILL signal.
@@ -431,6 +432,6 @@ ContainerManagerInterface::~ContainerManagerInterface() { }
In case the \a debugWrapperCommand is not empty, the plugin is requested to execute the binary
set by ContainterInterface::setProgram using this debug-wrapper. The plugin is responsible for
- combining both and by handling the replacement of \c{%program%} and \c{%arguments%}. See the
+ combining both and for handling the replacement of \c{%program%} and \c{%arguments%}. See the
\l{DebugWrappers} {debug-wrapper documentation} for more information.
*/
diff --git a/src/tools/launcher-qml/launcher-qml.cpp b/src/tools/launcher-qml/launcher-qml.cpp
index 9588f848..c3eb49db 100644
--- a/src/tools/launcher-qml/launcher-qml.cpp
+++ b/src/tools/launcher-qml/launcher-qml.cpp
@@ -207,20 +207,36 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc
m_configuration = a->runtimeConfiguration();
- QString absolutePath;
+ QString absolutePluginPath;
+ QStringList pluginPaths = variantToStringList(m_configuration.value(qSL("pluginPaths")));
+ for (QString &path : pluginPaths) {
+ if (QFileInfo(path).isRelative())
+ path.prepend(a->baseDir());
+ else if (absolutePluginPath.isEmpty())
+ absolutePluginPath = path;
+
+ qApp->addLibraryPath(path);
+ }
+
+ if (!absolutePluginPath.isEmpty()) {
+ qCWarning(LogDeployment).nospace() << "Absolute plugin path in the runtime configuration "
+ "can lead to problems inside containers (e.g. " << absolutePluginPath << ")";
+ }
+
+ QString absoluteImportPath;
QStringList importPaths = variantToStringList(m_configuration.value(qSL("importPaths")));
for (QString &path : importPaths) {
if (QFileInfo(path).isRelative())
path.prepend(a->baseDir());
- else if (absolutePath.isEmpty())
- absolutePath = path;
+ else if (absoluteImportPath.isEmpty())
+ absoluteImportPath = path;
m_engine.addImportPath(path);
}
- if (!absolutePath.isEmpty()) {
+ if (!absoluteImportPath.isEmpty()) {
qCWarning(LogDeployment).nospace() << "Absolute import path in the runtime configuration "
- "can lead to problems inside containers (e.g. " << absolutePath << ")";
+ "can lead to problems inside containers (e.g. " << absoluteImportPath << ")";
}
StartupTimer::instance()->checkpoint("after application config initialization");
@@ -413,10 +429,22 @@ void Controller::startApplication(const QString &baseDir, const QString &qmlFile
loadQmlDummyDataFiles(&m_engine, QFileInfo(qmlFileStr).path());
}
+ QVariant pluginPaths = runtimeParameters.value(qSL("pluginPaths"));
+ const QVariantList ppvl = (pluginPaths.type() == QVariant::String) ? QVariantList{pluginPaths}
+ : qdbus_cast<QVariantList>(pluginPaths);
+ for (const QVariant &v : ppvl) {
+ const QString path = v.toString();
+ if (QFileInfo(path).isRelative())
+ qApp->addLibraryPath(QDir().absoluteFilePath(path));
+ else
+ qCWarning(LogQmlRuntime) << "Omitting absolute plugin path in info file for safety reasons:" << path;
+ }
+ qCDebug(LogQmlRuntime) << "Plugin paths:" << qApp->libraryPaths();
+
QVariant imports = runtimeParameters.value(qSL("importPaths"));
- const QVariantList vl = (imports.type() == QVariant::String) ? QVariantList{imports}
- : qdbus_cast<QVariantList>(imports);
- for (const QVariant &v : vl) {
+ const QVariantList ipvl = (imports.type() == QVariant::String) ? QVariantList{imports}
+ : qdbus_cast<QVariantList>(imports);
+ for (const QVariant &v : ipvl) {
const QString path = v.toString();
const QFileInfo fi(path);
if (!(fi.isNativePath() && fi.isAbsolute()))