diff options
author | Robert Griebl <robert.griebl@qt.io> | 2022-05-11 20:51:08 +0200 |
---|---|---|
committer | Robert Griebl <robert.griebl@qt.io> | 2022-08-02 09:57:09 +0000 |
commit | 2f5e9e5b41505d944bfbc9ed6a47ed4a9156f603 (patch) | |
tree | eb06902c0b0939ea9c32c681a3d1fcefb2a6a98d | |
parent | 9669f87db08d0c2ce49146f65eea3c3db99f7904 (diff) | |
download | qtapplicationmanager-2f5e9e5b41505d944bfbc9ed6a47ed4a9156f603.tar.gz |
Fix DBus error handling when set to "auto"
Problem 1: A Qt plugin calls QDBusConnection::sessionBus() before we
fork off our own, private session bus. In this case, Qt caches the old
bus address and we try to register our objects on the wrong bus.
-> register on our own bus explicitly.
Problem 2: If "Problem 1" happened, every QML application would block
for 100 * ~25sec on startup, trying to call "Introspect" on the non-
existing Notification interface (on the wrong dbus). The delay loop
was written for the P2P case, which doesn't block in the QDBusInterface
constructor, resulting in a more reasonable 100 * 1msec timeout.
-> check if the service is available at all first and also check
for time-elapsed instead of trying 100 times.
Change-Id: I34ade2bee2da27753eda09b6c0f3562882f40bc3
Reviewed-by: Dominik Holland <dominik.holland@qt.io>
(cherry picked from commit 6ffa6c7fa98336be9edc83e06f0c9ddad3769550)
Reviewed-by: Bernd Weimer <bernd.weimer@qt.io>
-rw-r--r-- | src/launcher-lib/dbusapplicationinterface.cpp | 31 | ||||
-rw-r--r-- | src/main-lib/main.cpp | 5 |
2 files changed, 29 insertions, 7 deletions
diff --git a/src/launcher-lib/dbusapplicationinterface.cpp b/src/launcher-lib/dbusapplicationinterface.cpp index 735a92d4..c4b27528 100644 --- a/src/launcher-lib/dbusapplicationinterface.cpp +++ b/src/launcher-lib/dbusapplicationinterface.cpp @@ -30,6 +30,7 @@ ****************************************************************************/ #include <QDBusConnection> +#include <QDBusConnectionInterface> #include <QDBusInterface> #include <QDBusMessage> #include <QDBusReply> @@ -38,6 +39,7 @@ #include <QPointer> #include <QCoreApplication> #include <QThread> +#include <QElapsedTimer> #include "global.h" #include "dbusapplicationinterface.h" @@ -48,6 +50,10 @@ #include "intentclientrequest.h" #include "intentclientdbusimplementation.h" +#ifdef interface // in case windows.h got included somehow +# undef interface +#endif + QT_BEGIN_NAMESPACE_AM DBusApplicationInterface *DBusApplicationInterface::s_instance = nullptr; @@ -72,7 +78,16 @@ bool DBusApplicationInterface::initialize(bool hasRuntime) auto tryConnect = [](const QString &service, const QString &path, const QString &interfaceName, const QDBusConnection &conn, QObject *parent) -> QDBusInterface * { - for (int i = 0; i < 100; ++i) { + if (!service.isEmpty() && conn.interface()) { + if (!conn.interface()->isServiceRegistered(service)) + return nullptr; + } + + QElapsedTimer timer; + timer.start(); + + while (timer.elapsed() < (100 * timeout)) { // 100msec base line + // this constructor can block up to 25sec (!), if the service is not registered! QDBusInterface *iface = new QDBusInterface(service, path, interfaceName, conn, parent); if (!iface->lastError().isValid()) return iface; @@ -86,7 +101,7 @@ bool DBusApplicationInterface::initialize(bool hasRuntime) qSL("io.qt.ApplicationManager.ApplicationInterface"), m_connection, this); if (!m_applicationIf) { - qCritical("ERROR: could not connect to the ApplicationInterface on the P2P D-Bus"); + qCritical("ERROR: could not connect to the ApplicationInterface signals on the P2P D-Bus"); return false; } @@ -115,7 +130,7 @@ bool DBusApplicationInterface::initialize(bool hasRuntime) ok = connect(m_runtimeIf, SIGNAL(startApplication(QString,QString,QString,QString,QVariantMap,QVariantMap)), this, SIGNAL(startApplication(QString,QString,QString,QString,QVariantMap,QVariantMap))); if (!ok) { - qCritical("ERROR: could not connect the RuntimeInterface via D-Bus: %s", + qCritical("ERROR: could not connect the RuntimeInterface signals via D-Bus: %s", qPrintable(m_runtimeIf->lastError().name())); } } @@ -138,11 +153,15 @@ bool DBusApplicationInterface::initialize(bool hasRuntime) ok = ok && connect(m_notifyIf, SIGNAL(ActionInvoked(uint,QString)), this, SLOT(notificationActionTriggered(uint,QString))); - if (!ok) - qCritical("ERROR: could not connect the org.freedesktop.Notifications interface via D-Bus: %s", + if (!ok) { + qCritical("ERROR: could not connect the org.freedesktop.Notifications signals via D-Bus: %s", qPrintable(m_notifyIf->lastError().name())); + + delete m_notifyIf; + m_notifyIf = nullptr; + } } else { - qCritical("ERROR: could not create the org.freedesktop.Notifications interface on D-Bus"); + qCritical("ERROR: could not connect to the org.freedesktop.Notifications interface via D-Bus"); } } diff --git a/src/main-lib/main.cpp b/src/main-lib/main.cpp index ea003066..5b15aa15 100644 --- a/src/main-lib/main.cpp +++ b/src/main-lib/main.cpp @@ -852,7 +852,10 @@ void Main::registerDBusObject(QDBusAbstractAdaptor *adaptor, QString dbusName, c conn = QDBusConnection::sessionBus(); } else if (dbusName == qL1S("auto")) { dbusAddress = QString::fromLocal8Bit(qgetenv("DBUS_SESSION_BUS_ADDRESS")); - conn = QDBusConnection::sessionBus(); + // we cannot be using QDBusConnection::sessionBus() here, because some plugin + // might have called that function before we could spawn our own session bus. In + // this case, Qt has cached the bus name and we would get the old one back. + conn = QDBusConnection::connectToBus(dbusAddress, qSL("qtam_session")); if (!conn.isConnected()) return; dbusName = qL1S("session"); |