Bug 744349 - Create message distribution mechanism for DBus Bluetooth Signals; r=cjones
authorKyle Machulis <kyle@nonpolynomial.com>
Sat, 02 Jun 2012 11:23:16 -0700
changeset 95648 5f9bf688b9ac88ec8ff5fbcee441e323070575ae
parent 95647 ba8cfc79dd6eab662f6ecd5223a1f618da2052fe
child 95649 b0dd2b70a23324f419500405b747743a72a0ac54
push idunknown
push userunknown
push dateunknown
reviewerscjones
bugs744349
milestone15.0a1
Bug 744349 - Create message distribution mechanism for DBus Bluetooth Signals; r=cjones
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothAdapter.h
dom/bluetooth/BluetoothCommon.h
dom/bluetooth/BluetoothManager.cpp
dom/bluetooth/BluetoothManager.h
dom/bluetooth/BluetoothUtils.h
dom/bluetooth/Makefile.in
dom/bluetooth/linux/BluetoothDBusUtils.cpp
dom/system/gonk/SystemWorkerManager.cpp
ipc/dbus/DBusThread.cpp
ipc/dbus/DBusThread.h
ipc/dbus/DBusUtils.cpp
ipc/dbus/DBusUtils.h
ipc/dbus/RawDBusConnection.cpp
ipc/dbus/RawDBusConnection.h
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=40: */
 /* 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 "BluetoothAdapter.h"
-#include "BluetoothFirmware.h"
+#include "BluetoothUtils.h"
 
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
 
@@ -31,8 +31,34 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 
+BluetoothAdapter::BluetoothAdapter(const nsCString& name) :
+  mName(name)
+{
+}
+
+BluetoothAdapter::~BluetoothAdapter()
+{
+  if (NS_FAILED(UnregisterBluetoothEventHandler(mName, this))) {
+    NS_WARNING("Failed to unregister object with observer!");
+  }
+}
+
+// static
+already_AddRefed<BluetoothAdapter>
+BluetoothAdapter::Create(const nsCString& name) {
+  nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(name);
+  if (NS_FAILED(RegisterBluetoothEventHandler(name, adapter))) {
+    NS_WARNING("Failed to register object with observer!");
+    return NULL;
+  }
+  return adapter.forget();
+}
+
+void BluetoothAdapter::Notify(const BluetoothEvent& aData) {
+  printf("Got an adapter message!\n");
+}
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -6,30 +6,42 @@
 
 #ifndef mozilla_dom_bluetooth_bluetoothadapter_h__
 #define mozilla_dom_bluetooth_bluetoothadapter_h__
 
 #include "BluetoothCommon.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMBluetoothAdapter.h"
 #include "nsIDOMDOMRequest.h"
+#include "mozilla/Observer.h"
 
 class nsIEventTarget;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothAdapter : public nsDOMEventTargetHelper
                        , public nsIDOMBluetoothAdapter
+                       , public BluetoothEventObserver
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMBLUETOOTHADAPTER
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothAdapter,
                                            nsDOMEventTargetHelper)
 
+  static already_AddRefed<BluetoothAdapter>
+  Create(const nsCString& name);
+
+  void Notify(const BluetoothEvent& aParam);
+protected:
+  nsCString mName;
+private:
+  BluetoothAdapter() {}
+  BluetoothAdapter(const nsCString& name);
+  ~BluetoothAdapter();
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -2,18 +2,64 @@
 /* vim: set ts=2 et sw=2 tw=40: */
 /* 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/. */
 
 #ifndef mozilla_dom_bluetooth_bluetoothcommon_h__
 #define mozilla_dom_bluetooth_bluetoothcommon_h__
 
+#include "nsString.h"
+#include "nsTArray.h"
+#include "mozilla/Observer.h"
+
 #define BEGIN_BLUETOOTH_NAMESPACE \
   namespace mozilla { namespace dom { namespace bluetooth {
 #define END_BLUETOOTH_NAMESPACE \
   } /* namespace bluetooth */ } /* namespace dom */ } /* namespace mozilla */
 #define USING_BLUETOOTH_NAMESPACE \
   using namespace mozilla::dom::bluetooth;
 
