From d755f7ab67a1f5b345caf09b1fc798d3c6e0ca34 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Fri, 7 Jun 2019 09:05:36 +0200 Subject: winrt: Avoid threading issues when handling characteristic changes As callbacks do not necessarily happen on Qt's main thread, it is possible that we access the service list while it is being changed if we access it from the callback directly. Doing this can cause application crashes. Thus we hand back the information about a changed characteristic to the main thread via signal/slot and handle it from the main thread. With QLowEnergyControllerPrivateWinRTNew having the Q_OBJECT macro, we can no longer use forward declares for the GATT classes as moc chokes on these. Thus an include is used. Fixes: QTBUG-75907 Change-Id: I063794eecf904921ff55fab76a5bdde3a9aebf44 Reviewed-by: Alex Blasche --- src/bluetooth/qlowenergycontroller_winrt.cpp | 10 +++++++--- src/bluetooth/qlowenergycontroller_winrt_new.cpp | 8 ++++++-- src/bluetooth/qlowenergycontroller_winrt_new_p.h | 14 ++++++-------- src/bluetooth/qlowenergycontroller_winrt_p.h | 5 ++++- 4 files changed, 23 insertions(+), 14 deletions(-) (limited to 'src/bluetooth') diff --git a/src/bluetooth/qlowenergycontroller_winrt.cpp b/src/bluetooth/qlowenergycontroller_winrt.cpp index e70b046b..16a68334 100644 --- a/src/bluetooth/qlowenergycontroller_winrt.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt.cpp @@ -239,6 +239,9 @@ QLowEnergyControllerPrivateWinRT::QLowEnergyControllerPrivateWinRT() qCDebug(QT_BT_WINRT) << __FUNCTION__; registerQLowEnergyControllerMetaType(); + connect(this, &QLowEnergyControllerPrivateWinRT::characteristicChanged, + this, &QLowEnergyControllerPrivateWinRT::handleCharacteristicChanged, + Qt::QueuedConnection); } QLowEnergyControllerPrivateWinRT::~QLowEnergyControllerPrivateWinRT() @@ -453,7 +456,7 @@ void QLowEnergyControllerPrivateWinRT::registerForValueChanges(const QBluetoothU ComPtr buffer; hr = args->get_CharacteristicValue(&buffer); Q_ASSERT_SUCCEEDED(hr); - characteristicChanged(handle, byteArrayFromBuffer(buffer)); + emit characteristicChanged(handle, byteArrayFromBuffer(buffer)); return S_OK; }).Get(), &token); Q_ASSERT_SUCCEEDED(hr); @@ -1103,9 +1106,10 @@ void QLowEnergyControllerPrivateWinRT::addToGenericAttributeList(const QLowEnerg Q_UNIMPLEMENTED(); } -void QLowEnergyControllerPrivateWinRT::characteristicChanged( - int charHandle, const QByteArray &data) +void QLowEnergyControllerPrivateWinRT::handleCharacteristicChanged( + quint16 charHandle, const QByteArray &data) { + qCDebug(QT_BT_WINRT) << __FUNCTION__ << charHandle << data; QSharedPointer service = serviceForHandle(charHandle); if (service.isNull()) diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp index bb9894ff..3f1b04f2 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_new.cpp +++ b/src/bluetooth/qlowenergycontroller_winrt_new.cpp @@ -435,6 +435,9 @@ QLowEnergyControllerPrivateWinRTNew::QLowEnergyControllerPrivateWinRTNew() : QLowEnergyControllerPrivate() { registerQLowEnergyControllerMetaType(); + connect(this, &QLowEnergyControllerPrivateWinRTNew::characteristicChanged, + this, &QLowEnergyControllerPrivateWinRTNew::handleCharacteristicChanged, + Qt::QueuedConnection); } QLowEnergyControllerPrivateWinRTNew::~QLowEnergyControllerPrivateWinRTNew() @@ -613,7 +616,7 @@ HRESULT QLowEnergyControllerPrivateWinRTNew::onValueChange(IGattCharacteristic * ComPtr buffer; hr = args->get_CharacteristicValue(&buffer); RETURN_IF_FAILED("Could not obtain characteristic's value", return S_OK) - characteristicChanged(handle, byteArrayFromBuffer(buffer)); + emit characteristicChanged(handle, byteArrayFromBuffer(buffer)); return S_OK; } @@ -1487,9 +1490,10 @@ void QLowEnergyControllerPrivateWinRTNew::addToGenericAttributeList(const QLowEn Q_UNIMPLEMENTED(); } -void QLowEnergyControllerPrivateWinRTNew::characteristicChanged( +void QLowEnergyControllerPrivateWinRTNew::handleCharacteristicChanged( quint16 charHandle, const QByteArray &data) { + qCDebug(QT_BT_WINRT) << __FUNCTION__ << charHandle << data; QSharedPointer service = serviceForHandle(charHandle); if (service.isNull()) diff --git a/src/bluetooth/qlowenergycontroller_winrt_new_p.h b/src/bluetooth/qlowenergycontroller_winrt_new_p.h index 8cc5f9ce..c31408be 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_new_p.h +++ b/src/bluetooth/qlowenergycontroller_winrt_new_p.h @@ -64,13 +64,6 @@ namespace ABI { namespace Windows { namespace Devices { namespace Bluetooth { - namespace GenericAttributeProfile { - class GattDeviceServicesResult; - struct IGattCharacteristic; - struct IGattDeviceService; - struct IGattValueChangedEventArgs; - } - struct IBluetoothLEDevice; } } @@ -82,6 +75,7 @@ namespace ABI { } #include +#include #include @@ -97,6 +91,7 @@ QLowEnergyControllerPrivate *createWinRTLowEnergyController(); class QLowEnergyControllerPrivateWinRTNew final : public QLowEnergyControllerPrivate { + Q_OBJECT public: QLowEnergyControllerPrivateWinRTNew(); ~QLowEnergyControllerPrivateWinRTNew() override; @@ -135,8 +130,11 @@ public: void addToGenericAttributeList(const QLowEnergyServiceData &service, QLowEnergyHandle startHandle) override; -private slots: +signals: void characteristicChanged(quint16 charHandle, const QByteArray &data); + +private slots: + void handleCharacteristicChanged(quint16 charHandle, const QByteArray &data); void handleServiceHandlerError(const QString &error); private: diff --git a/src/bluetooth/qlowenergycontroller_winrt_p.h b/src/bluetooth/qlowenergycontroller_winrt_p.h index da21353f..fedc52d9 100644 --- a/src/bluetooth/qlowenergycontroller_winrt_p.h +++ b/src/bluetooth/qlowenergycontroller_winrt_p.h @@ -114,8 +114,11 @@ public: void addToGenericAttributeList(const QLowEnergyServiceData &service, QLowEnergyHandle startHandle) override; +signals: + void characteristicChanged(quint16 charHandle, const QByteArray &data); + private slots: - void characteristicChanged(int charHandle, const QByteArray &data); + void handleCharacteristicChanged(quint16 charHandle, const QByteArray &data); private: Microsoft::WRL::ComPtr mDevice; -- cgit v1.2.3