fix ghost devices in the udisks2 Solid backend

This commit is contained in:
Lukáš Tinkl 2012-12-03 17:31:16 +01:00
parent 8d3faf2202
commit 3966b2d0bd
2 changed files with 171 additions and 129 deletions

View File

@ -471,10 +471,10 @@ index 0000000..19cb70a
+#endif // UDISKS2BLOCK_H
diff --git a/solid/solid/backends/udisks2/udisksdevice.cpp b/solid/solid/backends/udisks2/udisksdevice.cpp
new file mode 100644
index 0000000..b888360
index 0000000..2a4313a
--- /dev/null
+++ b/solid/solid/backends/udisks2/udisksdevice.cpp
@@ -0,0 +1,834 @@
@@ -0,0 +1,833 @@
+/*
+ Copyright 2010 Michael Zanetti <mzanetti@kde.org>
+ Copyright 2010-2012 Lukáš Tinkl <ltinkl@redhat.com>
@ -581,7 +581,60 @@ index 0000000..b888360
+
+Device::~Device()
+{
+}
+
+QString Device::udi() const
+{
+ if (m_backend) {
+ return m_backend->udi();
+ }
+
+ return QString();
+}
+
+QVariant Device::prop(const QString &key) const
+{
+ if (m_backend) {
+ return m_backend->prop(key);
+ }
+
+ return QVariant();
+}
+
+bool Device::propertyExists(const QString &key) const
+{
+ if (m_backend) {
+ return m_backend->propertyExists(key);
+ }
+
+ return false;
+}
+
+QVariantMap Device::allProperties() const
+{
+ if (m_backend) {
+ return m_backend->allProperties();
+ }
+
+ return QVariantMap();
+}
+
+bool Device::hasInterface(const QString &name) const
+{
+ if (m_backend) {
+ return m_backend->interfaces().contains(name);
+ }
+
+ return false;
+}
+
+QStringList Device::interfaces() const
+{
+ if (m_backend) {
+ return m_backend->interfaces();
+ }
+
+ return QStringList();
+}
+
+QObject* Device::createDeviceInterface(const Solid::DeviceInterface::Type& type)
@ -1105,15 +1158,6 @@ index 0000000..b888360
+ return prop("Vendor").toString();
+}
+
+QString Device::udi() const
+{
+ if (m_backend) {
+ return m_backend->udi;
+ }
+
+ return QString();
+}
+
+QString Device::parentUdi() const
+{
+ QString parent;
@ -1128,51 +1172,6 @@ index 0000000..b888360
+ return parent;
+}
+
+QVariant Device::prop(const QString &key) const
+{
+ if (m_backend) {
+ return m_backend->prop(key);
+ }
+
+ return QVariant();
+}
+
+bool Device::propertyExists(const QString &key) const
+{
+ if (m_backend) {
+ return m_backend->propertyExists(key);
+ }
+
+ return false;
+}
+
+QVariantMap Device::allProperties() const
+{
+ if (m_backend) {
+ return m_backend->allProperties();
+ }
+
+ return QVariantMap();
+}
+
+bool Device::hasInterface(const QString &name) const
+{
+ if (m_backend) {
+ return m_backend->interfaces().contains(name);
+ }
+
+ return false;
+}
+
+QStringList Device::interfaces() const
+{
+ if (m_backend) {
+ return m_backend->interfaces();
+ }
+
+ return QStringList();
+}
+
+QString Device::errorToString(const QString & error) const
+{
+ if (error == UD2_ERROR_UNAUTHORIZED || error == UD2_ERROR_NOT_AUTHORIZED)
@ -1311,10 +1310,10 @@ index 0000000..b888360
+}
diff --git a/solid/solid/backends/udisks2/udisksdevice.h b/solid/solid/backends/udisks2/udisksdevice.h
new file mode 100644
index 0000000..90bb042
index 0000000..6038178
--- /dev/null
+++ b/solid/solid/backends/udisks2/udisksdevice.h
@@ -0,0 +1,103 @@
@@ -0,0 +1,104 @@
+/*
+ Copyright 2010 Michael Zanetti <mzanetti@kde.org>
+ Copyright 2010-2012 Lukáš Tinkl <ltinkl@redhat.com>
@ -1406,11 +1405,12 @@ index 0000000..90bb042
+ void changed();
+ void propertyChanged(const QMap<QString,int> &changes);
+
+protected:
+ QPointer<DeviceBackend> m_backend;
+
+private:
+ QString storageDescription() const;
+ QString volumeDescription() const;
+
+ DeviceBackend *m_backend;
+};
+
+}
@ -1420,10 +1420,10 @@ index 0000000..90bb042
+#endif // UDISKS2DEVICE_H
diff --git a/solid/solid/backends/udisks2/udisksdevicebackend.cpp b/solid/solid/backends/udisks2/udisksdevicebackend.cpp
new file mode 100644
index 0000000..ffa98db
index 0000000..8131cb5
--- /dev/null
+++ b/solid/solid/backends/udisks2/udisksdevicebackend.cpp
@@ -0,0 +1,205 @@
@@ -0,0 +1,239 @@
+/*
+ Copyright 2010 Michael Zanetti <mzanetti@kde.org>
+ Copyright 2010-2012 Lukáš Tinkl <ltinkl@redhat.com>
@ -1477,16 +1477,25 @@ index 0000000..ffa98db
+ return backend;
+}
+
+DeviceBackend::DeviceBackend(const QString& udi)
+ : udi(udi)
+void DeviceBackend::destroyBackend(const QString& udi)
+{
+ qDebug() << "Creating backend for device" << udi;
+ m_device = new QDBusInterface(UD2_DBUS_SERVICE, udi,
+ if (s_backends.contains(udi)) {
+ DeviceBackend *backend = s_backends.value(udi);
+ s_backends.remove(udi);
+ delete backend;
+ }
+}
+
+DeviceBackend::DeviceBackend(const QString& udi)
+ : m_udi(udi)
+{
+ qDebug() << "Creating backend for device" << m_udi;
+ m_device = new QDBusInterface(UD2_DBUS_SERVICE, m_udi,
+ QString(), // no interface, we aggregate them
+ QDBusConnection::systemBus(), this);
+
+ if (m_device->isValid()) {
+ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, udi, DBUS_INTERFACE_PROPS, "PropertiesChanged", this,
+ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, m_udi, DBUS_INTERFACE_PROPS, "PropertiesChanged", this,
+ SLOT(slotPropertiesChanged(QString,QVariantMap,QStringList)));
+ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, UD2_DBUS_PATH, DBUS_INTERFACE_MANAGER, "InterfacesAdded",
+ this, SLOT(slotInterfacesAdded(QDBusObjectPath,QVariantMapMap)));
@ -1499,20 +1508,33 @@ index 0000000..ffa98db
+
+DeviceBackend::~DeviceBackend()
+{
+ qDebug() << "Destroying backend for device" << m_udi;
+}
+
+void DeviceBackend::initInterfaces()
+{
+ m_interfaces.clear();
+
+ const QString xmlData = introspect();
+ if (xmlData.isEmpty()) {
+ qDebug() << m_udi << "has no interfaces!";
+ return;
+ }
+
+ QDomDocument dom;
+ dom.setContent(xmlData);
+
+ QDomNodeList ifaceNodeList = dom.elementsByTagName("interface");
+ for (int i = 0; i < ifaceNodeList.count(); i++) {
+ QDomElement ifaceElem = ifaceNodeList.item(i).toElement();
+ if (!ifaceElem.isNull())
+ /* Accept only org.freedesktop.UDisks2.* interfaces so that when the device is unplugged,
+ * m_interfaces goes empty and we can easily verify that the device is gone. */
+ if (!ifaceElem.isNull() && ifaceElem.attribute("name").startsWith(UD2_DBUS_SERVICE)) {
+ m_interfaces.append(ifaceElem.attribute("name"));
+ }
+ }
+
+ qDebug() << m_udi << "has interfaces:" << m_interfaces;
+}
+
+QStringList DeviceBackend::interfaces() const
@ -1520,42 +1542,30 @@ index 0000000..ffa98db
+ return m_interfaces;
+}
+
+
+QString DeviceBackend::introspect() const
+const QString& DeviceBackend::udi() const
+{
+ QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, udi,
+ DBUS_INTERFACE_INTROSPECT, "Introspect");
+ QDBusPendingReply<QString> reply = QDBusConnection::systemBus().call(call);
+
+ if (reply.isValid())
+ return reply.value();
+ else {
+ return QString();
+ }
+ return m_udi;
+}
+
+QVariant DeviceBackend::prop(const QString& key)
+QVariant DeviceBackend::prop(const QString& key) const
+{
+ checkCache(key);
+ return m_propertyCache.value(key);
+}
+
+bool DeviceBackend::propertyExists(const QString& key)
+bool DeviceBackend::propertyExists(const QString& key) const
+{
+ checkCache(key);
+ return m_propertyCache.contains(key);
+ /* checkCache() will put an invalid QVariant in cache when the property
+ * does not exist, so check for validity, not for an actual presence. */
+ return m_propertyCache.value(key).isValid();
+}
+
+
+QVariantMap DeviceBackend::allProperties() const
+{
+ QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, udi, DBUS_INTERFACE_PROPS, "GetAll");
+ QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, m_udi, DBUS_INTERFACE_PROPS, "GetAll");
+
+ Q_FOREACH (const QString & iface, m_interfaces) {
+ if (iface.startsWith("org.freedesktop.DBus")) {
+ continue;
+ }
+
+ call.setArguments(QVariantList() << iface);
+ QDBusPendingReply<QVariantMap> reply = QDBusConnection::systemBus().call(call);
+
@ -1570,6 +1580,19 @@ index 0000000..ffa98db
+ return m_propertyCache;
+}
+
+QString DeviceBackend::introspect() const
+{
+ QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, m_udi,
+ DBUS_INTERFACE_INTROSPECT, "Introspect");
+ QDBusPendingReply<QString> reply = QDBusConnection::systemBus().call(call);
+
+ if (reply.isValid())
+ return reply.value();
+ else {
+ return QString();
+ }
+}
+
+void DeviceBackend::checkCache(const QString& key) const
+{
+ if (m_propertyCache.isEmpty()) { // recreate the cache
@ -1581,17 +1604,19 @@ index 0000000..ffa98db
+ }
+
+ QVariant reply = m_device->property(key.toUtf8());
+ m_propertyCache.insert(key, reply);
+
+ if (reply.isValid()) {
+ m_propertyCache.insert(key, reply);
+ } else {
+ qWarning() << "got invalid reply for cache:" << key;
+ if (!reply.isValid()) {
+ /* Store the item in the cache anyway so next time we don't have to
+ * do the DBus call to find out it does not exist but just check whether
+ * prop(key).isValid() */
+ qDebug() << m_udi << ": property" << key << "does not exist";
+ }
+}
+
+void DeviceBackend::slotPropertiesChanged(const QString& ifaceName, const QVariantMap& changedProps, const QStringList& invalidatedProps)
+{
+ qDebug() << udi << "'s interface" << ifaceName << "changed props:";
+ qDebug() << m_udi << "'s interface" << ifaceName << "changed props:";
+
+ QMap<QString, int> changeMap;
+
@ -1616,25 +1641,34 @@ index 0000000..ffa98db
+
+void DeviceBackend::slotInterfacesAdded(const QDBusObjectPath& object_path, const QVariantMapMap& interfaces_and_properties)
+{
+ if (object_path.path() == udi) {
+ m_interfaces.append(interfaces_and_properties.keys());
+ if (object_path.path() != m_udi) {
+ return;
+ }
+
+ Q_FOREACH(const QString & iface, interfaces_and_properties.keys()) {
+ /* Don't store generic DBus interfaces */
+ if (iface.startsWith(UD2_DBUS_SERVICE)) {
+ m_interfaces.append(interfaces_and_properties.keys());
+ }
+ }
+}
+
+void DeviceBackend::slotInterfacesRemoved(const QDBusObjectPath& object_path, const QStringList& interfaces)
+{
+ if (object_path.path() == udi) {
+ Q_FOREACH(const QString & iface, interfaces) {
+ m_interfaces.removeAll(iface);
+ }
+ if (object_path.path() != m_udi) {
+ return;
+ }
+
+ Q_FOREACH(const QString & iface, interfaces) {
+ m_interfaces.removeAll(iface);
+ }
+}
diff --git a/solid/solid/backends/udisks2/udisksdevicebackend.h b/solid/solid/backends/udisks2/udisksdevicebackend.h
new file mode 100644
index 0000000..4953ad5
index 0000000..829fa41
--- /dev/null
+++ b/solid/solid/backends/udisks2/udisksdevicebackend.h
@@ -0,0 +1,83 @@
@@ -0,0 +1,84 @@
+/*
+ Copyright 2010 Michael Zanetti <mzanetti@kde.org>
+ Copyright 2010-2012 Lukáš Tinkl <ltinkl@redhat.com>
@ -1678,21 +1712,17 @@ index 0000000..4953ad5
+
+ public:
+ static DeviceBackend* backendForUDI(const QString &udi);
+ static void destroyBackend(const QString &udi);
+
+ DeviceBackend(const QString &udi);
+ ~DeviceBackend();
+
+ void initInterfaces();
+ QString introspect() const;
+
+ QVariant prop(const QString &key);
+ bool propertyExists(const QString &key);
+ QVariant prop(const QString &key) const;
+ bool propertyExists(const QString &key) const;
+ QVariantMap allProperties() const;
+ void checkCache(const QString &key) const;
+
+ QStringList interfaces() const;
+
+ QString udi;
+ const QString & udi() const;
+
+ Q_SIGNALS:
+ void propertyChanged(const QMap<QString, int> &changeMap);
@ -1704,10 +1734,15 @@ index 0000000..4953ad5
+ void slotPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps);
+
+ private:
+ void initInterfaces();
+ QString introspect() const;
+ void checkCache(const QString &key) const;
+
+ QDBusInterface *m_device;
+
+ mutable QVariantMap m_propertyCache;
+ QStringList m_interfaces;
+ QString m_udi;
+
+ static QMap<QString, DeviceBackend*> s_backends;
+
@ -2036,10 +2071,10 @@ index 0000000..d225f32
+#endif // SOLID_BACKENDS_UDISKS2_GENERICINTERFACE_H
diff --git a/solid/solid/backends/udisks2/udisksmanager.cpp b/solid/solid/backends/udisks2/udisksmanager.cpp
new file mode 100644
index 0000000..69e053f
index 0000000..35b0d23
--- /dev/null
+++ b/solid/solid/backends/udisks2/udisksmanager.cpp
@@ -0,0 +1,238 @@
@@ -0,0 +1,248 @@
+/*
+ Copyright 2012 Lukáš Tinkl <ltinkl@redhat.com>
+
@ -2061,6 +2096,7 @@ index 0000000..69e053f
+*/
+
+#include "udisksmanager.h"
+#include "udisksdevicebackend.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
@ -2118,7 +2154,10 @@ index 0000000..69e053f
+
+Manager::~Manager()
+{
+ QDBusConnection::systemBus().disconnectFromBus("Solid::UDisks2");
+ while (!m_deviceCache.isEmpty()) {
+ QString udi = m_deviceCache.takeFirst();
+ DeviceBackend::destroyBackend(udi);
+ }
+}
+
+QObject* Manager::createDevice(const QString& udi)
@ -2170,7 +2209,11 @@ index 0000000..69e053f
+
+QStringList Manager::allDevices()
+{
+ m_deviceCache.clear();
+ /* Clear the cache, destroy all backends */
+ while (!m_deviceCache.isEmpty()) {
+ QString udi= m_deviceCache.takeFirst();
+ DeviceBackend::destroyBackend(udi);
+ }
+
+ introspect("/org/freedesktop/UDisks2/block_devices", true /*checkOptical*/);
+ introspect("/org/freedesktop/UDisks2/drives");
@ -2245,6 +2288,7 @@ index 0000000..69e053f
+ if (!udi.isEmpty() && (interfaces.isEmpty() || device.interfaces().isEmpty() || device.interfaces().contains(UD2_DBUS_INTERFACE_FILESYSTEM))) {
+ Q_EMIT deviceRemoved(udi);
+ m_deviceCache.removeAll(udi);
+ DeviceBackend::destroyBackend(udi);
+ }
+}
+
@ -2267,6 +2311,7 @@ index 0000000..69e053f
+ if (m_deviceCache.contains(udi) && size == 0) { // we know the optdisc, got removed
+ Q_EMIT deviceRemoved(udi);
+ m_deviceCache.removeAll(udi);
+ DeviceBackend::destroyBackend(udi);
+ }
+}
+
@ -2734,7 +2779,7 @@ index 0000000..0cdcc66
+#endif // UDISKS2OPTICALDISC_H
diff --git a/solid/solid/backends/udisks2/udisksopticaldrive.cpp b/solid/solid/backends/udisks2/udisksopticaldrive.cpp
new file mode 100644
index 0000000..74a901e
index 0000000..4df18b1
--- /dev/null
+++ b/solid/solid/backends/udisks2/udisksopticaldrive.cpp
@@ -0,0 +1,226 @@
@ -2803,7 +2848,7 @@ index 0000000..74a901e
+ m_device->broadcastActionRequested("eject");
+
+ const QString path = m_device->udi();
+ QDBusConnection c = QDBusConnection::systemBus();
+ QDBusConnection c = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "Solid::Udisks2::OpticalDrive::" + path);
+
+ // if the device is mounted, unmount first
+ QString blockPath;
@ -3952,13 +3997,14 @@ index 0000000..2ca04d2
+
+#endif // UDISKS2STORAGEVOLUME_H
diff --git a/solid/solid/managerbase.cpp b/solid/solid/managerbase.cpp
index fb5a67c..c7005ff 100644
index fb5a67c..dc1700d 100644
--- a/solid/solid/managerbase.cpp
+++ b/solid/solid/managerbase.cpp
@@ -30,8 +30,11 @@
@@ -29,9 +29,11 @@
#if defined (Q_OS_MAC)
#include "backends/iokit/iokitmanager.h"
#elif defined (Q_OS_UNIX)
-#elif defined (Q_OS_UNIX)
-#include "backends/hal/halmanager.h"
+#if defined (WITH_SOLID_UDISKS2)
+#include "backends/udisks2/udisksmanager.h"
@ -3968,7 +4014,7 @@ index fb5a67c..c7005ff 100644
#include "backends/upower/upowermanager.h"
#if defined (HUPNP_FOUND)
@@ -71,22 +74,17 @@ void Solid::ManagerBasePrivate::loadBackends()
@@ -71,22 +73,17 @@ void Solid::ManagerBasePrivate::loadBackends()
# elif defined(Q_WS_WIN) && defined(HAVE_WBEM) && !defined(_WIN32_WCE)
m_backends << new Solid::Backends::Wmi::WmiManager(0);
@ -3995,20 +4041,15 @@ index fb5a67c..c7005ff 100644
# endif
# if defined (HUPNP_FOUND)
@@ -99,5 +97,3 @@ QList<QObject*> Solid::ManagerBasePrivate::managerBackends() const
{
return m_backends;
}
-
-
diff --git a/solid/tests/CMakeLists.txt b/solid/tests/CMakeLists.txt
index ef507d1..9212741 100644
index ef507d1..b9f3720 100644
--- a/solid/tests/CMakeLists.txt
+++ b/solid/tests/CMakeLists.txt
@@ -16,20 +16,6 @@ target_link_libraries(fakehardwaretest solid_static ${QT_QTCORE_LIBRARY} ${QT_QT
@@ -15,21 +15,6 @@ endif(WIN32)
target_link_libraries(fakehardwaretest solid_static ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTTEST_LIBRARY} )
add_definitions(-DTEST_DATA="\\"${CMAKE_CURRENT_SOURCE_DIR}/../solid/backends/fakehw/fakecomputer.xml\\"")
-
-########### halbasictest ###############
-
-if(NOT WIN32 AND NOT APPLE)

View File

@ -596,8 +596,9 @@ rm -rf %{buildroot}
%changelog
* Mon Dec 03 2012 Than Ngo <than@redhat.com> - 4.9.4-1
* Mon Dec 03 2012 Than Ngo <than@redhat.com> - 6:4.9.4-1
- 4.9.4
- update udisks2 backend patch to fix ghost devices
* Fri Nov 30 2012 Dan Vrátil <dvratil@redhat.com> - 6:4.9.3-7
- update udisks2 backend patch