-class nsIDOMBluetooth;
+class nsCString;
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+/**
+ * BluetoothEvents usually hand back one of 3 types:
+ *
+ * - 32-bit Int
+ * - String
+ * - Bool
+ *
+ * BluetoothVariant encases the types into a single structure.
+ */
+struct BluetoothVariant
+{
+  uint32_t mUint32;
+  nsCString mString;  
+};
+
+/**
+ * BluetoothNamedVariant is a variant with a name value, for passing around
+ * things like properties with variant values.
+ */
+struct BluetoothNamedVariant
+{
+  nsCString mName;
+  BluetoothVariant mValue;
+};
+
+/**
+ * BluetoothEvent holds a variant value and the name of an event, such as
+ * PropertyChanged or DeviceFound.
+ */
+struct BluetoothEvent
+{
+  nsCString mEventName;
+  nsTArray<BluetoothNamedVariant> mValues;
+};
+
+typedef mozilla::Observer<BluetoothEvent> BluetoothEventObserver;
+typedef mozilla::ObserverList<BluetoothEvent> BluetoothEventObserverList;
+
+END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluetoothcommon_h__
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -3,16 +3,17 @@
 /* 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 "BluetoothManager.h"
 #include "BluetoothCommon.h"
 #include "BluetoothFirmware.h"
 #include "BluetoothAdapter.h"
+#include "BluetoothUtils.h"
 
 #include "nsIDocument.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsPIDOMWindow.h"
 
 #include "jsapi.h"
 #include "mozilla/Preferences.h"
@@ -25,34 +26,37 @@
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 
 #define DOM_BLUETOOTH_URL_PREF "dom.mozBluetooth.whitelist"
 
+using namespace mozilla;
 using mozilla::Preferences;
 
 USING_BLUETOOTH_NAMESPACE
 
 static void
 FireEnabled(bool aResult, nsIDOMDOMRequest* aDomRequest)
 {
-  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+  nsCOMPtr<nsIDOMRequestService> rs =
+    do_GetService("@mozilla.org/dom/dom-request-service;1");
 
   if (!rs) {
     NS_WARNING("No DOMRequest Service!");
     return;
   }
 
-  mozilla::DebugOnly<nsresult> rv = aResult ?     
-                                    rs->FireSuccess(aDomRequest, JSVAL_VOID) :
-                                    rs->FireError(aDomRequest, 
-                                                  NS_LITERAL_STRING("Bluetooth firmware loading failed"));
+  DebugOnly<nsresult> rv =
+    aResult ?     
+    rs->FireSuccess(aDomRequest, JSVAL_VOID) :
+    rs->FireError(aDomRequest, 
+                  NS_LITERAL_STRING("Bluetooth firmware loading failed"));
 
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Bluetooth firmware loading failed");
 }
 
 DOMCI_DATA(BluetoothManager, BluetoothManager)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothManager)
 
@@ -115,17 +119,18 @@ class ToggleBtResultTask : public nsRunn
     nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
     bool mEnabled;
     bool mResult;
 };
 
 class ToggleBtTask : public nsRunnable
 {
   public:
-    ToggleBtTask(bool aEnabled, nsIDOMDOMRequest* aReq, BluetoothManager* aManager)
+    ToggleBtTask(bool aEnabled, nsIDOMDOMRequest* aReq,
+                 BluetoothManager* aManager)
       : mEnabled(aEnabled),        
         mManagerPtr(aManager),
         mDOMRequest(aReq)
     {
       MOZ_ASSERT(NS_IsMainThread());
     }
 
     NS_IMETHOD Run() 
@@ -172,21 +177,29 @@ class ToggleBtTask : public nsRunnable
 
   private:
     bool mEnabled;
     nsRefPtr<BluetoothManager> mManagerPtr;
     nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
 };
 
 BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow) :
-  mEnabled(false)
+  mEnabled(false),
+  mName(nsDependentCString("/"))
 {
   BindToOwner(aWindow);
 }
 
+BluetoothManager::~BluetoothManager()
+{
+  if(NS_FAILED(UnregisterBluetoothEventHandler(mName, this))) {
+    NS_WARNING("Failed to unregister object with observer!");
+  }
+}
+
 NS_IMETHODIMP
 BluetoothManager::SetEnabled(bool aEnabled, nsIDOMDOMRequest** aDomRequest)
 {
   nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
 
   if (!rs) {
     NS_ERROR("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
@@ -215,31 +228,55 @@ BluetoothManager::GetEnabled(bool* aEnab
 {
   *aEnabled = mEnabled;
   return NS_OK; 
 }
 
 NS_IMETHODIMP
 BluetoothManager::GetDefaultAdapter(nsIDOMBluetoothAdapter** aAdapter)
 {
-  //TODO: Implement adapter fetching
-  return NS_ERROR_FAILURE;
+  nsCString path;
+  nsresult rv = GetDefaultAdapterPathInternal(path);
+  if(NS_FAILED(rv)) {
+    NS_WARNING("Cannot fetch adapter path!");
+    return NS_ERROR_FAILURE;
+  }
+  nsRefPtr<BluetoothAdapter> adapter = BluetoothAdapter::Create(path);
+  adapter.forget(aAdapter);
+  return NS_OK;
+}
+
+// static
+already_AddRefed<BluetoothManager>
+BluetoothManager::Create(nsPIDOMWindow* aWindow) {
+  nsRefPtr<BluetoothManager> manager = new BluetoothManager(aWindow);
+  nsDependentCString name("/");
+  if(NS_FAILED(RegisterBluetoothEventHandler(name, manager))) {
+    NS_WARNING("Failed to register object with observer!");
+    return NULL;
+  }
+  return manager.forget();
 }
 
 nsresult
-NS_NewBluetoothManager(nsPIDOMWindow* aWindow, nsIDOMBluetoothManager** aBluetoothManager)
+NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
+                       nsIDOMBluetoothManager** aBluetoothManager)
 {
   NS_ASSERTION(aWindow, "Null pointer!");
 
   bool allowed;
   nsresult rv = nsContentUtils::IsOnPrefWhitelist(aWindow, DOM_BLUETOOTH_URL_PREF, &allowed);
   NS_ENSURE_SUCCESS(rv, rv);
   
   if (!allowed) {
     *aBluetoothManager = NULL;
     return NS_OK;
   }
 
-  nsRefPtr<BluetoothManager> bluetoothManager = new BluetoothManager(aWindow);
+  nsRefPtr<BluetoothManager> bluetoothManager = BluetoothManager::Create(aWindow);
 
   bluetoothManager.forget(aBluetoothManager);
   return NS_OK;
 }
+
+void BluetoothManager::Notify(const BluetoothEvent& aData) {
+  printf("Received an manager message!\n");
+}
--- a/dom/bluetooth/BluetoothManager.h
+++ b/dom/bluetooth/BluetoothManager.h
@@ -5,41 +5,50 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluetoothmanager_h__
 #define mozilla_dom_bluetooth_bluetoothmanager_h__
 
 #include "BluetoothCommon.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMBluetoothManager.h"
+#include "nsWeakReference.h"
+#include "mozilla/Observer.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
-class BluetoothAdapter;
-
 class BluetoothManager : public nsDOMEventTargetHelper
-                       , public nsIDOMBluetoothManager                         
+                       , public nsIDOMBluetoothManager
+                       , public BluetoothEventObserver
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMBLUETOOTHMANAGER
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothManager,
                                            nsDOMEventTargetHelper)
 
-  BluetoothManager(nsPIDOMWindow*);
+
   inline void SetEnabledInternal(bool aEnabled) {mEnabled = aEnabled;}
-  
+
+  static already_AddRefed<BluetoothManager>
+  Create(nsPIDOMWindow* aWindow);
+  void Notify(const BluetoothEvent& aData);
 private:
+  BluetoothManager() {}
+  BluetoothManager(nsPIDOMWindow* aWindow);
+  ~BluetoothManager();
   bool mEnabled;
+  nsCString mName;
 
   NS_DECL_EVENT_HANDLER(enabled)
 
   nsCOMPtr<nsIEventTarget> mToggleBtThread;
 };
 
 END_BLUETOOTH_NAMESPACE
 
-nsresult NS_NewBluetoothManager(nsPIDOMWindow* aWindow, nsIDOMBluetoothManager** aBluetoothManager);
+nsresult NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
+                                nsIDOMBluetoothManager** aBluetoothManager);
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothUtils.h
@@ -0,0 +1,77 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothutils_h__
+#define mozilla_dom_bluetooth_bluetoothutils_h__
+
+#include "BluetoothCommon.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+/**
+ * BluetoothUtil functions are used to dispatch messages to Bluetooth DOM
+ * objects on the main thread, as well as provide platform indenpendent access
+ * to BT functionality. Tasks for polling for outside messages will usually
+ * happen on the IO Thread (see ipc/dbus for instance), and these messages will
+ * be encased in runnables that will then be distributed via observers managed
+ * here.
+ */
+
+/** 
+ * Add a message handler object from message distribution observer.
+ * Must be called from the main thread.
+ *
+ * @param aNodeName Node name of the object
+ * @param aMsgHandler Weak pointer to the object
+ *
+ * @return NS_OK on successful addition to observer, NS_ERROR_FAILED
+ * otherwise
+ */
+nsresult RegisterBluetoothEventHandler(const nsCString& aNodeName,
+                                       BluetoothEventObserver *aMsgHandler);
+
+/** 
+ * Remove a message handler object from message distribution observer.
+ * Must be called from the main thread.
+ *
+ * @param aNodeName Node name of the object
+ * @param aMsgHandler Weak pointer to the object
+ *
+ * @return NS_OK on successful removal from observer service,
+ * NS_ERROR_FAILED otherwise
+ */
+nsresult UnregisterBluetoothEventHandler(const nsCString& aNodeName,
+                                         BluetoothEventObserver *aMsgHandler);
+
+/** 
+ * Returns the path of the default adapter, implemented via a platform
+ * specific method.
+ *
+ * @return Default adapter path/name on success, NULL otherwise
+ */
+nsresult GetDefaultAdapterPathInternal(nsCString& aAdapterPath);
+
+/** 
+ * Set up variables and start the platform specific connection. Must
+ * be called from main thread.
+ *
+ * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
+ * otherwise
+ */
+nsresult StartBluetoothConnection();
+
+/** 
+ * Stop the platform specific connection. Must be called from main
+ * thread.
+ *
+ * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
+ * otherwise
+ */
+nsresult StopBluetoothConnection();
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -10,36 +10,46 @@ VPATH            = @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MODULE           = dom
 LIBRARY_NAME     = dombluetooth_s
 XPIDL_MODULE     = dom_bluetooth
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 
+ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
+VPATH += $(srcdir)/linux
+LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
+endif
+
+ifdef MOZ_ENABLE_DBUS
+VPATH += $(srcdir)/linux
+LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
+endif
+
 include $(topsrcdir)/dom/dom-config.mk
 
 CPPSRCS = \
   BluetoothManager.cpp \
   BluetoothAdapter.cpp \
   BluetoothFirmware.cpp \
   $(NULL)
 
