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 id22826
push userphilringnalda@gmail.com
push dateSun, 03 Jun 2012 19:07:58 +0000
treeherdermozilla-central@07d362aa2c1b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs744349
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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