File indexing completed on 2024-12-01 12:29:49
0001 /* 0002 * BluezQt - Asynchronous Bluez wrapper library 0003 * 0004 * SPDX-FileCopyrightText: 2014-2015 David Rosca <nowrep@gmail.com> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "manager_p.h" 0010 #include "adapter.h" 0011 #include "adapter_p.h" 0012 #include "debug.h" 0013 #include "device.h" 0014 #include "device_p.h" 0015 #include "manager.h" 0016 #include "utils.h" 0017 0018 #include <QDBusServiceWatcher> 0019 0020 namespace BluezQt 0021 { 0022 ManagerPrivate::ManagerPrivate(Manager *parent) 0023 : QObject(parent) 0024 , q(parent) 0025 , m_dbusObjectManager(nullptr) 0026 , m_bluezAgentManager(nullptr) 0027 , m_bluezProfileManager(nullptr) 0028 , m_initialized(false) 0029 , m_bluezRunning(false) 0030 , m_loaded(false) 0031 , m_adaptersLoaded(false) 0032 { 0033 qDBusRegisterMetaType<DBusManagerStruct>(); 0034 qDBusRegisterMetaType<QVariantMapMap>(); 0035 0036 m_rfkill = new Rfkill(this); 0037 m_bluetoothBlocked = rfkillBlocked(); 0038 connect(m_rfkill, &Rfkill::stateChanged, this, &ManagerPrivate::rfkillStateChanged); 0039 0040 connect(q, &Manager::adapterRemoved, this, &ManagerPrivate::adapterRemoved); 0041 } 0042 0043 void ManagerPrivate::init() 0044 { 0045 // Keep an eye on org.bluez service 0046 QDBusServiceWatcher *serviceWatcher = new QDBusServiceWatcher(Strings::orgBluez(), 0047 DBusConnection::orgBluez(), 0048 QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration, 0049 this); 0050 0051 connect(serviceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &ManagerPrivate::serviceRegistered); 0052 connect(serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &ManagerPrivate::serviceUnregistered); 0053 0054 // Update the current state of org.bluez service 0055 if (!DBusConnection::orgBluez().isConnected()) { 0056 Q_EMIT initError(QStringLiteral("DBus system bus is not connected!")); 0057 return; 0058 } 0059 0060 QDBusMessage call = 0061 QDBusMessage::createMethodCall(Strings::orgFreedesktopDBus(), QStringLiteral("/"), Strings::orgFreedesktopDBus(), QStringLiteral("NameHasOwner")); 0062 0063 call << Strings::orgBluez(); 0064 0065 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(DBusConnection::orgBluez().asyncCall(call)); 0066 connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerPrivate::nameHasOwnerFinished); 0067 0068 DBusConnection::orgBluez().connect(Strings::orgBluez(), 0069 QString(), 0070 Strings::orgFreedesktopDBusProperties(), 0071 QStringLiteral("PropertiesChanged"), 0072 this, 0073 SLOT(propertiesChanged(QString, QVariantMap, QStringList))); 0074 } 0075 0076 void ManagerPrivate::nameHasOwnerFinished(QDBusPendingCallWatcher *watcher) 0077 { 0078 const QDBusPendingReply<bool> &reply = *watcher; 0079 watcher->deleteLater(); 0080 0081 if (reply.isError()) { 0082 Q_EMIT initError(reply.error().message()); 0083 return; 0084 } 0085 0086 m_bluezRunning = reply.value(); 0087 0088 if (m_bluezRunning) { 0089 load(); 0090 } else { 0091 m_initialized = true; 0092 Q_EMIT initFinished(); 0093 } 0094 } 0095 0096 void ManagerPrivate::load() 0097 { 0098 if (!m_bluezRunning || m_loaded) { 0099 return; 0100 } 0101 0102 // Force QDBus to cache owner of org.bluez - this will be the only blocking call on system connection 0103 DBusConnection::orgBluez().connect(Strings::orgBluez(), QStringLiteral("/"), Strings::orgFreedesktopDBus(), QStringLiteral("Dummy"), this, SLOT(dummy())); 0104 0105 m_dbusObjectManager = new DBusObjectManager(Strings::orgBluez(), QStringLiteral("/"), DBusConnection::orgBluez(), this); 0106 0107 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(m_dbusObjectManager->GetManagedObjects(), this); 0108 connect(watcher, &QDBusPendingCallWatcher::finished, this, &ManagerPrivate::getManagedObjectsFinished); 0109 } 0110 0111 void ManagerPrivate::getManagedObjectsFinished(QDBusPendingCallWatcher *watcher) 0112 { 0113 const QDBusPendingReply<DBusManagerStruct> &reply = *watcher; 0114 watcher->deleteLater(); 0115 0116 if (reply.isError()) { 0117 Q_EMIT initError(reply.error().message()); 0118 return; 0119 } 0120 0121 DBusManagerStruct::const_iterator it; 0122 const DBusManagerStruct &managedObjects = reply.value(); 0123 0124 for (it = managedObjects.constBegin(); it != managedObjects.constEnd(); ++it) { 0125 const QString &path = it.key().path(); 0126 const QVariantMapMap &interfaces = it.value(); 0127 0128 interfacesAdded(it.key(), interfaces); 0129 0130 if (interfaces.contains(Strings::orgBluezAgentManager1())) { 0131 m_bluezAgentManager = new BluezAgentManager(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); 0132 } 0133 if (interfaces.contains(Strings::orgBluezProfileManager1())) { 0134 m_bluezProfileManager = new BluezProfileManager(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); 0135 } 0136 } 0137 0138 if (!m_bluezAgentManager) { 0139 Q_EMIT initError(QStringLiteral("Cannot find org.bluez.AgentManager1 object!")); 0140 return; 0141 } 0142 0143 if (!m_bluezProfileManager) { 0144 Q_EMIT initError(QStringLiteral("Cannot find org.bluez.ProfileManager1 object!")); 0145 return; 0146 } 0147 0148 connect(m_dbusObjectManager, &DBusObjectManager::InterfacesAdded, this, &ManagerPrivate::interfacesAdded); 0149 connect(m_dbusObjectManager, &DBusObjectManager::InterfacesRemoved, this, &ManagerPrivate::interfacesRemoved); 0150 0151 m_loaded = true; 0152 m_initialized = true; 0153 0154 Q_EMIT q->operationalChanged(true); 0155 0156 if (q->isBluetoothOperational()) { 0157 Q_EMIT q->bluetoothOperationalChanged(true); 0158 } 0159 0160 Q_EMIT initFinished(); 0161 } 0162 0163 void ManagerPrivate::clear() 0164 { 0165 m_loaded = false; 0166 0167 // Delete all devices first 0168 while (!m_devices.isEmpty()) { 0169 DevicePtr device = m_devices.begin().value(); 0170 m_devices.remove(m_devices.begin().key()); 0171 device->adapter()->d->removeDevice(device); 0172 } 0173 0174 // Delete all adapters 0175 while (!m_adapters.isEmpty()) { 0176 AdapterPtr adapter = m_adapters.begin().value(); 0177 m_adapters.remove(m_adapters.begin().key()); 0178 Q_EMIT adapter->adapterRemoved(adapter); 0179 0180 if (m_adapters.isEmpty()) { 0181 Q_EMIT q->allAdaptersRemoved(); 0182 } 0183 } 0184 0185 // Delete all other objects 0186 m_usableAdapter.clear(); 0187 0188 if (m_dbusObjectManager) { 0189 m_dbusObjectManager->deleteLater(); 0190 m_dbusObjectManager = nullptr; 0191 } 0192 0193 if (m_bluezAgentManager) { 0194 m_bluezAgentManager->deleteLater(); 0195 m_bluezAgentManager = nullptr; 0196 } 0197 } 0198 0199 AdapterPtr ManagerPrivate::findUsableAdapter() const 0200 { 0201 for (AdapterPtr adapter : std::as_const(m_adapters)) { 0202 if (adapter->isPowered()) { 0203 return adapter; 0204 } 0205 } 0206 return AdapterPtr(); 0207 } 0208 0209 void ManagerPrivate::serviceRegistered() 0210 { 0211 qCDebug(BLUEZQT) << "BlueZ service registered"; 0212 m_bluezRunning = true; 0213 0214 load(); 0215 } 0216 0217 void ManagerPrivate::serviceUnregistered() 0218 { 0219 qCDebug(BLUEZQT) << "BlueZ service unregistered"; 0220 0221 bool wasBtOperational = q->isBluetoothOperational(); 0222 m_bluezRunning = false; 0223 0224 if (wasBtOperational) { 0225 Q_EMIT q->bluetoothOperationalChanged(false); 0226 } 0227 0228 clear(); 0229 Q_EMIT q->operationalChanged(false); 0230 } 0231 0232 void ManagerPrivate::interfacesAdded(const QDBusObjectPath &objectPath, const QVariantMapMap &interfaces) 0233 { 0234 const QString &path = objectPath.path(); 0235 QVariantMapMap::const_iterator it; 0236 0237 for (it = interfaces.constBegin(); it != interfaces.constEnd(); ++it) { 0238 if (it.key() == Strings::orgBluezAdapter1()) { 0239 addAdapter(path, it.value()); 0240 } else if (it.key() == Strings::orgBluezDevice1()) { 0241 addDevice(path, it.value()); 0242 } 0243 } 0244 0245 for (auto it = m_adapters.cbegin(); it != m_adapters.cend(); ++it) { 0246 if (path.startsWith(it.value()->ubi())) { 0247 it.value()->d->interfacesAdded(path, interfaces); 0248 break; 0249 } 0250 } 0251 0252 for (auto it = m_devices.cbegin(); it != m_devices.cend(); ++it) { 0253 if (path.startsWith(it.value()->ubi())) { 0254 it.value()->d->interfacesAdded(path, interfaces); 0255 break; 0256 } 0257 } 0258 } 0259 0260 void ManagerPrivate::interfacesRemoved(const QDBusObjectPath &objectPath, const QStringList &interfaces) 0261 { 0262 const QString &path = objectPath.path(); 0263 0264 for (const QString &interface : interfaces) { 0265 if (interface == Strings::orgBluezAdapter1()) { 0266 removeAdapter(path); 0267 } else if (interface == Strings::orgBluezDevice1()) { 0268 removeDevice(path); 0269 } 0270 } 0271 0272 for (auto it = m_adapters.cbegin(); it != m_adapters.cend(); ++it) { 0273 if (path.startsWith(it.value()->ubi())) { 0274 it.value()->d->interfacesRemoved(path, interfaces); 0275 break; 0276 } 0277 } 0278 0279 for (auto it = m_devices.cbegin(); it != m_devices.cend(); ++it) { 0280 if (path.startsWith(it.value()->ubi())) { 0281 it.value()->d->interfacesRemoved(path, interfaces); 0282 break; 0283 } 0284 } 0285 } 0286 0287 void ManagerPrivate::adapterRemoved(const AdapterPtr &adapter) 0288 { 0289 disconnect(adapter.data(), &Adapter::poweredChanged, this, &ManagerPrivate::adapterPoweredChanged); 0290 0291 // Current usable adapter was removed 0292 if (adapter == m_usableAdapter) { 0293 setUsableAdapter(findUsableAdapter()); 0294 } 0295 } 0296 0297 void ManagerPrivate::adapterPoweredChanged(bool powered) 0298 { 0299 Q_ASSERT(qobject_cast<Adapter *>(sender())); 0300 AdapterPtr adapter = static_cast<Adapter *>(sender())->toSharedPtr(); 0301 0302 // Current usable adapter was powered off 0303 if (m_usableAdapter == adapter && !powered) { 0304 setUsableAdapter(findUsableAdapter()); 0305 } 0306 0307 // Adapter was powered on, set it as usable 0308 if (!m_usableAdapter && powered) { 0309 setUsableAdapter(adapter); 0310 } 0311 } 0312 0313 void ManagerPrivate::rfkillStateChanged(Rfkill::State state) 0314 { 0315 Q_UNUSED(state) 0316 0317 bool blocked = rfkillBlocked(); 0318 bool wasBtOperational = q->isBluetoothOperational(); 0319 0320 if (m_bluetoothBlocked != blocked) { 0321 m_bluetoothBlocked = blocked; 0322 Q_EMIT q->bluetoothBlockedChanged(m_bluetoothBlocked); 0323 if (wasBtOperational != q->isBluetoothOperational()) { 0324 Q_EMIT q->bluetoothOperationalChanged(q->isBluetoothOperational()); 0325 } 0326 } 0327 } 0328 0329 void ManagerPrivate::addAdapter(const QString &adapterPath, const QVariantMap &properties) 0330 { 0331 AdapterPtr adapter = AdapterPtr(new Adapter(adapterPath, properties)); 0332 adapter->d->q = adapter.toWeakRef(); 0333 m_adapters.insert(adapterPath, adapter); 0334 0335 Q_EMIT q->adapterAdded(adapter); 0336 0337 // Powered adapter was added, set it as usable 0338 if (!m_usableAdapter && adapter->isPowered()) { 0339 setUsableAdapter(adapter); 0340 } 0341 0342 connect(adapter.data(), &Adapter::deviceAdded, q, &Manager::deviceAdded); 0343 connect(adapter.data(), &Adapter::adapterRemoved, q, &Manager::adapterRemoved); 0344 connect(adapter.data(), &Adapter::adapterChanged, q, &Manager::adapterChanged); 0345 connect(adapter.data(), &Adapter::poweredChanged, this, &ManagerPrivate::adapterPoweredChanged); 0346 } 0347 0348 void ManagerPrivate::addDevice(const QString &devicePath, const QVariantMap &properties) 0349 { 0350 AdapterPtr adapter = m_adapters.value(properties.value(QStringLiteral("Adapter")).value<QDBusObjectPath>().path()); 0351 if (!adapter) { 0352 return; 0353 } 0354 0355 DevicePtr device = DevicePtr(new Device(devicePath, properties, adapter)); 0356 device->d->q = device.toWeakRef(); 0357 m_devices.insert(devicePath, device); 0358 adapter->d->addDevice(device); 0359 0360 connect(device.data(), &Device::deviceRemoved, q, &Manager::deviceRemoved); 0361 connect(device.data(), &Device::deviceChanged, q, &Manager::deviceChanged); 0362 } 0363 0364 void ManagerPrivate::removeAdapter(const QString &adapterPath) 0365 { 0366 AdapterPtr adapter = m_adapters.value(adapterPath); 0367 if (!adapter) { 0368 return; 0369 } 0370 0371 // Make sure we always remove all devices before removing the adapter 0372 const auto devices = adapter->devices(); 0373 for (const DevicePtr &device : devices) { 0374 removeDevice(device->ubi()); 0375 } 0376 0377 m_adapters.remove(adapterPath); 0378 Q_EMIT adapter->adapterRemoved(adapter); 0379 0380 if (m_adapters.isEmpty()) { 0381 Q_EMIT q->allAdaptersRemoved(); 0382 } 0383 0384 disconnect(adapter.data(), &Adapter::adapterChanged, q, &Manager::adapterChanged); 0385 disconnect(adapter.data(), &Adapter::poweredChanged, this, &ManagerPrivate::adapterPoweredChanged); 0386 } 0387 0388 void ManagerPrivate::removeDevice(const QString &devicePath) 0389 { 0390 DevicePtr device = m_devices.take(devicePath); 0391 if (!device) { 0392 return; 0393 } 0394 0395 device->adapter()->d->removeDevice(device); 0396 0397 disconnect(device.data(), &Device::deviceChanged, q, &Manager::deviceChanged); 0398 } 0399 0400 bool ManagerPrivate::rfkillBlocked() const 0401 { 0402 return m_rfkill->state() == Rfkill::SoftBlocked || m_rfkill->state() == Rfkill::HardBlocked; 0403 } 0404 0405 void ManagerPrivate::setUsableAdapter(const AdapterPtr &adapter) 0406 { 0407 if (m_usableAdapter == adapter) { 0408 return; 0409 } 0410 0411 qCDebug(BLUEZQT) << "Setting usable adapter" << adapter; 0412 0413 bool wasBtOperational = q->isBluetoothOperational(); 0414 0415 m_usableAdapter = adapter; 0416 Q_EMIT q->usableAdapterChanged(m_usableAdapter); 0417 0418 if (wasBtOperational != q->isBluetoothOperational()) { 0419 Q_EMIT q->bluetoothOperationalChanged(q->isBluetoothOperational()); 0420 } 0421 } 0422 0423 void ManagerPrivate::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated) 0424 { 0425 // Cut anything after device path to forward it to Device to handle 0426 const QString path_full = message().path(); 0427 const QString path_device = path_full.section(QLatin1Char('/'), 0, 4); 0428 0429 QTimer::singleShot(0, this, [=]() { 0430 AdapterPtr adapter = m_adapters.value(path_device); 0431 if (adapter) { 0432 adapter->d->propertiesChanged(interface, changed, invalidated); 0433 return; 0434 } 0435 DevicePtr device = m_devices.value(path_device); 0436 if (device) { 0437 device->d->propertiesChanged(path_full, interface, changed, invalidated); 0438 return; 0439 } 0440 qCDebug(BLUEZQT) << "Unhandled property change" << interface << changed << invalidated; 0441 }); 0442 } 0443 0444 void ManagerPrivate::dummy() 0445 { 0446 } 0447 0448 } // namespace BluezQt 0449 0450 #include "moc_manager_p.cpp"