+ifdef MOZ_ENABLE_DBUS
+CPPSRCS += BluetoothDBusUtils.cpp
+endif
+
+ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
+CPPSRCS += BluetoothDBusUtils.cpp
+endif
+
 XPIDLSRCS = \
   nsIDOMNavigatorBluetooth.idl \
   nsIDOMBluetoothManager.idl \
   nsIDOMBluetoothAdapter.idl \
   $(NULL)
 
-ifneq (gonk,$(MOZ_WIDGET_TOOLKIT))
-CFLAGS += $(MOZ_DBUS_CFLAGS)
-CXXFLAGS += $(MOZ_DBUS_CFLAGS) -DHAVE_PTHREADS
-endif
-
 include $(topsrcdir)/config/rules.mk
 
-ifeq (Linux,$(OS_TARGET))
 ifdef MOZ_ENABLE_DBUS
 CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
 CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
 endif
-endif
-
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/linux/BluetoothDBusUtils.cpp
@@ -0,0 +1,270 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "BluetoothUtils.h"
+
+#include <cstdio>
+#include <dbus/dbus.h>
+
+#include "nsAutoPtr.h"
+#include "nsThreadUtils.h"
+#include "nsDebug.h"
+#include "nsClassHashtable.h"
+#include "mozilla/ipc/DBusUtils.h"
+#include "mozilla/ipc/RawDBusConnection.h"
+
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+namespace dom {
+namespace bluetooth {
+
+static nsAutoPtr<RawDBusConnection> sDBusConnection;
+
+#undef LOG
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
+#else
+#define BTDEBUG true
+#define LOG(args...) if (BTDEBUG) printf(args);
+#endif
+
+#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
+#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
+#define BLUEZ_DBUS_BASE_PATH      "/org/bluez"
+#define BLUEZ_DBUS_BASE_IFC       "org.bluez"
+#define BLUEZ_ERROR_IFC           "org.bluez.Error"
+
+static const char* BLUETOOTH_DBUS_SIGNALS[] =
+{
+  "type='signal',interface='org.freedesktop.DBus'",
+  "type='signal',interface='org.bluez.Adapter'",
+  "type='signal',interface='org.bluez.Manager'",
+  "type='signal',interface='org.bluez.Device'",
+  "type='signal',interface='org.bluez.Input'",
+  "type='signal',interface='org.bluez.Network'",
+  "type='signal',interface='org.bluez.NetworkServer'",
+  "type='signal',interface='org.bluez.HealthDevice'",
+  "type='signal',interface='org.bluez.AudioSink'"
+};
+
+typedef nsClassHashtable<nsCStringHashKey, BluetoothEventObserverList >
+        BluetoothEventObserverTable;
+static nsAutoPtr<BluetoothEventObserverTable> sBluetoothEventObserverTable;
+
+nsresult
+RegisterBluetoothEventHandler(const nsCString& aNodeName,
+                              BluetoothEventObserver* aHandler)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  BluetoothEventObserverList *ol;
+  if (!sBluetoothEventObserverTable->Get(aNodeName, &ol)) {
+    sBluetoothEventObserverTable->Put(aNodeName,
+                                      new BluetoothEventObserverList());
+  }
+  sBluetoothEventObserverTable->Get(aNodeName, &ol);
+  ol->AddObserver(aHandler);
+  return NS_OK;
+}
+
+nsresult
+UnregisterBluetoothEventHandler(const nsCString& aNodeName,
+                                BluetoothEventObserver* aHandler)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  BluetoothEventObserverList *ol;
+  if (!sBluetoothEventObserverTable->Get(aNodeName, &ol)) {
+    NS_WARNING("Node does not exist to remove BluetoothEventListener from!");
+    return NS_ERROR_FAILURE;
+  }
+  sBluetoothEventObserverTable->Get(aNodeName, &ol);  
+  ol->RemoveObserver(aHandler);
+  if (ol->Length() == 0) {
+    sBluetoothEventObserverTable->Remove(aNodeName);
+  }
+  return NS_OK;
+}
+
+struct DistributeDBusMessageTask : public nsRunnable {
+
+  DistributeDBusMessageTask(DBusMessage* aMsg) : mMsg(aMsg)
+  {
+  }
+  
+  NS_IMETHOD Run()
+  {
+    if (dbus_message_get_path(mMsg.get()) == NULL) {
+      return NS_OK;
+    }    
+    MOZ_ASSERT(NS_IsMainThread());
+    
+    // Notify observers that a message has been sent
+    nsDependentCString path(dbus_message_get_path(mMsg.get()));
+    nsDependentCString member(dbus_message_get_member(mMsg.get()));
+    BluetoothEventObserverList *ol;
+    if (!sBluetoothEventObserverTable->Get(path, &ol)) {
+      LOG("No objects registered for %s, returning\n",
+          dbus_message_get_path(mMsg.get()));
+      return NS_OK;
+    }
+    BluetoothEvent e;
+    e.mEventName = member;
+    ol->Broadcast(e);
+    return NS_OK;
+  }
+
+  DBusMessageRefPtr mMsg;
+};
+
+// Called by dbus during WaitForAndDispatchEventNative()
+// This function is called on the IOThread
+static DBusHandlerResult
+EventFilter(DBusConnection *aConn, DBusMessage *aMsg,
+            void *aData)
+{
+  DBusError err;
+
+  dbus_error_init(&err);
+
+  if (dbus_message_get_type(aMsg) != DBUS_MESSAGE_TYPE_SIGNAL) {
+    LOG("%s: not interested (not a signal).\n", __FUNCTION__);
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  LOG("%s: Received signal %s:%s from %s\n", __FUNCTION__,
+      dbus_message_get_interface(aMsg), dbus_message_get_member(aMsg),
+      dbus_message_get_path(aMsg));
+
+  // TODO: Parse DBusMessage* on the IOThread and return as a BluetoothEvent so
+  // we aren't passing the pointer at all, as well as offloading parsing (not
+  // that it's that heavy.)
+  nsCOMPtr<DistributeDBusMessageTask> t(new DistributeDBusMessageTask(aMsg));
+  if (NS_FAILED(NS_DispatchToMainThread(t))) {
+    NS_WARNING("Failed to dispatch to main thread!");
+  }
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+nsresult
+StartBluetoothConnection()
+{
+  if(sDBusConnection) {
+    NS_WARNING("DBusConnection already established, skipping");
+    return NS_OK;    
+  }
+  sBluetoothEventObserverTable = new BluetoothEventObserverTable();
+  sBluetoothEventObserverTable->Init(100);
+
+  sDBusConnection = new RawDBusConnection();
+  sDBusConnection->EstablishDBusConnection();
+	
+  // Add a filter for all incoming messages_base
+  if (!dbus_connection_add_filter(sDBusConnection->mConnection, EventFilter,
+                                  NULL, NULL)) {
+    NS_WARNING("Cannot create DBus Event Filter for DBus Thread!");
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+StopBluetoothConnection()
+{
+  if(!sDBusConnection) {
+    NS_WARNING("DBusConnection does not exist, nothing to stop, skipping.");
+    return NS_OK;
+  }
+  dbus_connection_remove_filter(sDBusConnection->mConnection, EventFilter, NULL);
+  sDBusConnection = NULL;
+  sBluetoothEventObserverTable->Clear();
+  sBluetoothEventObserverTable = NULL;
+  return NS_OK;
+}
+
+nsresult
+GetDefaultAdapterPathInternal(nsCString& aAdapterPath)
+{
+  DBusMessage *msg = NULL, *reply = NULL;
+  DBusError err;
+  const char *device_path = NULL;
+  int attempt = 0;
+
+  for (attempt = 0; attempt < 1000 && reply == NULL; attempt ++) {
+    msg = dbus_message_new_method_call("org.bluez", "/",
+                                       "org.bluez.Manager", "DefaultAdapter");
+    if (!msg) {
+      LOG("%s: Can't allocate new method call for get_adapter_path!",
+             __FUNCTION__);
+      return NS_ERROR_FAILURE;
+    }
+    dbus_message_append_args(msg, DBUS_TYPE_INVALID);
+    dbus_error_init(&err);
+    reply = dbus_connection_send_with_reply_and_block(
+      sDBusConnection->mConnection, msg, -1, &err);
+
+    if (!reply) {
+      if (dbus_error_is_set(&err)) {
+        if (dbus_error_has_name(&err,
+                                "org.freedesktop.DBus.Error.ServiceUnknown")) {
+          // bluetoothd is still down, retry
+          LOG("Service unknown\n");
+          dbus_error_free(&err);
+          //usleep(10000); // 10 ms
+          continue;
+        } else if (dbus_error_has_name(&err,
+                                       "org.bluez.Error.NoSuchAdapter")) {
+          LOG("No adapter found\n");
+          dbus_error_free(&err);
+          goto failed;
+        } else {
+          // Some other error we weren't expecting
+          LOG("other error\n");
+          dbus_error_free(&err);
+        }
+      }
+    }
+  }
+  if (attempt == 1000) {
+    LOG("timeout\n");
+    //printfE("Time out while trying to get Adapter path, is bluetoothd up ?");
+    goto failed;
+  }
+
+  if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
+                             &device_path, DBUS_TYPE_INVALID)
+      || !device_path) {
+    if (dbus_error_is_set(&err)) {
+      dbus_error_free(&err);
+    }
+    goto failed;
+  }
+  dbus_message_unref(msg);
+  aAdapterPath = nsDependentCString(device_path);
+  return NS_OK;
+failed:
+  dbus_message_unref(msg);
+  return NS_ERROR_FAILURE;
+}
+
+}
+}
+}
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/dom/workers/Workers.h"
 #ifdef MOZ_WIDGET_GONK
 #include "AutoMounter.h"
 #endif
 #include "mozilla/ipc/Ril.h"
 #ifdef MOZ_B2G_BT
 #include "mozilla/ipc/DBusThread.h"
 #include "BluetoothFirmware.h"
