Bug 906019: Implemented non-blocking GetDefaultAdapterPathInternal, r=echou,gyeh

GetDefaultAdapterPathInternal used two blocking DBus operations,
namely 'DefaultAdapter' and 'GetProperties'. The latter one depends
on the result of the former one.

The be non-blocking, GetDefaultAdapterPathInternal first make a
non-blocking 'DefaultAdapter' call. Once received, the reply handler
non-blockingly calls 'GetProperties' with the values received for
'DefaultAdapter', and put itself in place as this call's reply
handler. For this second reply, it finally schedules the Bluetooth
reply runnable.

--HG--
extra : rebase_source : aa0872a5db69c928ca25723952fe2928ef52d107
This commit is contained in:
Thomas Zimmermann 2013-08-20 10:27:36 +02:00
Родитель 482dd7c30b
Коммит 88b10d29d8
1 изменённых файлов: 105 добавлений и 28 удалений

Просмотреть файл

@ -1789,46 +1789,119 @@ BluetoothDBusService::IsEnabledInternal()
return mEnabled; return mEnabled;
} }
class DefaultAdapterPropertiesRunnable : public nsRunnable class DefaultAdapterPathReplyHandler : public DBusReplyHandler
{ {
public: public:
DefaultAdapterPropertiesRunnable(BluetoothReplyRunnable* aRunnable) DefaultAdapterPathReplyHandler(BluetoothReplyRunnable* aRunnable)
: mRunnable(dont_AddRef(aRunnable)) : mRunnable(aRunnable)
{ {
MOZ_ASSERT(mRunnable);
} }
nsresult Run() void Handle(DBusMessage* aReply) MOZ_OVERRIDE
{ {
MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
BluetoothValue v; if (!aReply || (dbus_message_get_type(aReply) == DBUS_MESSAGE_TYPE_ERROR)) {
nsAutoString replyError; const char* errStr = "Timeout in DefaultAdapterPathReplyHandler";
if (!GetDefaultAdapterPath(v, replyError)) { if (aReply) {
DispatchBluetoothReply(mRunnable, v, replyError); errStr = dbus_message_get_error_name(aReply);
return NS_ERROR_FAILURE; if (!errStr) {
errStr = "Bluetooth DBus Error";
}
}
DispatchBluetoothReply(mRunnable, BluetoothValue(),
NS_ConvertUTF8toUTF16(errStr));
return;
} }
DBusError err; bool success;
dbus_error_init(&err); nsAutoString replyError;
nsString objectPath = v.get_nsString(); if (mAdapterPath.IsEmpty()) {
v = InfallibleTArray<BluetoothNamedValue>(); success = HandleDefaultAdapterPathReply(aReply, replyError);
if (!GetPropertiesInternal(objectPath, DBUS_ADAPTER_IFACE, v)) { } else {
NS_WARNING("Getting properties failed!"); success = HandleGetPropertiesReply(aReply, replyError);
return NS_ERROR_FAILURE; }
if (!success) {
DispatchBluetoothReply(mRunnable, BluetoothValue(), replyError);
}
}
protected:
bool HandleDefaultAdapterPathReply(DBusMessage* aReply,
nsAString& aReplyError)
{
BluetoothValue value;
DBusError error;
dbus_error_init(&error);
MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
UnpackObjectPathMessage(aReply, &error, value, aReplyError);
if (!aReplyError.IsEmpty()) {
return false;
}
mAdapterPath = value.get_nsString();
// Acquire another reference to this reply handler
nsRefPtr<DefaultAdapterPathReplyHandler> handler = this;
nsRefPtr<RawDBusConnection> threadConnection = gThreadConnection;
if (!threadConnection.get()) {
aReplyError = NS_LITERAL_STRING("DBus connection has been closed.");
return false;
}
bool success = dbus_func_args_async(threadConnection->GetConnection(), 1000,
DefaultAdapterPathReplyHandler::Callback,
handler.get(),
NS_ConvertUTF16toUTF8(mAdapterPath).get(),
DBUS_ADAPTER_IFACE, "GetProperties",
DBUS_TYPE_INVALID);
if (!success) {
aReplyError = NS_LITERAL_STRING("dbus_func_args_async failed");
return false;
}
handler.forget();
return true;
}
bool HandleGetPropertiesReply(DBusMessage* aReply,
nsAutoString& aReplyError)
{
BluetoothValue value;
DBusError error;
dbus_error_init(&error);
MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
bool success = UnpackPropertiesMessage(aReply, &error, value,
DBUS_ADAPTER_IFACE);
if (!success) {
aReplyError = NS_ConvertUTF8toUTF16(error.message);
return false;
} }
// We have to manually attach the path to the rest of the elements // We have to manually attach the path to the rest of the elements
v.get_ArrayOfBluetoothNamedValue().AppendElement( value.get_ArrayOfBluetoothNamedValue().AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Path"), objectPath)); BluetoothNamedValue(NS_LITERAL_STRING("Path"), mAdapterPath));
DispatchBluetoothReply(mRunnable, v, replyError); // Dispatch result
DispatchBluetoothReply(mRunnable, value, aReplyError);
return NS_OK; return true;
} }
private: private:
nsRefPtr<BluetoothReplyRunnable> mRunnable; nsRefPtr<BluetoothReplyRunnable> mRunnable;
nsString mAdapterPath;
}; };
nsresult nsresult
@ -1843,14 +1916,18 @@ BluetoothDBusService::GetDefaultAdapterPathInternal(
return NS_OK; return NS_OK;
} }
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable; nsRefPtr<DefaultAdapterPathReplyHandler> handler =
nsRefPtr<nsRunnable> func(new DefaultAdapterPropertiesRunnable(runnable)); new DefaultAdapterPathReplyHandler(aRunnable);
if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) { bool success = dbus_func_args_async(mConnection, 1000,
NS_WARNING("Cannot dispatch firmware loading task!"); DefaultAdapterPathReplyHandler::Callback,
return NS_ERROR_FAILURE; handler.get(),
} "/",
DBUS_MANAGER_IFACE, "DefaultAdapter",
DBUS_TYPE_INVALID);
NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
handler.forget();
runnable.forget();
return NS_OK; return NS_OK;
} }