on xenial help sign in
Fix timing of DBus registrations to avoid a race
f4fcd19Michael Terry
plugins/LightDM/Greeter.cpp+21
@@ -16,9 +16,17 @@
16 * Author: Michael Terry <michael.terry@canonical.com>
16 * Author: Michael Terry <michael.terry@canonical.com>
17 */
17 */
18
18
19+#include "DBusGreeter.h"
20+#include "DBusGreeterList.h"
19#include "Greeter.h"
21#include "Greeter.h"
20#include <libintl.h>
22#include <libintl.h>
21#include <QLightDM/Greeter>
23#include <QLightDM/Greeter>
24+#include <QTimer>
25+
26+static const char* GREETER_DBUS_PATH = "/";
27+static const char* GREETER_LIST_DBUS_PATH = "/list";
28+static const char* GREETER_DBUS_SERVICE = "com.canonical.UnityGreeter";
29+
22
30
23class GreeterPrivate
31class GreeterPrivate
24{
32{
@@ -61,6 +69,9 @@ Greeter::Greeter(QObject* parent)
61 this, SLOT(authenticationCompleteFilter()));
69 this, SLOT(authenticationCompleteFilter()));
62
70
63 d->m_greeter->connectSync();
71 d->m_greeter->connectSync();
72+
73+ // Use a zero-timer to let Qml finish loading before we announce on DBus
74+ QTimer::singleShot(0, this, SLOT(registerDBus()));
64}
75}
65
76
66bool Greeter::isActive() const
77bool Greeter::isActive() const
@@ -154,3 +165,13 @@ void Greeter::authenticationCompleteFilter()
154 Q_EMIT isAuthenticatedChanged();
165 Q_EMIT isAuthenticatedChanged();
155 Q_EMIT authenticationComplete();
166 Q_EMIT authenticationComplete();
156}
167}
168+
169+void Greeter::registerDBus()
170+{
171+ QDBusConnection connection = QDBusConnection::sessionBus();
172+ DBusGreeter *root = new DBusGreeter(this, connection, GREETER_DBUS_PATH);
173+ connection.registerObject(GREETER_DBUS_PATH, root, QDBusConnection::ExportScriptableContents);
174+ DBusGreeterList *list = new DBusGreeterList(this, connection, GREETER_LIST_DBUS_PATH);
175+ connection.registerObject(GREETER_LIST_DBUS_PATH, list, QDBusConnection::ExportScriptableContents);
176+ connection.registerService(GREETER_DBUS_SERVICE);
177+}
plugins/LightDM/Greeter.h+1
@@ -77,6 +77,7 @@ private Q_SLOTS:
77 void showMessageFilter(const QString &text, QLightDM::Greeter::MessageType type);
77 void showMessageFilter(const QString &text, QLightDM::Greeter::MessageType type);
78 void showPromptFilter(const QString &text, QLightDM::Greeter::PromptType type);
78 void showPromptFilter(const QString &text, QLightDM::Greeter::PromptType type);
79 void authenticationCompleteFilter();
79 void authenticationCompleteFilter();
80+ void registerDBus();
80};
81};
81
82
82#endif
83#endif
plugins/LightDM/plugin.cpp+1−15
@@ -18,8 +18,6 @@
18 */
18 */
19
19
20#include "plugin.h"
20#include "plugin.h"
21−#include "DBusGreeter.h"
22−#include "DBusGreeterList.h"
23#include "Greeter.h"
21#include "Greeter.h"
24#include "UsersModel.h"
22#include "UsersModel.h"
25#include <libusermetricsoutput/ColorTheme.h>
23#include <libusermetricsoutput/ColorTheme.h>
@@ -30,23 +28,11 @@
30#include <QDBusConnection>
28#include <QDBusConnection>
31#include <QtQml/qqml.h>
29#include <QtQml/qqml.h>
32
30
33−static const char* GREETER_LIST_DBUS_PATH = "/list";
34−static const char* GREETER_DBUS_SERVICE = "com.canonical.UnityGreeter";
35−
36static QObject *greeter_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
31static QObject *greeter_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
37{
32{
38 Q_UNUSED(engine)
33 Q_UNUSED(engine)
39 Q_UNUSED(scriptEngine)
34 Q_UNUSED(scriptEngine)
40−
41− Greeter *greeter = new Greeter();
42− QDBusConnection connection = QDBusConnection::sessionBus();
43− DBusGreeter *root = new DBusGreeter(greeter, connection, "/");
44− connection.registerObject("/", root, QDBusConnection::ExportScriptableContents);
45− DBusGreeterList *list = new DBusGreeterList(greeter, connection, GREETER_LIST_DBUS_PATH);
46− connection.registerObject(GREETER_LIST_DBUS_PATH, list, QDBusConnection::ExportScriptableContents);
47− connection.registerService(GREETER_DBUS_SERVICE);
48−
49− return greeter;
35+ return new Greeter();
50}
36}
51
37
52static QObject *users_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
38static QObject *users_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.cpp+11−4
@@ -19,14 +19,13 @@
19#include <QDBusConnection>
19#include <QDBusConnection>
20#include <QDBusInterface>
20#include <QDBusInterface>
21#include <QDebug>
21#include <QDebug>
22+#include <QTimer>
22
23
23DBusDashCommunicatorService::DBusDashCommunicatorService(QObject *parent):
24DBusDashCommunicatorService::DBusDashCommunicatorService(QObject *parent):
24 QObject(parent)
25 QObject(parent)
25{
26{
26− QDBusConnection connection = QDBusConnection::sessionBus();
27+ // Use a zero-timer to let Qml finish loading before we announce on DBus
27−
28+ QTimer::singleShot(0, this, SLOT(registerDBus()));
28− connection.registerService("com.canonical.UnityDash");
29− connection.registerObject("/com/canonical/UnityDash", this, QDBusConnection::ExportScriptableSlots);
30}
29}
31
30
32DBusDashCommunicatorService::~DBusDashCommunicatorService()
31DBusDashCommunicatorService::~DBusDashCommunicatorService()
@@ -37,3 +36,11 @@ void DBusDashCommunicatorService::SetCurrentScope(const QString &scopeId, bool a
37{
36{
38 Q_EMIT setCurrentScopeRequested(scopeId, animate, isSwipe);
37 Q_EMIT setCurrentScopeRequested(scopeId, animate, isSwipe);
39}
38}
39+
40+void DBusDashCommunicatorService::registerDBus()
41+{
42+ QDBusConnection connection = QDBusConnection::sessionBus();
43+
44+ connection.registerService("com.canonical.UnityDash");
45+ connection.registerObject("/com/canonical/UnityDash", this, QDBusConnection::ExportScriptableSlots);
46+}
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.h+2
@@ -34,6 +34,8 @@ Q_SIGNALS:
34public Q_SLOTS:
34public Q_SLOTS:
35 Q_SCRIPTABLE void SetCurrentScope(const QString &scopeId, bool animate, bool isSwipe);
35 Q_SCRIPTABLE void SetCurrentScope(const QString &scopeId, bool animate, bool isSwipe);
36
36
37+private Q_SLOTS:
38+ void registerDBus();
37};
39};
38
40
39#endif // DBUSUNITYSESSIONSERVICE_H
41#endif // DBUSUNITYSESSIONSERVICE_H
plugins/Unity/Launcher/dbusinterface.cpp+15−8
@@ -25,19 +25,14 @@
25#include <QDBusConnection>
25#include <QDBusConnection>
26#include <QDBusMessage>
26#include <QDBusMessage>
27#include <QDebug>
27#include <QDebug>
28+#include <QTimer>
28
29
29DBusInterface::DBusInterface(LauncherModel *parent):
30DBusInterface::DBusInterface(LauncherModel *parent):
30 QDBusVirtualObject(parent),
31 QDBusVirtualObject(parent),
31 m_launcherModel(parent)
32 m_launcherModel(parent)
32{
33{
33− /* Set up ourselves on DBus */
34+ // Use a zero-timer to let Qml finish loading before we announce on DBus
34− QDBusConnection con = QDBusConnection::sessionBus();
35+ QTimer::singleShot(0, this, SLOT(registerDBus()));
35− if (!con.registerService("com.canonical.Unity.Launcher")) {
36− qWarning() << "Unable to register launcher name";
37− }
38− if (!con.registerVirtualObject("/com/canonical/Unity/Launcher", this, QDBusConnection::VirtualObjectRegisterOption::SubPath)) {
39− qWarning() << "Unable to register launcher object";
40− }
41}
36}
42
37
43DBusInterface::~DBusInterface()
38DBusInterface::~DBusInterface()
@@ -230,3 +225,15 @@ void DBusInterface::emitPropChangedDbus(const QString& appId, const QString& pro
230 QDBusConnection con = QDBusConnection::sessionBus();
225 QDBusConnection con = QDBusConnection::sessionBus();
231 con.send(message);
226 con.send(message);
232}
227}
228+
229+void DBusInterface::registerDBus()
230+{
231+ /* Set up ourselves on DBus */
232+ QDBusConnection con = QDBusConnection::sessionBus();
233+ if (!con.registerService("com.canonical.Unity.Launcher")) {
234+ qWarning() << "Unable to register launcher name";
235+ }
236+ if (!con.registerVirtualObject("/com/canonical/Unity/Launcher", this, QDBusConnection::VirtualObjectRegisterOption::SubPath)) {
237+ qWarning() << "Unable to register launcher object";
238+ }
239+}
plugins/Unity/Launcher/dbusinterface.h+2
@@ -47,4 +47,6 @@ private:
47
47
48 LauncherModel *m_launcherModel;
48 LauncherModel *m_launcherModel;
49
49
50+private Q_SLOTS:
51+ void registerDBus();
50};
52};
plugins/Unity/Session/dbusunitysessionservice.cpp+14−7
@@ -20,16 +20,12 @@
20// Qt
20// Qt
21#include <QDBusConnection>
21#include <QDBusConnection>
22#include <QDBusInterface>
22#include <QDBusInterface>
23+#include <QTimer>
23
24
24DBusUnitySessionService::DBusUnitySessionService() : QObject()
25DBusUnitySessionService::DBusUnitySessionService() : QObject()
25{
26{
26− QDBusConnection connection = QDBusConnection::sessionBus();
27+ // Use a zero-timer to let Qml finish loading before we announce on DBus
27−
28+ QTimer::singleShot(0, this, SLOT(registerDBus()));
28− connection.registerService("com.canonical.Unity");
29− connection.registerObject("/com/canonical/Unity/Session", this,
30− QDBusConnection::ExportScriptableSignals
31− | QDBusConnection::ExportScriptableSlots
32− | QDBusConnection::ExportScriptableInvokables);
33}
29}
34
30
35DBusUnitySessionService::~DBusUnitySessionService()
31DBusUnitySessionService::~DBusUnitySessionService()
@@ -77,3 +73,14 @@ void DBusUnitySessionService::RequestShutdown()
77{
73{
78 Q_EMIT shutdownRequested(false);
74 Q_EMIT shutdownRequested(false);
79}
75}
76+
77+void DBusUnitySessionService::registerDBus()
78+{
79+ QDBusConnection connection = QDBusConnection::sessionBus();
80+
81+ connection.registerService("com.canonical.Unity");
82+ connection.registerObject("/com/canonical/Unity/Session", this,
83+ QDBusConnection::ExportScriptableSignals
84+ | QDBusConnection::ExportScriptableSlots
85+ | QDBusConnection::ExportScriptableInvokables);
86+}
plugins/Unity/Session/dbusunitysessionservice.h+2
@@ -134,6 +134,8 @@ public Q_SLOTS:
134 */
134 */
135 Q_SCRIPTABLE void RequestShutdown();
135 Q_SCRIPTABLE void RequestShutdown();
136
136
137+private Q_SLOTS:
138+ void registerDBus();
137};
139};
138
140
139#endif // DBUSUNITYSESSIONSERVICE_H
141#endif // DBUSUNITYSESSIONSERVICE_H
tests/plugins/LightDM/CMakeLists.txt+2
@@ -1,5 +1,7 @@
1add_executable(test-lightdm-dbus
1add_executable(test-lightdm-dbus
2 dbus.cpp
2 dbus.cpp
3+ ${CMAKE_SOURCE_DIR}/plugins/LightDM/DBusGreeter.cpp
4+ ${CMAKE_SOURCE_DIR}/plugins/LightDM/DBusGreeterList.cpp
3 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
5 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
4 )
6 )
5qt5_use_modules(test-lightdm-dbus Core DBus Quick Test)
7qt5_use_modules(test-lightdm-dbus Core DBus Quick Test)
tests/plugins/Unity/Launcher/launchermodeltest.cpp+1
@@ -124,6 +124,7 @@ private Q_SLOTS:
124
124
125 void initTestCase() {
125 void initTestCase() {
126 launcherModel = new LauncherModel(this);
126 launcherModel = new LauncherModel(this);
127+ QCoreApplication::processEvents(); // to let the model register on DBus
127 QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
128 QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
128
129
129 appManager = new MockAppManager(this);
130 appManager = new MockAppManager(this);
tests/plugins/Unity/Session/sessionbackendtest.cpp+1
@@ -45,6 +45,7 @@ private Q_SLOTS:
45 QFETCH(QString, method);
45 QFETCH(QString, method);
46
46
47 DBusUnitySessionService dbusUnitySessionService;
47 DBusUnitySessionService dbusUnitySessionService;
48+ QCoreApplication::processEvents(); // to let the service register on DBus
48
49
49 QDBusConnection con = QDBusConnection::sessionBus();
50 QDBusConnection con = QDBusConnection::sessionBus();
50 QDBusInterface interface ("com.canonical.Unity",
51 QDBusInterface interface ("com.canonical.Unity",