+#include "BluetoothUtils.h"
 #endif
 #include "nsContentUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsRadioInterfaceLayer.h"
 #include "WifiWorker.h"
 
 #undef LOG
@@ -229,16 +230,17 @@ SystemWorkerManager::Init()
   }
 
 #ifdef MOZ_B2G_BT
   rv = InitBluetooth(cx);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to initialize Bluetooth!");
     return rv;
   }
+
 #endif
 
 #ifdef MOZ_WIDGET_GONK
   InitAutoMounter();
 #endif
 
   nsCOMPtr<nsIObserverService> obs =
     do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
@@ -390,16 +392,17 @@ SystemWorkerManager::InitBluetooth(JSCon
 #ifdef MOZ_WIDGET_GONK
   // We need a platform specific check here to make sure of when we're
   // running on an emulator. Therefore, if we're compiled with gonk,
   // see if we can load functions out of bluedroid. If not, assume
   // it's an emulator and don't start the bluetooth thread.
   if(EnsureBluetoothInit()) {
 #endif
     StartDBus();
+    StartBluetoothConnection();
 #ifdef MOZ_WIDGET_GONK
   }
   else {
     LOG("Bluedroid functions not available, assuming running on simulator. Not starting DBus thread.");
   }
 #endif
 #endif
   return NS_OK;
--- a/ipc/dbus/DBusThread.cpp
+++ b/ipc/dbus/DBusThread.cpp
@@ -40,28 +40,31 @@
 #include <unistd.h>
 #include <poll.h>
 
 #include <list>
 
 #include "base/eintr_wrapper.h"
 #include "base/message_loop.h"
 #include "nsTArray.h"
+#include "nsDataHashtable.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/Util.h"
 #include "mozilla/FileUtils.h"
-#include "nsAutoPtr.h"
+#include "nsThreadUtils.h"
 #include "nsIThread.h"
 #include "nsXULAppAPI.h"
+#include "nsServiceManagerUtils.h"
+#include "nsCOMPtr.h"
 
 #undef LOG
 #if defined(MOZ_WIDGET_GONK)
 #include <android/log.h>
-#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkBluetooth", args);
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
 #else
 #define BTDEBUG true
 #define LOG(args...) if(BTDEBUG) printf(args);
 #endif
 
 #define DEFAULT_INITIAL_POLLFD_COUNT 8
 
 // Functions for converting between unix events in the poll struct,
@@ -77,16 +80,17 @@ enum {
 
 // Signals that the DBus thread should listen for. Needs to include
 // all signals any DBus observer object may need.
 
 static const char* DBUS_SIGNALS[] =
 {
   "type='signal',interface='org.freedesktop.DBus'",
   "type='signal',interface='org.bluez.Adapter'",
+  "type='signal',interface='org.bluez.Manager'",
   "type='signal',interface='org.bluez.Device'",
   "type='signal',interface='org.bluez.Input'",
   "type='signal',interface='org.bluez.Network'",
   "type='signal',interface='org.bluez.NetworkServer'",
   "type='signal',interface='org.bluez.HealthDevice'",
   "type='signal',interface='org.bluez.AudioSink'"
 };
 
@@ -286,37 +290,16 @@ static void HandleWatchRemove(DBusThread
   }
   aDbt->mPollData.RemoveElementAt(index);
 
   // DBusWatch pointers are maintained by DBus, so we won't leak by
   // removing.
   aDbt->mWatchData.RemoveElementAt(index);
 }
 
-// Called by dbus during WaitForAndDispatchEventNative()
-static DBusHandlerResult
-EventFilter(DBusConnection *aConn, DBusMessage *aMsg,
-            void *aData)
-{
-  DBusError err;
-
-  dbus_error_init(&err);
-
-  if (dbus_message_get_type(aMsg) != DBUS_MESSAGE_TYPE_SIGNAL) {
-    LOG("%s: not interested (not a signal).\n", __FUNCTION__);
-    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-  }
-
-  LOG("%s: Received signal %s:%s from %s\n", __FUNCTION__,
-      dbus_message_get_interface(aMsg), dbus_message_get_member(aMsg),
-      dbus_message_get_path(aMsg));
-
-  return DBUS_HANDLER_RESULT_HANDLED;
-}
-
 // DBus Thread Implementation
 
 DBusThread::DBusThread() : mMutex("DBusGonk.mMutex")
                          , mIsRunning(false)
 {
 }
 
 DBusThread::~DBusThread()
@@ -332,22 +315,19 @@ DBusThread::SetUpEventLoop()
     return false;
   }
 
   dbus_threads_init_default();
   DBusError err;
   dbus_error_init(&err);
 
   // If we can't establish a connection to dbus, nothing else will work
