diff options
Diffstat (limited to 'ipc/dbus/DBusHelpers.cpp')
-rw-r--r-- | ipc/dbus/DBusHelpers.cpp | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/ipc/dbus/DBusHelpers.cpp b/ipc/dbus/DBusHelpers.cpp new file mode 100644 index 0000000000..73b4596f29 --- /dev/null +++ b/ipc/dbus/DBusHelpers.cpp @@ -0,0 +1,246 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DBusHelpers.h" +#include "mozilla/ipc/DBusMessageRefPtr.h" +#include "mozilla/ipc/DBusPendingCallRefPtr.h" +#include "mozilla/ipc/DBusWatcher.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Unused.h" +#include "nsThreadUtils.h" + +#undef CHROMIUM_LOG +#if defined(MOZ_WIDGET_GONK) +#include <android/log.h> +#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args); +#else +#define CHROMIUM_LOG(args...) printf(args); +#endif + +namespace mozilla { +namespace ipc { + +// +// DBus I/O +// + +namespace { + +class Notification final +{ +public: + Notification(DBusReplyCallback aCallback, void* aData) + : mCallback(aCallback) + , mData(aData) + { } + + // Callback function for DBus replies. Only run it on I/O thread. + // + static void Handle(DBusPendingCall* aCall, void* aData) + { + MOZ_ASSERT(!NS_IsMainThread()); + + RefPtr<DBusPendingCall> call = already_AddRefed<DBusPendingCall>(aCall); + + UniquePtr<Notification> ntfn(static_cast<Notification*>(aData)); + + RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>( + dbus_pending_call_steal_reply(call)); + + // The reply can be null if the timeout has been reached. + if (reply) { + ntfn->RunCallback(reply); + } + + dbus_pending_call_cancel(call); + } + +private: + void RunCallback(DBusMessage* aMessage) + { + if (mCallback) { + mCallback(aMessage, mData); + } + } + + DBusReplyCallback mCallback; + void* mData; +}; + +static already_AddRefed<DBusMessage> +BuildDBusMessage(const char* aDestination, + const char* aPath, + const char* aIntf, + const char* aFunc, + int aFirstArgType, + va_list aArgs) +{ + RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>( + dbus_message_new_method_call(aDestination, aPath, aIntf, aFunc)); + + if (!msg) { + CHROMIUM_LOG("dbus_message_new_method_call failed"); + return nullptr; + } + + auto success = dbus_message_append_args_valist(msg, aFirstArgType, aArgs); + + if (!success) { + CHROMIUM_LOG("dbus_message_append_args_valist failed"); + return nullptr; + } + + return msg.forget(); +} + +} // anonymous namespace + +nsresult +DBusWatchConnection(DBusConnection* aConnection) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + + auto success = + dbus_connection_set_watch_functions(aConnection, + DBusWatcher::AddWatchFunction, + DBusWatcher::RemoveWatchFunction, + DBusWatcher::ToggleWatchFunction, + aConnection, nullptr); + if (!success) { + CHROMIUM_LOG("dbus_connection_set_watch_functions failed"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +void +DBusUnwatchConnection(DBusConnection* aConnection) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + + auto success = dbus_connection_set_watch_functions(aConnection, + nullptr, nullptr, nullptr, + nullptr, nullptr); + if (!success) { + CHROMIUM_LOG("dbus_connection_set_watch_functions failed"); + } +} + +nsresult +DBusSendMessage(DBusConnection* aConnection, DBusMessage* aMessage) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + MOZ_ASSERT(aMessage); + + auto success = dbus_connection_send(aConnection, aMessage, nullptr); + + if (!success) { + CHROMIUM_LOG("dbus_connection_send failed"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +DBusSendMessageWithReply(DBusConnection* aConnection, + DBusReplyCallback aCallback, void* aData, + int aTimeout, + DBusMessage* aMessage) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + MOZ_ASSERT(aMessage); + + UniquePtr<Notification> ntfn = MakeUnique<Notification>(aCallback, aData); + + auto call = static_cast<DBusPendingCall*>(nullptr); + + auto success = dbus_connection_send_with_reply(aConnection, + aMessage, + &call, + aTimeout); + if (!success) { + CHROMIUM_LOG("dbus_connection_send_with_reply failed"); + return NS_ERROR_FAILURE; + } + + success = dbus_pending_call_set_notify(call, Notification::Handle, + ntfn.get(), nullptr); + if (!success) { + CHROMIUM_LOG("dbus_pending_call_set_notify failed"); + return NS_ERROR_FAILURE; + } + + Unused << ntfn.release(); // Picked up in |Notification::Handle| + + return NS_OK; +} + +nsresult +DBusSendMessageWithReply(DBusConnection* aConnection, + DBusReplyCallback aCallback, + void* aData, + int aTimeout, + const char* aDestination, + const char* aPath, + const char* aIntf, + const char* aFunc, + int aFirstArgType, + va_list aArgs) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + + RefPtr<DBusMessage> msg = + BuildDBusMessage(aDestination, aPath, aIntf, aFunc, aFirstArgType, aArgs); + + if (!msg) { + return NS_ERROR_FAILURE; + } + + return DBusSendMessageWithReply(aConnection, aCallback, aData, aTimeout, msg); +} + +nsresult +DBusSendMessageWithReply(DBusConnection* aConnection, + DBusReplyCallback aCallback, + void* aData, + int aTimeout, + const char* aDestination, + const char* aPath, + const char* aIntf, + const char* aFunc, + int aFirstArgType, + ...) +{ + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aConnection); + + va_list args; + va_start(args, aFirstArgType); + + auto rv = DBusSendMessageWithReply(aConnection, + aCallback, aData, + aTimeout, + aDestination, aPath, aIntf, aFunc, + aFirstArgType, args); + va_end(args); + + if (NS_FAILED(rv)) { + return rv; + } + + return NS_OK; +} + +} +} |