From e57a26afccd77e9723168f83aa6143cda93147bf Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 27 Aug 2013 01:00:47 +0200 Subject: [PATCH] Bug 906020: Implement non-blocking BluetoothArrayOfDevicePropertiesRunnable, r=echou,gyeh BluetoothArrayOfDevicePropertiesRunnable used to block while waiting for the results of the 'GetProperties' messages it sends over DBus. With this patch, each 'GetProperties' operation is performed asyncronously and the result is handled in a DBus reply handler. The same reply handler gets used for all 'GetProperties' messages until all devices have been processed. In this case the final Bluetooth reply runnable gets dispatched. The old function GetPropertiesInternal is now unused and has been removed. --HG-- extra : rebase_source : 6e5ed63ce2077e16bcaf995c3ca89f923ec8b37e --- dom/bluetooth/linux/BluetoothDBusService.cpp | 217 ++++++++++++------- 1 file changed, 141 insertions(+), 76 deletions(-) diff --git a/dom/bluetooth/linux/BluetoothDBusService.cpp b/dom/bluetooth/linux/BluetoothDBusService.cpp index ddc11e54fa9..412f3219568 100644 --- a/dom/bluetooth/linux/BluetoothDBusService.cpp +++ b/dom/bluetooth/linux/BluetoothDBusService.cpp @@ -783,32 +783,6 @@ ParsePropertyChange(DBusMessage* aMsg, BluetoothValue& aValue, aValue = props; } -static bool -GetPropertiesInternal(const nsAString& aPath, - const char* aIface, - BluetoothValue& aValue) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - DBusError err; - dbus_error_init(&err); - - DBusMessage* msg = dbus_func_args_timeout(gThreadConnection->GetConnection(), - 1000, - &err, - NS_ConvertUTF16toUTF8(aPath).get(), - aIface, - "GetProperties", - DBUS_TYPE_INVALID); - NS_ENSURE_TRUE(msg, false); - - bool success = UnpackPropertiesMessage(msg, &err, aValue, aIface); - - dbus_message_unref(msg); - - return success; -} - class AppendDeviceNameReplyHandler: public DBusReplyHandler { public: @@ -2048,6 +2022,142 @@ BluetoothDBusService::StartDiscoveryInternal(BluetoothReplyRunnable* aRunnable) return SendDiscoveryMessage("StartDiscovery", aRunnable); } +class BluetoothArrayOfDevicePropertiesReplyHandler : public DBusReplyHandler +{ +public: + BluetoothArrayOfDevicePropertiesReplyHandler( + const nsTArray& aDeviceAddresses, + const FilterFunc aFilterFunc, BluetoothReplyRunnable* aRunnable) + : mDeviceAddresses(aDeviceAddresses) + , mProcessedDeviceAddresses(0) + , mFilterFunc(aFilterFunc) + , mRunnable(aRunnable) + , mValues(InfallibleTArray()) + { + MOZ_ASSERT(mRunnable); + } + + void Handle(DBusMessage* aReply) MOZ_OVERRIDE + { + MOZ_ASSERT(!NS_IsMainThread()); // DBus thread + MOZ_ASSERT(!mObjectPath.IsEmpty()); + MOZ_ASSERT(mProcessedDeviceAddresses < mDeviceAddresses.Length()); + + const nsTArray::index_type i = mProcessedDeviceAddresses++; + + if (!aReply || + (dbus_message_get_type(aReply) == DBUS_MESSAGE_TYPE_ERROR)) { + BT_WARNING("Invalid DBus message"); + ProcessRemainingDeviceAddresses(); + return; + } + + // Get device properties from result of GetProperties + + DBusError err; + dbus_error_init(&err); + + BluetoothValue deviceProperties; + + bool success = UnpackPropertiesMessage(aReply, &err, deviceProperties, + DBUS_DEVICE_IFACE); + if (!success) { + BT_WARNING("Failed to get device properties"); + ProcessRemainingDeviceAddresses(); + return; + } + + InfallibleTArray& devicePropertiesArray = + deviceProperties.get_ArrayOfBluetoothNamedValue(); + + // We have to manually attach the path to the rest of the elements + devicePropertiesArray.AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Path"), mObjectPath)); + + // It is possible that property Icon missed due to CoD of major + // class is TOY but service class is "Audio", we need to assign + // Icon as audio-card. This is for PTS test TC_AG_COD_BV_02_I. + // As HFP specification defined that + // service class is "Audio" can be considered as HFP AG. + if (!ContainsIcon(devicePropertiesArray)) { + InfallibleTArray::size_type j; + for (j = 0; j < devicePropertiesArray.Length(); ++j) { + BluetoothNamedValue& deviceProperty = devicePropertiesArray[j]; + if (deviceProperty.name().EqualsLiteral("Class")) { + if (HasAudioService(deviceProperty.value().get_uint32_t())) { + devicePropertiesArray.AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Icon"), + NS_LITERAL_STRING("audio-card"))); + } + break; + } + } + } + + if (mFilterFunc(deviceProperties)) { + mValues.get_ArrayOfBluetoothNamedValue().AppendElement( + BluetoothNamedValue(mDeviceAddresses[i], deviceProperties)); + } + + ProcessRemainingDeviceAddresses(); + } + + void ProcessRemainingDeviceAddresses() + { + if (mProcessedDeviceAddresses < mDeviceAddresses.Length()) { + if (!SendNextGetProperties()) { + DispatchBluetoothReply(mRunnable, BluetoothValue(), + NS_LITERAL_STRING( + "SendNextGetProperties failed")); + } + } else { + // Send resulting device properties + DispatchBluetoothReply(mRunnable, mValues, EmptyString()); + } + } + +protected: + bool SendNextGetProperties() + { + MOZ_ASSERT(mProcessedDeviceAddresses < mDeviceAddresses.Length()); + + // cache object path for reply + mObjectPath = GetObjectPathFromAddress(sAdapterPath, + mDeviceAddresses[mProcessedDeviceAddresses]); + + nsRefPtr threadConnection = gThreadConnection; + + if (!threadConnection.get()) { + BT_WARNING("%s: DBus connection has been closed.", __FUNCTION__); + return false; + } + + nsRefPtr handler = this; + + bool success = + dbus_func_args_async(threadConnection->GetConnection(), 1000, + BluetoothArrayOfDevicePropertiesReplyHandler::Callback, + handler.get(), + NS_ConvertUTF16toUTF8(mObjectPath).get(), + DBUS_DEVICE_IFACE, "GetProperties", + DBUS_TYPE_INVALID); + + NS_ENSURE_TRUE(success, false); + + handler.forget(); + + return true; + } + +private: + nsString mObjectPath; + const nsTArray mDeviceAddresses; + nsTArray::size_type mProcessedDeviceAddresses; + const FilterFunc mFilterFunc; + nsRefPtr mRunnable; + BluetoothValue mValues; +}; + class BluetoothArrayOfDevicePropertiesRunnable : public nsRunnable { public: @@ -2064,58 +2174,13 @@ public: nsresult Run() { MOZ_ASSERT(!NS_IsMainThread()); - DBusError err; - dbus_error_init(&err); - BluetoothValue values = InfallibleTArray(); - nsAutoString errorStr; + nsRefPtr handler = + new BluetoothArrayOfDevicePropertiesReplyHandler(mDeviceAddresses, + mFilterFunc, + mRunnable); + handler->ProcessRemainingDeviceAddresses(); - for (uint32_t i = 0; i < mDeviceAddresses.Length(); i++) { - BluetoothValue v; - nsString objectPath = - GetObjectPathFromAddress(sAdapterPath, mDeviceAddresses[i]); - - if (!GetPropertiesInternal(objectPath, DBUS_DEVICE_IFACE, v)) { - // The target device may have been removed, so continue checking the - // next device object. - continue; - } - - // We have to manually attach the path to the rest of the elements - v.get_ArrayOfBluetoothNamedValue().AppendElement( - BluetoothNamedValue(NS_LITERAL_STRING("Path"), objectPath) - ); - const InfallibleTArray& deviceProperties = - v.get_ArrayOfBluetoothNamedValue(); - uint32_t length = deviceProperties.Length(); - // It is possible that property Icon missed due to CoD of major - // class is TOY but service class is "Audio", we need to assign - // Icon as audio-card. This is for PTS test TC_AG_COD_BV_02_I. - // As HFP specification defined that - // service class is "Audio" can be considered as HFP AG. - if (!ContainsIcon(deviceProperties)) { - for (uint32_t p = 0; p < length; ++p) { - if (deviceProperties[p].name().EqualsLiteral("Class")) { - if (HasAudioService(deviceProperties[p].value().get_uint32_t())) { - v.get_ArrayOfBluetoothNamedValue() - .AppendElement( - BluetoothNamedValue(NS_LITERAL_STRING("Icon"), - NS_LITERAL_STRING("audio-card"))); - } - break; - } - } - } - - if (mFilterFunc(v)) { - values.get_ArrayOfBluetoothNamedValue().AppendElement( - BluetoothNamedValue(mDeviceAddresses[i], - v.get_ArrayOfBluetoothNamedValue()) - ); - } - } - - DispatchBluetoothReply(mRunnable, values, errorStr); return NS_OK; }