-  if(!Create()) {
-    return false;
-  }
-
-  // Add a filter for all incoming messages_base
-  if (!dbus_connection_add_filter(mConnection, EventFilter, this, NULL)){
+  nsresult rv = EstablishDBusConnection();
+  if(NS_FAILED(rv)) {
+    NS_WARNING("Cannot create DBus Connection for DBus Thread!");
     return false;
   }
 
   // Set which messages will be processed by this dbus connection.
   // Since we are maintaining a single thread for all the DBus bluez
   // signals we want, register all of them in this thread at startup.
   // The event handler will sort the destinations out as needed.
   for(uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
@@ -360,17 +340,17 @@ DBusThread::SetUpEventLoop()
     }
   }
   return true;
 }
 
 bool
 DBusThread::TearDownData()
 {
-  LOG("Removing DBus Bluetooth Sockets\n");
+  LOG("Removing DBus Sockets\n");
   if (mControlFdW.get()) {
     mControlFdW.dispose();
   }
   if (mControlFdR.get()) {
     mControlFdR.dispose();
   }
   mPollData.Clear();
 
@@ -392,47 +372,46 @@ DBusThread::TearDownEventLoop()
     dbus_bus_remove_match(mConnection,
                           DBUS_SIGNALS[i],
                           &err);
     if (dbus_error_is_set(&err)) {
       LOG_AND_FREE_DBUS_ERROR(&err);
     }
   }
 
