summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@qt.io>2021-02-12 17:31:29 +0100
committerRobert Griebl <robert.griebl@qt.io>2021-04-23 14:34:19 +0000
commit0633c2a16fc47a9e38623517f0b5dd38c4ecc8e9 (patch)
treef8fac9af66dbfb545d8085ef54aa65b41886a953
parent0f8d4513c0ad7423d1643385049afd70fa9b30ce (diff)
downloadqtapplicationmanager-0633c2a16fc47a9e38623517f0b5dd38c4ecc8e9.tar.gz
Add support for running multiple (external) apps with the same PID
The appId property of the incoming XDG surface is used to disambiguate Wayland mapping requests. Any other PID identification requests to the AM have to disambiguated by the caller. Change-Id: Ief5576e65b76348239a64dfd41fd887a4084168c Pick-to: 5.15 Reviewed-by: Dominik Holland <dominik.holland@qt.io>
-rw-r--r--qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes5
-rw-r--r--src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp6
-rw-r--r--src/dbus-lib/dbuspolicy.cpp6
-rw-r--r--src/dbus-lib/io.qt.applicationmanager.xml4
-rw-r--r--src/manager-lib/applicationmanager.cpp39
-rw-r--r--src/manager-lib/applicationmanager.h3
-rw-r--r--src/window-lib/waylandcompositor.cpp9
-rw-r--r--src/window-lib/waylandcompositor.h1
-rw-r--r--src/window-lib/windowmanager.cpp20
9 files changed, 83 insertions, 10 deletions
diff --git a/qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes b/qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes
index 5b7ce6ce..f9b4460c 100644
--- a/qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes
+++ b/qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes
@@ -1124,6 +1124,11 @@ Module {
Parameter { name: "pid"; type: "int"; }
}
Method {
+ name: "identifyAllApplications"
+ type: "QStringList"
+ Parameter { name: "pid"; type: "int"; }
+ }
+ Method {
name: "applicationRunState"
type: "RunState"
Parameter { name: "id"; type: "string"; }
diff --git a/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp b/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp
index c12ae788..5ad54940 100644
--- a/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp
+++ b/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp
@@ -206,6 +206,12 @@ QString ApplicationManagerAdaptor::identifyApplication(qlonglong pid)
return ApplicationManager::instance()->identifyApplication(pid);
}
+QStringList ApplicationManagerAdaptor::identifyAllApplications(qlonglong pid)
+{
+ AM_AUTHENTICATE_DBUS(QStringList)
+ return ApplicationManager::instance()->identifyAllApplications(pid);
+}
+
bool ApplicationManagerAdaptor::openUrl(const QString &url)
{
AM_AUTHENTICATE_DBUS(bool)
diff --git a/src/dbus-lib/dbuspolicy.cpp b/src/dbus-lib/dbuspolicy.cpp
index ef6214f6..43ed01b0 100644
--- a/src/dbus-lib/dbuspolicy.cpp
+++ b/src/dbus-lib/dbuspolicy.cpp
@@ -140,7 +140,11 @@ bool DBusPolicy::check(QDBusAbstractAdaptor *dbusAdaptor, const QByteArray &func
if (!ip->m_capabilities.isEmpty()) {
pid = dbusContext->connection().interface()->servicePid(dbusContext->message().service());
- QStringList appCaps = ApplicationManager::instance()->capabilities(ApplicationManager::instance()->identifyApplication(pid));
+ const auto apps = ApplicationManager::instance()->identifyAllApplications(pid);
+ if (apps.size() > 1)
+ throw "multiple apps per pid are not supported";
+ const QString appId = !apps.isEmpty() ? apps.constFirst() : QString();
+ QStringList appCaps = ApplicationManager::instance()->capabilities(appId);
bool match = false;
for (const QString &cap : ip->m_capabilities)
match = match && std::binary_search(appCaps.cbegin(), appCaps.cend(), cap);
diff --git a/src/dbus-lib/io.qt.applicationmanager.xml b/src/dbus-lib/io.qt.applicationmanager.xml
index 70ca1111..74294862 100644
--- a/src/dbus-lib/io.qt.applicationmanager.xml
+++ b/src/dbus-lib/io.qt.applicationmanager.xml
@@ -95,6 +95,10 @@
<arg type="s" direction="out"/>
<arg name="pid" type="x" direction="in"/>
</method>
+ <method name="identifyAllApplications">
+ <arg type="as" direction="out"/>
+ <arg name="pid" type="x" direction="in"/>
+ </method>
<method name="applicationRunState">
<arg type="u" direction="out"/>
<arg name="id" type="s" direction="in"/>
diff --git a/src/manager-lib/applicationmanager.cpp b/src/manager-lib/applicationmanager.cpp
index 58da711f..938333bb 100644
--- a/src/manager-lib/applicationmanager.cpp
+++ b/src/manager-lib/applicationmanager.cpp
@@ -515,19 +515,23 @@ Application *ApplicationManager::fromId(const QString &id) const
return nullptr;
}
-Application *ApplicationManager::fromProcessId(qint64 pid) const
+QVector<Application *> ApplicationManager::fromProcessId(qint64 pid) const
{
+ QVector<Application *> apps;
+
// pid could be an indirect child (e.g. when started via gdbserver)
qint64 appmanPid = QCoreApplication::applicationPid();
while ((pid > 1) && (pid != appmanPid)) {
for (Application *app : d->apps) {
+ if (apps.contains(app))
+ continue;
if (app->currentRuntime() && (app->currentRuntime()->applicationProcessId() == pid))
- return app;
+ apps.append(app);
}
pid = getParentPid(pid);
}
- return nullptr;
+ return apps;
}
Application *ApplicationManager::fromSecurityToken(const QByteArray &securityToken) const
@@ -1119,12 +1123,37 @@ QStringList ApplicationManager::capabilities(const QString &id) const
Validates the process running with process-identifier \a pid as a process started by the
application manager.
+ \note If multiple applications are running within the same container process, this function
+ will return only the first matching application. See identifyAllApplications() for
+ a way to retrieve all application ids.
+
Returns the application's \c id on success, or an empty string on failure.
*/
QString ApplicationManager::identifyApplication(qint64 pid) const
{
- Application *app = fromProcessId(pid);
- return app ? app->id() : QString();
+ const auto apps = fromProcessId(pid);
+ return !apps.isEmpty() ? apps.constFirst()->id() : QString();
+}
+
+/*!
+ \qmlmethod list<string> ApplicationManager::identifyAllApplications(int pid)
+
+ Validates the process running with process-identifier \a pid as a process started by the
+ application manager.
+
+ If multiple applications are running within the same container process, this function will
+ return all those application ids.
+
+ Returns a list with the applications' \c ids on success, or an empty list on failure.
+*/
+QStringList ApplicationManager::identifyAllApplications(qint64 pid) const
+{
+ const auto apps = fromProcessId(pid);
+ QStringList result;
+ result.reserve(apps.size());
+ for (const auto &app : apps)
+ result << app->id();
+ return result;
}
void ApplicationManager::shutDown()
diff --git a/src/manager-lib/applicationmanager.h b/src/manager-lib/applicationmanager.h
index d7d8f0fa..498f2ba5 100644
--- a/src/manager-lib/applicationmanager.h
+++ b/src/manager-lib/applicationmanager.h
@@ -102,7 +102,7 @@ public:
QVector<Application *> applications() const;
Application *fromId(const QString &id) const;
- Application *fromProcessId(qint64 pid) const;
+ QVector<Application *> fromProcessId(qint64 pid) const;
Application *fromSecurityToken(const QByteArray &securityToken) const;
QVector<Application *> schemeHandlers(const QString &scheme) const;
QVector<Application *> mimeTypeHandlers(const QString &mimeType) const;
@@ -151,6 +151,7 @@ public:
Q_SCRIPTABLE bool openUrl(const QString &url);
Q_SCRIPTABLE QStringList capabilities(const QString &id) const;
Q_SCRIPTABLE QString identifyApplication(qint64 pid) const;
+ Q_SCRIPTABLE QStringList identifyAllApplications(qint64 pid) const;
Q_SCRIPTABLE QT_PREPEND_NAMESPACE_AM(Am::RunState) applicationRunState(const QString &id) const;
ApplicationManagerInternalSignals internalSignals;
diff --git a/src/window-lib/waylandcompositor.cpp b/src/window-lib/waylandcompositor.cpp
index 45b2cbb7..8854089d 100644
--- a/src/window-lib/waylandcompositor.cpp
+++ b/src/window-lib/waylandcompositor.cpp
@@ -94,6 +94,13 @@ WaylandCompositor *WindowSurface::compositor() const
return m_compositor;
}
+QString WindowSurface::applicationId() const
+{
+ if (m_xdgSurface && m_xdgSurface->toplevel())
+ return m_xdgSurface->toplevel()->appId();
+ return { };
+}
+
bool WindowSurface::isPopup() const
{
return m_popup;
@@ -167,7 +174,7 @@ WaylandCompositor::WaylandCompositor(QQuickWindow *window, const QString &waylan
auto wmext = new QWaylandQtWindowManager(this);
connect(wmext, &QWaylandQtWindowManager::openUrl, this, [](QWaylandClient *client, const QUrl &url) {
- if (ApplicationManager::instance()->fromProcessId(client->processId()))
+ if (!ApplicationManager::instance()->fromProcessId(client->processId()).isEmpty())
ApplicationManager::instance()->openUrl(url.toString());
});
diff --git a/src/window-lib/waylandcompositor.h b/src/window-lib/waylandcompositor.h
index ddf0ab97..fdb8add9 100644
--- a/src/window-lib/waylandcompositor.h
+++ b/src/window-lib/waylandcompositor.h
@@ -90,6 +90,7 @@ public:
QWaylandWlShellSurface *shellSurface() const;
WaylandCompositor *compositor() const;
+ QString applicationId() const;
bool isPopup() const;
QRect popupGeometry() const;
void sendResizing(const QSize &size);
diff --git a/src/window-lib/windowmanager.cpp b/src/window-lib/windowmanager.cpp
index 0d8c7e9c..69201f01 100644
--- a/src/window-lib/windowmanager.cpp
+++ b/src/window-lib/windowmanager.cpp
@@ -808,11 +808,27 @@ void WindowManager::waylandSurfaceCreated(QWaylandSurface *surface)
void WindowManager::waylandSurfaceMapped(WindowSurface *surface)
{
qint64 processId = surface->processId();
- Application *app = ApplicationManager::instance()->fromProcessId(processId);
+ const auto apps = ApplicationManager::instance()->fromProcessId(processId);
+ Application *app = nullptr;
+
+ if (apps.size() == 1) {
+ app = apps.constFirst();
+ } else if (apps.size() > 1) {
+ // if there is more than one app within the same process, check the XDG surface appId
+ const QString xdgAppId = surface->applicationId();
+ if (!xdgAppId.isEmpty()) {
+ for (const auto &checkApp : apps) {
+ if (checkApp->id() == xdgAppId) {
+ app = checkApp;
+ break;
+ }
+ }
+ }
+ }
if (!app && ApplicationManager::instance()->securityChecksEnabled()) {
qCCritical(LogGraphics) << "SECURITY ALERT: an unknown application with pid" << processId
- << "tried to map a Wayland surface!";
+ << "tried to map a Wayland surface!";
return;
}