-  dbus_connection_remove_filter(mConnection, EventFilter, this);
   return true;
 }
 
 void*
 DBusThread::EventLoop(void *aPtr)
 {
   DBusThread* dbt = static_cast<DBusThread*>(aPtr);
   MOZ_ASSERT(dbt);
 
   dbus_connection_set_watch_functions(dbt->mConnection, AddWatch,
                                       RemoveWatch, ToggleWatch, aPtr, NULL);
 
   dbt->mIsRunning = true;
-  LOG("DBus Bluetooth Event Loop Starting\n");
+  LOG("DBus Event Loop Starting\n");
   while (1) {
     poll(dbt->mPollData.Elements(), dbt->mPollData.Length(), -1);
 
     for (uint32_t i = 0; i < dbt->mPollData.Length(); i++) {
       if (!dbt->mPollData[i].revents) {
         continue;
       }
 
       if (dbt->mPollData[i].fd == dbt->mControlFdR.get()) {
         char data;
         while (recv(dbt->mControlFdR.get(), &data, sizeof(char), MSG_DONTWAIT)
                != -1) {
           switch (data) {
           case DBUS_EVENT_LOOP_EXIT:
           {
-            LOG("DBus Bluetooth Event Loop Exiting\n");
+            LOG("DBus Event Loop Exiting\n");
             dbus_connection_set_watch_functions(dbt->mConnection,
                                                 NULL, NULL, NULL, NULL, NULL);
             dbt->TearDownEventLoop();
             return NULL;
           }
           case DBUS_EVENT_LOOP_ADD:
           {
             HandleWatchAdd(dbt);
@@ -490,35 +469,35 @@ DBusThread::StartEventLoop()
   // push a null to the front of mWatchData since it has the control
   // fd in the first slot of mPollData.
 
   mWatchData.AppendElement((DBusWatch*)NULL);
   if (!SetUpEventLoop()) {
     TearDownData();
     return false;
   }
-  LOG("DBus Bluetooth Thread Starting\n");
+  LOG("DBus Thread Starting\n");
   pthread_create(&(mThread), NULL, DBusThread::EventLoop, this);
   return true;
 }
 
 void
 DBusThread::StopEventLoop()
 {
   MutexAutoLock lock(mMutex);
   if (mIsRunning) {
     char data = DBUS_EVENT_LOOP_EXIT;
     ssize_t wret = write(mControlFdW.get(), &data, sizeof(char));
     if(wret < 0) {
-      LOG("Cannot write exit bit to DBus Bluetooth Thread!\n");
+      LOG("Cannot write exit bit to DBus Thread!\n");
     }
     void *ret;
-    LOG("DBus Bluetooth Thread Joining\n");
+    LOG("DBus Thread Joining\n");
     pthread_join(mThread, &ret);
-    LOG("DBus Bluetooth Thread Joined\n");
+    LOG("DBus Thread Joined\n");
     TearDownData();
   }
   mIsRunning = false;
 }
 
 bool
 DBusThread::IsEventLoopRunning()
 {
@@ -530,16 +509,17 @@ DBusThread::IsEventLoopRunning()
 
 static void
 ConnectDBus(Monitor* aMonitor, bool* aSuccess)
 {
   if(sDBusThread) {
     NS_WARNING("Trying to start DBus Thread that is already currently running, skipping.");
     return;
   }
+
   sDBusThread = new DBusThread();
   *aSuccess = true;
   if(!sDBusThread->StartEventLoop())
   {
     *aSuccess = false;
   }
   {
     MonitorAutoLock lock(*aMonitor);
@@ -549,16 +529,17 @@ ConnectDBus(Monitor* aMonitor, bool* aSu
 
 static void
 DisconnectDBus(Monitor* aMonitor, bool* aSuccess)
 {
   if(!sDBusThread) {
     NS_WARNING("Trying to shutdown DBus Thread that is not currently running, skipping.");
     return;
   }
+
   *aSuccess = true;
   sDBusThread->StopEventLoop();
   sDBusThread = NULL;
   {
     MonitorAutoLock lock(*aMonitor);
     lock.Notify();
   }
 }
--- a/ipc/dbus/DBusThread.h
+++ b/ipc/dbus/DBusThread.h
@@ -2,24 +2,36 @@
 /* vim: set ts=2 et sw=2 tw=40: */
 /* 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/. */
 
 #ifndef mozilla_ipc_dbus_gonk_dbusthread_h__
 #define mozilla_ipc_dbus_gonk_dbusthread_h__
 
+struct DBusMessage;
+
 namespace mozilla {
 namespace ipc {
 
+class nsCString;
 
-// Starts the DBus thread, which handles returning signals to objects
-// that call asynchronous functions. This should be called from the
-// main thread at startup.
+/** 
+ * Starts the DBus thread, which handles returning signals to objects
+ * that call asynchronous functions. This should be called from the
+ * main thread at startup.
+ *
+ * @return True on thread starting correctly, false otherwise
+ */
 bool StartDBus();
 
-// Stop the DBus thread, assuming it's currently running. Should be
-// called from main thread.
+/** 
+ * Stop the DBus thread, assuming it's currently running. Should be
+ * called from main thread.
+ *
+ * @return True on thread stopping correctly, false otherwise
+ */
 bool StopDBus();
+
 }
 }
 #endif
 
--- a/ipc/dbus/DBusUtils.cpp
+++ b/ipc/dbus/DBusUtils.cpp
@@ -11,37 +11,253 @@
 **
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
-#include <stdio.h>
-#include "dbus/dbus.h"
+#include "DBusUtils.h"
+#include <cstdio>
+#include <cstring>
 
 #undef LOG
 #if defined(MOZ_WIDGET_GONK)
 #include <android/log.h>
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args);
 #else
 #define LOG(args...)  printf(args);
 #endif
 
+#define BLUEZ_DBUS_BASE_PATH      "/org/bluez"
+#define BLUEZ_DBUS_BASE_IFC       "org.bluez"
+#define BLUEZ_ERROR_IFC           "org.bluez.Error"
+
 namespace mozilla {
 namespace ipc {
 
 void
 log_and_free_dbus_error(DBusError* err, const char* function, DBusMessage* msg)
 {
   if(msg) {
     LOG("%s: D-Bus error in %s: %s (%s)", function,
         dbus_message_get_member((msg)), (err)->name, (err)->message);
   }	else {
     LOG("%s: D-Bus error: %s (%s)", __FUNCTION__,
         (err)->name, (err)->message);
   }
   dbus_error_free((err));
 }
 
+typedef struct {
+  void (*user_cb)(DBusMessage *, void *, void *);
+  void *user;
+  void *nat;
+} dbus_async_call_t;
+
+void dbus_func_args_async_callback(DBusPendingCall *call, void *data) {
+
+  dbus_async_call_t *req = (dbus_async_call_t *)data;
+  DBusMessage *msg;
+
+  /* This is guaranteed to be non-NULL, because this function is called only
+     when once the remote method invokation returns. */
+  msg = dbus_pending_call_steal_reply(call);
+
+  if (msg) {
+    if (req->user_cb) {
+      // The user may not deref the message object.
+      req->user_cb(msg, req->user, req->nat);
+    }
+    dbus_message_unref(msg);
+  }
+
+  //dbus_message_unref(req->method);
+  dbus_pending_call_cancel(call);
+  dbus_pending_call_unref(call);
+  free(req);
+}
+
+static dbus_bool_t dbus_func_args_async_valist(DBusConnection *conn,
+                                               int timeout_ms,
+                                               void (*user_cb)(DBusMessage *,
+                                                               void *,
+                                                               void*),
+                                               void *user,
+                                               void *nat,
+                                               const char *path,
+                                               const char *ifc,
+                                               const char *func,
+                                               int first_arg_type,
+                                               va_list args) {
+  DBusMessage *msg = NULL;
+  const char *name;
+  dbus_async_call_t *pending;
+  dbus_bool_t reply = FALSE;
+
+  /* Compose the command */
+  msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
+
+  if (msg == NULL) {
+    LOG("Could not allocate D-Bus message object!");
+    goto done;
+  }
+
+  /* append arguments */
+  if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
+    LOG("Could not append argument to method call!");
+    goto done;
+  }
+
+  /* Make the call. */
+  pending = (dbus_async_call_t *)malloc(sizeof(dbus_async_call_t));
+  if (pending) {
+    DBusPendingCall *call;
+
+    pending->user_cb = user_cb;
+    pending->user = user;
+    pending->nat = nat;
+    //pending->method = msg;
+
+    reply = dbus_connection_send_with_reply(conn, msg,
+                                            &call,
+                                            timeout_ms);
+    if (reply == TRUE) {
+      dbus_pending_call_set_notify(call,
+                                   dbus_func_args_async_callback,
+                                   pending,
+                                   NULL);
+    }
+  }
+
+done:
+  if (msg) dbus_message_unref(msg);
+  return reply;
+}
+
+dbus_bool_t dbus_func_args_async(DBusConnection *conn,
+                                 int timeout_ms,
+                                 void (*reply)(DBusMessage *, void *, void*),
+                                 void *user,
+                                 void *nat,
+                                 const char *path,
+                                 const char *ifc,
+                                 const char *func,
+                                 int first_arg_type,
+                                 ...) {
+  dbus_bool_t ret;
+  va_list lst;
+  va_start(lst, first_arg_type);
+
+  ret = dbus_func_args_async_valist(conn,
+                                    timeout_ms,
+                                    reply, user, nat,
+                                    path, ifc, func,
+                                    first_arg_type, lst);
+  va_end(lst);
+  return ret;
+}
+
+// If err is NULL, then any errors will be LOG'd, and free'd and the reply
+// will be NULL.
+// If err is not NULL, then it is assumed that dbus_error_init was already
+// called, and error's will be returned to the caller without logging. The
+// return value is NULL iff an error was set. The client must free the error if
+// set.
+DBusMessage * dbus_func_args_timeout_valist(DBusConnection *conn,
+                                            int timeout_ms,
+                                            DBusError *err,
+                                            const char *path,
+                                            const char *ifc,
+                                            const char *func,
+                                            int first_arg_type,
+                                            va_list args) {
+  
+  DBusMessage *msg = NULL, *reply = NULL;
+  const char *name;
+  bool return_error = (err != NULL);
+
+  if (!return_error) {
+    err = (DBusError*)malloc(sizeof(DBusError));
+    dbus_error_init(err);
+  }
+
+  /* Compose the command */
+  msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
+
+  if (msg == NULL) {
+    LOG("Could not allocate D-Bus message object!");
+    goto done;
+  }
+
+  /* append arguments */
+  if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
+    LOG("Could not append argument to method call!");
+    goto done;
+  }
+
+  /* Make the call. */
+  reply = dbus_connection_send_with_reply_and_block(conn, msg, timeout_ms, err);
+  if (!return_error && dbus_error_is_set(err)) {
+    //LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg);
+  }
+
+done:
+  if (!return_error) {
+    free(err);
+  }
+  if (msg) dbus_message_unref(msg);
+  return reply;
+}
+
+DBusMessage * dbus_func_args_timeout(DBusConnection *conn,
+                                     int timeout_ms,
+                                     const char *path,
+                                     const char *ifc,
+                                     const char *func,
+                                     int first_arg_type,
+                                     ...) {
+  DBusMessage *ret;
+  va_list lst;
+  va_start(lst, first_arg_type);
+  ret = dbus_func_args_timeout_valist(conn, timeout_ms, NULL,
+                                      path, ifc, func,
+                                      first_arg_type, lst);
+  va_end(lst);
+  return ret;
+}
+
+DBusMessage * dbus_func_args(DBusConnection *conn,
+                             const char *path,
+                             const char *ifc,
+                             const char *func,
+                             int first_arg_type,
+                             ...) {
+  DBusMessage *ret;
+  va_list lst;
+  va_start(lst, first_arg_type);
+  ret = dbus_func_args_timeout_valist(conn, -1, NULL,
+                                      path, ifc, func,
+                                      first_arg_type, lst);
+  va_end(lst);
+  return ret;
+}
+
+DBusMessage * dbus_func_args_error(DBusConnection *conn,
+                                   DBusError *err,
+                                   const char *path,
+                                   const char *ifc,
+                                   const char *func,
+                                   int first_arg_type,
+                                   ...) {
+  DBusMessage *ret;
+  va_list lst;
+  va_start(lst, first_arg_type);
+  ret = dbus_func_args_timeout_valist(conn, -1, err,
+                                      path, ifc, func,
+                                      first_arg_type, lst);
+  va_end(lst);
+  return ret;
+}
+
 }
 }
--- a/ipc/dbus/DBusUtils.h
+++ b/ipc/dbus/DBusUtils.h
@@ -14,24 +14,91 @@
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 #ifndef mozilla_ipc_dbus_dbusutils_h__
 #define mozilla_ipc_dbus_dbusutils_h__
 
+#include <dbus/dbus.h>
+#include "mozilla/Scoped.h"
+
 // LOGE and free a D-Bus error
 // Using #define so that __FUNCTION__ resolves usefully
 #define LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg) log_and_free_dbus_error(err, __FUNCTION__, msg);
 #define LOG_AND_FREE_DBUS_ERROR(err) log_and_free_dbus_error(err, __FUNCTION__);
 
 struct DBusMessage;
 struct DBusError;
 
 namespace mozilla {
 namespace ipc {
-void log_and_free_dbus_error(DBusError* err, const char* function, DBusMessage* msg = NULL);
+
+class DBusMessageRefPtr
+{
+public:
+  DBusMessageRefPtr(DBusMessage* aMsg) : mMsg(aMsg)
+  {
+    if (mMsg) dbus_message_ref(mMsg);
+  }
+  ~DBusMessageRefPtr()
+  {
+    if (mMsg) dbus_message_unref(mMsg);
+  }
+  operator DBusMessage*() { return mMsg; }
+  DBusMessage* get() { return mMsg; }
+private:
+  DBusMessage* mMsg;
+};
+
+void log_and_free_dbus_error(DBusError* err,
+                             const char* function,
+                             DBusMessage* msg = NULL);
+dbus_bool_t dbus_func_args_async(DBusConnection *conn,
+                                 int timeout_ms,
+                                 void (*reply)(DBusMessage *, void *, void *),
+                                 void *user,
+                                 void *nat,
+                                 const char *path,
+                                 const char *ifc,
+                                 const char *func,
+                                 int first_arg_type,
+                                 ...);
+
+DBusMessage * dbus_func_args(DBusConnection *conn,
+                             const char *path,
+                             const char *ifc,
+                             const char *func,
+                             int first_arg_type,
+                             ...);
+
+DBusMessage * dbus_func_args_error(DBusConnection *conn,
+                                   DBusError *err,
+                                   const char *path,
+                                   const char *ifc,
+                                   const char *func,
+                                   int first_arg_type,
+                                   ...);
+
+DBusMessage * dbus_func_args_timeout(DBusConnection *conn,
+                                     int timeout_ms,
+                                     const char *path,
+                                     const char *ifc,
+                                     const char *func,
+                                     int first_arg_type,
+                                     ...);
+
+DBusMessage * dbus_func_args_timeout_valist(DBusConnection *conn,
+                                            int timeout_ms,
+                                            DBusError *err,
+                                            const char *path,
+                                            const char *ifc,
+                                            const char *func,
+                                            int first_arg_type,
+                                            va_list args);
+
+
 }
 }
 
 #endif
 
--- a/ipc/dbus/RawDBusConnection.cpp
+++ b/ipc/dbus/RawDBusConnection.cpp
@@ -10,20 +10,24 @@
 using namespace mozilla::ipc;
 
 RawDBusConnection::RawDBusConnection() {
 }
 
 RawDBusConnection::~RawDBusConnection() {
 }
 
-bool RawDBusConnection::Create() {
+nsresult RawDBusConnection::EstablishDBusConnection() {
   DBusError err;
   dbus_error_init(&err);
   mConnection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
   if (dbus_error_is_set(&err)) {
     dbus_error_free(&err);
-    return false;
+    return NS_ERROR_FAILURE;
   }
   dbus_connection_set_exit_on_disconnect(mConnection, FALSE);
-  return true;
+  return NS_OK;
 }
 
+void RawDBusConnection::ScopedDBusConnectionPtrTraits::release(DBusConnection* ptr)
+{
+  if(ptr) dbus_connection_unref(ptr);
+}
--- a/ipc/dbus/RawDBusConnection.h
+++ b/ipc/dbus/RawDBusConnection.h
@@ -7,35 +7,34 @@
 #ifndef mozilla_ipc_dbus_gonk_rawdbusconnection_h__
 #define mozilla_ipc_dbus_gonk_rawdbusconnection_h__
 
 #include <string.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string>
 #include <stdlib.h>
+#include "nscore.h"
 #include "mozilla/Scoped.h"
-#include "dbus/dbus.h"
 
 struct DBusConnection;
 
 namespace mozilla {
 namespace ipc {
 
 class RawDBusConnection
 {
   struct ScopedDBusConnectionPtrTraits : ScopedFreePtrTraits<DBusConnection>
   {
-    static void release(DBusConnection* ptr) { if(ptr) dbus_connection_unref(ptr); }
+    static void release(DBusConnection* ptr);
   };
 
 public:
   RawDBusConnection();
   ~RawDBusConnection();
-  bool Create();
-protected:
+  nsresult EstablishDBusConnection();
   Scoped<ScopedDBusConnectionPtrTraits> mConnection;
 };
 
 }
 }
 
 #endif