Bug 740744: Asynchronous dbus events for bluetooth, Start/StopDiscovery and device event firing; r=bent sr=mrbkap
authorKyle Machulis <kyle@nonpolynomial.com>
Tue, 17 Jul 2012 20:41:54 -0700
changeset 99627 b1bab07e4390fa5ab6e2a4163b3cf081ebdd9f08
parent 99626 1dfcb36d7c176f9f9e88a128889e0ae48da482e7
child 99628 486769aaada148702503ef3b1d91a5c2a20793da
push id932
push userttaubert@mozilla.com
push dateThu, 19 Jul 2012 14:38:53 +0000
treeherderfx-team@01929e390ba5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent, mrbkap
bugs740744
milestone17.0a1
Bug 740744: Asynchronous dbus events for bluetooth, Start/StopDiscovery and device event firing; r=bent sr=mrbkap
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothAdapter.h
dom/bluetooth/BluetoothCommon.h
dom/bluetooth/BluetoothDevice.cpp
dom/bluetooth/BluetoothDevice.h
dom/bluetooth/BluetoothDeviceEvent.cpp
dom/bluetooth/BluetoothDeviceEvent.h
dom/bluetooth/BluetoothFirmware.cpp
dom/bluetooth/BluetoothFirmware.h
dom/bluetooth/BluetoothManager.cpp
dom/bluetooth/BluetoothManager.h
dom/bluetooth/BluetoothNullServiceFactory.cpp
dom/bluetooth/BluetoothReplyRunnable.cpp
dom/bluetooth/BluetoothReplyRunnable.h
dom/bluetooth/BluetoothService.cpp
dom/bluetooth/BluetoothService.h
dom/bluetooth/BluetoothUtils.h
dom/bluetooth/Makefile.in
dom/bluetooth/gonk/BluetoothGonkService.cpp
dom/bluetooth/gonk/BluetoothGonkService.h
dom/bluetooth/gonk/BluetoothGonkServiceFactory.cpp
dom/bluetooth/ipc/BluetoothTypes.ipdlh
dom/bluetooth/ipc/ipdl.mk
dom/bluetooth/linux/BluetoothDBusService.cpp
dom/bluetooth/linux/BluetoothDBusService.h
dom/bluetooth/linux/BluetoothDBusServiceFactory.cpp
dom/bluetooth/nsIDOMBluetoothAdapter.idl
dom/bluetooth/nsIDOMBluetoothDevice.idl
dom/bluetooth/nsIDOMBluetoothDeviceEvent.idl
dom/bluetooth/nsIDOMBluetoothManager.idl
dom/system/gonk/SystemWorkerManager.cpp
dom/system/gonk/SystemWorkerManager.h
ipc/dbus/DBusThread.cpp
ipc/dbus/DBusUtils.cpp
ipc/dbus/DBusUtils.h
ipc/dbus/RawDBusConnection.cpp
ipc/ipdl/Makefile.in
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -512,16 +512,18 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "Telephony.h"
 #include "TelephonyCall.h"
 #include "CallEvent.h"
 #endif
 
 #ifdef MOZ_B2G_BT
 #include "BluetoothManager.h"
 #include "BluetoothAdapter.h"
+#include "BluetoothDevice.h"
+#include "BluetoothDeviceEvent.h"
 #endif
 
 #include "nsIDOMNavigatorSystemMessages.h"
 
 #include "DOMError.h"
 #include "DOMRequest.h"
 #include "nsIOpenWindowEventDetail.h"
 #include "nsIDOMGlobalObjectConstructor.h"
@@ -1666,17 +1668,21 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(CallEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
 #ifdef MOZ_B2G_BT
   NS_DEFINE_CLASSINFO_DATA(BluetoothManager, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsEventTargetSH,
+                           EVENTTARGET_SCRIPTABLE_FLAGS)  
+  NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(BluetoothDeviceEvent, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DOMRequest, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(OpenWindowEventDetail, nsDOMGenericSH,
@@ -4479,16 +4485,25 @@ nsDOMClassInfo::Init()
 #ifdef MOZ_B2G_BT
   DOM_CLASSINFO_MAP_BEGIN(BluetoothManager, nsIDOMBluetoothManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothManager)
   DOM_CLASSINFO_MAP_END  
 
   DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
   DOM_CLASSINFO_MAP_END
+    
+  DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(BluetoothDeviceEvent, nsIDOMBluetoothDeviceEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDeviceEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
+  DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN(DOMError, nsIDOMDOMError)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DOMRequest, nsIDOMDOMRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -523,16 +523,18 @@ DOMCI_CLASS(MozWifiConnectionInfoEvent)
 DOMCI_CLASS(Telephony)
 DOMCI_CLASS(TelephonyCall)
 DOMCI_CLASS(CallEvent)
 #endif
 
 #ifdef MOZ_B2G_BT
 DOMCI_CLASS(BluetoothManager)
 DOMCI_CLASS(BluetoothAdapter)
+DOMCI_CLASS(BluetoothDevice)
+DOMCI_CLASS(BluetoothDeviceEvent)
 #endif
 
 DOMCI_CLASS(DOMError)
 DOMCI_CLASS(DOMRequest)
 DOMCI_CLASS(OpenWindowEventDetail)
 
 DOMCI_CLASS(DOMFileHandle)
 DOMCI_CLASS(FileRequest)
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -1,64 +1,277 @@
 /* -*- 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 "base/basictypes.h"
 #include "BluetoothAdapter.h"
-#include "BluetoothUtils.h"
+#include "BluetoothDevice.h"
+#include "BluetoothDeviceEvent.h"
+#include "BluetoothService.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
 
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
+#include "nsIDOMDOMRequest.h"
+
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
 
+using namespace mozilla;
+
 USING_BLUETOOTH_NAMESPACE
 
 DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter, 
                                                   nsDOMEventTargetHelper)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(devicefound)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(devicedisappeared)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)  
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter, 
                                                 nsDOMEventTargetHelper)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(devicefound)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(devicedisappeared)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)  
 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)
+class GetPropertiesTask : public BluetoothReplyRunnable
 {
-}
+public:
+  GetPropertiesTask(BluetoothAdapter* aAdapter, nsIDOMDOMRequest* aReq) :
+    BluetoothReplyRunnable(aReq),
+    mAdapterPtr(aAdapter)
+  {
+  }
+
+  bool
+  ParseSuccessfulReply(jsval* aValue)
+  {
+    const InfallibleTArray<BluetoothNamedValue>& values =
+      mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue();
+    for (uint32_t i = 0; i < values.Length(); ++i) {
+      mAdapterPtr->SetPropertyByValue(values[i]);
+    }
+    *aValue = JSVAL_VOID;
+    return true;
+  }
+
+  void
+  ReleaseMembers()
+  {
+    BluetoothReplyRunnable::ReleaseMembers();
+    mAdapterPtr = nsnull;
+  }
+private:
+  nsRefPtr<BluetoothAdapter> mAdapterPtr;
+};
 
 BluetoothAdapter::~BluetoothAdapter()
 {
-  if (NS_FAILED(UnregisterBluetoothEventHandler(mName, this))) {
-    NS_WARNING("Failed to unregister object with observer!");
+  BluetoothService* bs = BluetoothService::Get();
+  // We can be null on shutdown, where this might happen
+  if (bs) {
+    if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mPath, this))) {
+      NS_WARNING("Failed to unregister object with observer!");
+    }
+  }
+}
+
+void
+BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
+{
+  const nsString& name = aValue.name();
+  const BluetoothValue& value = aValue.value();
+  if (name.EqualsLiteral("Name")) {
+    mName = value.get_nsString();
+  } else if (name.EqualsLiteral("Address")) {
+    mAddress = value.get_nsString();
+  } else if (name.EqualsLiteral("Enabled")) {
+    mEnabled = value.get_bool();
+  } else if (name.EqualsLiteral("Discoverable")) {
+    mDiscoverable = value.get_bool();
+  } else if (name.EqualsLiteral("Pairable")) {
+    mPairable = value.get_bool();
+  } else if (name.EqualsLiteral("Powered")) {
+    mPowered = value.get_bool();
+  } else if (name.EqualsLiteral("PairableTimeout")) {
+    mPairableTimeout = value.get_uint32_t();
+  } else if (name.EqualsLiteral("DiscoverableTimeout")) {
+    mDiscoverableTimeout = value.get_uint32_t();
+  } else if (name.EqualsLiteral("Class")) {
+    mClass = value.get_uint32_t();
+  } else if (name.EqualsLiteral("UUIDs")) {
+    mUuids = value.get_ArrayOfnsString();
+  } else {
+#ifdef DEBUG
+    nsCString warningMsg;
+    warningMsg.AssignLiteral("Not handling adapter property: ");
+    warningMsg.Append(NS_ConvertUTF16toUTF8(name));
+    NS_WARNING(warningMsg.get());
+#endif
   }
 }
 
 // static
 already_AddRefed<BluetoothAdapter>
-BluetoothAdapter::Create(const nsCString& name) {
-  nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(name);
-  if (NS_FAILED(RegisterBluetoothEventHandler(name, adapter))) {
+BluetoothAdapter::Create(nsPIDOMWindow* aOwner, const nsAString& aPath)
+{
+  // Make sure we at least have a path
+  NS_ASSERTION(!aPath.IsEmpty(), "Adapter created with empty path!");
+    
+  BluetoothService* bs = BluetoothService::Get();
+  MOZ_ASSERT(bs);
+
+  nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aPath);
+  adapter->BindToOwner(aOwner);
+  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(aPath, adapter))) {
     NS_WARNING("Failed to register object with observer!");
-    return NULL;
+    return nsnull;
   }
   return adapter.forget();
 }
 
-void BluetoothAdapter::Notify(const BluetoothEvent& aData) {
-  printf("Got an adapter message!\n");
+void
+BluetoothAdapter::Notify(const BluetoothSignal& aData)
+{
+  if (aData.name().EqualsLiteral("DeviceFound")) {
+    nsRefPtr<BluetoothDevice> d = BluetoothDevice::Create(GetOwner(), aData);
+    nsRefPtr<BluetoothDeviceEvent> e = BluetoothDeviceEvent::Create(d);
+    e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("devicefound"));
+  } else {
+#ifdef DEBUG
+    nsCString warningMsg;
+    warningMsg.AssignLiteral("Not handling manager signal: ");
+    warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
+    NS_WARNING(warningMsg.get());
+#endif
+  }
+}
+
+nsresult
+BluetoothAdapter::StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest)
+{
+  BluetoothService* bs = BluetoothService::Get();
+  MOZ_ASSERT(bs);
+
+  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+    
+  if (!rs) {
+    NS_WARNING("No DOMRequest Service!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create DOMRequest!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
+
+  if (aStart) {
+    rv = bs->StartDiscoveryInternal(mPath, results);
+  } else {
+    rv = bs->StopDiscoveryInternal(mPath, results);
+  }
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Starting discovery failed!");
+    return NS_ERROR_FAILURE;
+  }
+
+  req.forget(aRequest);
+  
+  // mDiscovering is not set here, we'll get a Property update from our external
+  // protocol to tell us that it's been set.
+  
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::StartDiscovery(nsIDOMDOMRequest** aRequest)
+{
+  return StartStopDiscovery(true, aRequest);
 }
+
+NS_IMETHODIMP
+BluetoothAdapter::StopDiscovery(nsIDOMDOMRequest** aRequest)
+{
+  return StartStopDiscovery(false, aRequest);
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetEnabled(bool* aEnabled)
+{
+  *aEnabled = mEnabled;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetAddress(nsAString& aAddress)
+{
+  aAddress = mAddress;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetAdapterClass(PRUint32* aClass)
+{
+  *aClass = mClass;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetDiscovering(bool* aDiscovering)
+{
+  *aDiscovering = mDiscovering;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetName(nsAString& aName)
+{
+  aName = mName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetDiscoverable(bool* aDiscoverable)
+{
+  *aDiscoverable = mDiscoverable;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetDiscoverableTimeout(PRUint32* aDiscoverableTimeout)
+{
+  *aDiscoverableTimeout = mDiscoverableTimeout;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothAdapter::GetDevices(JSContext* aCx, jsval* aDevices)
+{
+  NS_WARNING("GetDevices not yet implemented.");
+  return NS_OK;
+}
+
+NS_IMPL_EVENT_HANDLER(BluetoothAdapter, propertychanged)
+NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicefound)
+NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicedisappeared)
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -3,45 +3,86 @@
 /* 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_bluetoothadapter_h__
 #define mozilla_dom_bluetooth_bluetoothadapter_h__
 
 #include "BluetoothCommon.h"
+#include "nsCOMPtr.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMBluetoothAdapter.h"
-#include "nsIDOMDOMRequest.h"
-#include "mozilla/Observer.h"
 
 class nsIEventTarget;
+class nsIDOMDOMRequest;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
+class BluetoothSignal;
+class BluetoothNamedValue;
+
 class BluetoothAdapter : public nsDOMEventTargetHelper
                        , public nsIDOMBluetoothAdapter
-                       , public BluetoothEventObserver
+                       , public BluetoothSignalObserver
 {
 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(nsPIDOMWindow* aOwner, const nsAString& name);
 
-  static already_AddRefed<BluetoothAdapter>
-  Create(const nsCString& name);
+  void Notify(const BluetoothSignal& aParam);
+
+  nsIDOMEventTarget*
+  ToIDOMEventTarget() const
+  {
+    return static_cast<nsDOMEventTargetHelper*>(
+      const_cast<BluetoothAdapter*>(this));
+  }
+
+  nsISupports*
+  ToISupports() const
+  {
+    return ToIDOMEventTarget();
+  }
 
-  void Notify(const BluetoothEvent& aParam);
-protected:
-  nsCString mName;
+  nsresult GetProperties();
+  void SetPropertyByValue(const BluetoothNamedValue& aValue);  
 private:
-  BluetoothAdapter() {}
-  BluetoothAdapter(const nsCString& name);
+  
+  BluetoothAdapter(const nsAString& aPath) : mPath(aPath)
+  {
+  }
+
   ~BluetoothAdapter();
+
+  nsresult SetProperty(const BluetoothNamedValue& aValue,
+                       nsIDOMDOMRequest** aRequest);
+  nsresult StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest);
+  
+  nsString mAddress;
+  nsString mName;
+  nsString mPath;
+  bool mEnabled;
+  bool mDiscoverable;
+  bool mDiscovering;
+  bool mPairable;
+  bool mPowered;
+  PRUint32 mPairableTimeout;
+  PRUint32 mDiscoverableTimeout;
+  PRUint32 mClass;
+  nsTArray<nsString> mDeviceAddresses;
+  nsTArray<nsString> mUuids;
+
+  NS_DECL_EVENT_HANDLER(propertychanged)
+  NS_DECL_EVENT_HANDLER(devicefound)
+  NS_DECL_EVENT_HANDLER(devicedisappeared)
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -17,49 +17,14 @@
   } /* namespace bluetooth */ } /* namespace dom */ } /* namespace mozilla */
 #define USING_BLUETOOTH_NAMESPACE \
   using namespace mozilla::dom::bluetooth;
 
 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;
+class BluetoothSignal;
+typedef mozilla::Observer<BluetoothSignal> BluetoothSignalObserver;
 
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluetoothcommon_h__
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -0,0 +1,117 @@
+/* -*- 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 "base/basictypes.h"
+#include "BluetoothDevice.h"
+#include "BluetoothTypes.h"
+
+#include "nsDOMClassInfo.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+DOMCI_DATA(BluetoothDevice, BluetoothDevice)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDevice)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice, 
+                                                  nsDOMEventTargetHelper)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)  
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice, 
+                                                nsDOMEventTargetHelper)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)  
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothDevice)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothDevice)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
+
+BluetoothDevice::BluetoothDevice(const BluetoothSignal& aSignal)
+{
+  const InfallibleTArray<BluetoothNamedValue>& values =
+    aSignal.value().get_ArrayOfBluetoothNamedValue();
+  for (uint32_t i = 0; i < values.Length(); ++i) {
+    SetPropertyByValue(values[i]);
+  }
+}
+
+void
+BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
+{
+  const nsString& name = aValue.name();
+  const BluetoothValue& value = aValue.value();
+  if (name.EqualsLiteral("Name")) {
+    mName = value.get_nsString();
+  } else if (name.EqualsLiteral("Address")) {
+    mAddress = value.get_nsString();
+  } else if (name.EqualsLiteral("Class")) {
+    mClass = value.get_uint32_t();
+  } else if (name.EqualsLiteral("Connected")) {
+    mConnected = value.get_bool();
+  } else if (name.EqualsLiteral("Paired")) {
+    mPaired = value.get_bool();
+  } else if (name.EqualsLiteral("UUIDs")) {
+    mUuids = value.get_ArrayOfnsString();
+  } else {
+#ifdef DEBUG
+    nsCString warningMsg;
+    warningMsg.AssignLiteral("Not handling device property: ");
+    warningMsg.Append(NS_ConvertUTF16toUTF8(name));
+    NS_WARNING(warningMsg.get());
+#endif
+  }
+}
+
+// static
+already_AddRefed<BluetoothDevice>
+BluetoothDevice::Create(nsPIDOMWindow* aOwner, const BluetoothSignal& aSignal)
+{
+  nsRefPtr<BluetoothDevice> device = new BluetoothDevice(aSignal);
+  device->BindToOwner(device);
+  return device.forget();
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetAddress(nsAString& aAddress)
+{
+  aAddress = mAddress;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetName(nsAString& aName)
+{
+  aName = mName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetDeviceClass(PRUint32* aClass)
+{
+  *aClass = mClass;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetPaired(bool* aPaired)
+{
+  *aPaired = mPaired;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+BluetoothDevice::GetConnected(bool* aConnected)
+{
+  *aConnected = mConnected;
+  return NS_OK;
+}
+
+NS_IMPL_EVENT_HANDLER(BluetoothDevice, propertychanged)
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothDevice.h
@@ -0,0 +1,65 @@
+/* -*- 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_bluetoothdevice_h__
+#define mozilla_dom_bluetooth_bluetoothdevice_h__
+
+#include "BluetoothCommon.h"
+#include "nsDOMEventTargetHelper.h"
+#include "nsIDOMBluetoothDevice.h"
+#include "nsString.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothNamedValue;
+class BluetoothSignal;
+
+class BluetoothDevice : public nsDOMEventTargetHelper
+                      , public nsIDOMBluetoothDevice
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMBLUETOOTHDEVICE
+
+  NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothDevice,
+                                           nsDOMEventTargetHelper)
+
+  static already_AddRefed<BluetoothDevice>
+  Create(nsPIDOMWindow* aOwner, const BluetoothSignal& aSignal);
+
+  nsIDOMEventTarget*
+  ToIDOMEventTarget() const
+  {
+    return static_cast<nsDOMEventTargetHelper*>(
+      const_cast<BluetoothDevice*>(this));
+  }
+
+  nsISupports*
+  ToISupports() const
+  {
+    return ToIDOMEventTarget();
+  }
+  
+private:
+  BluetoothDevice(const BluetoothSignal& aSignal);
+  ~BluetoothDevice() {}  
+  void SetPropertyByValue(const BluetoothNamedValue& aValue);
+  
+  nsString mAddress;
+  nsString mName;
+  PRUint32 mClass;
+  bool mConnected;
+  bool mPaired;
+  nsTArray<nsString> mUuids;
+
+  NS_DECL_EVENT_HANDLER(propertychanged)
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothDeviceEvent.cpp
@@ -0,0 +1,57 @@
+/* -*- 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 "base/basictypes.h"
+#include "BluetoothDeviceEvent.h"
+#include "BluetoothTypes.h"
+#include "BluetoothDevice.h"
+
+#include "nsDOMClassInfo.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+// static
+already_AddRefed<BluetoothDeviceEvent>
+BluetoothDeviceEvent::Create(BluetoothDevice* aDevice)
+{
+  NS_ASSERTION(aDevice, "Null pointer!");
+
+  nsRefPtr<BluetoothDeviceEvent> event = new BluetoothDeviceEvent();
+
+  event->mDevice = aDevice;
+
+  return event.forget();
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDeviceEvent)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDeviceEvent,
+                                                  nsDOMEvent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDevice)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDeviceEvent,
+                                                nsDOMEvent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDevice)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDeviceEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothDeviceEvent)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothDeviceEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMPL_ADDREF_INHERITED(BluetoothDeviceEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(BluetoothDeviceEvent, nsDOMEvent)
+
+DOMCI_DATA(BluetoothDeviceEvent, BluetoothDeviceEvent)
+
+NS_IMETHODIMP
+BluetoothDeviceEvent::GetDevice(nsIDOMBluetoothDevice** aDevice)
+{
+  nsCOMPtr<nsIDOMBluetoothDevice> device = mDevice.get();
+  device.forget(aDevice);
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothDeviceEvent.h
@@ -0,0 +1,68 @@
+/* -*- 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_deviceevent_h__
+#define mozilla_dom_bluetooth_deviceevent_h__
+
+#include "BluetoothCommon.h"
+
+#include "nsIDOMBluetoothDeviceEvent.h"
+#include "nsIDOMEventTarget.h"
+
+#include "nsDOMEvent.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothDevice;
+
+class BluetoothDeviceEvent : public nsDOMEvent
+                           , public nsIDOMBluetoothDeviceEvent
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_TO_NSDOMEVENT
+  NS_DECL_NSIDOMBLUETOOTHDEVICEEVENT
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothDeviceEvent, nsDOMEvent)
+
+  static already_AddRefed<BluetoothDeviceEvent>
+  Create(BluetoothDevice* aDevice);
+
+  nsresult
+  Dispatch(nsIDOMEventTarget* aTarget, const nsAString& aEventType)
+  {
+    NS_ASSERTION(aTarget, "Null pointer!");
+    NS_ASSERTION(!aEventType.IsEmpty(), "Empty event type!");
+
+    nsresult rv = InitEvent(aEventType, false, false);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = SetTrusted(true);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsIDOMEvent* thisEvent =
+      static_cast<nsDOMEvent*>(const_cast<BluetoothDeviceEvent*>(this));
+
+    bool dummy;
+    rv = aTarget->DispatchEvent(thisEvent, &dummy);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+private:
+  BluetoothDeviceEvent()
+  : nsDOMEvent(nsnull, nsnull)
+  { }
+
+  ~BluetoothDeviceEvent()
+  { }
+
+  nsCOMPtr<nsIDOMBluetoothDevice> mDevice;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
deleted file mode 100644
--- a/dom/bluetooth/BluetoothFirmware.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- 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 "BluetoothFirmware.h"
-
-#include "nsDebug.h"
-#include "nsError.h"
-#include <dlfcn.h>
-
-namespace mozilla {
-namespace dom {
-namespace bluetooth {
-
-static struct BluedroidFunctions {
-  bool initialized;
-  bool tried_initialization;
-
-  BluedroidFunctions() :
-    initialized(false),
-    tried_initialization(false)
-  {
-  }
-
-  int (* bt_enable)();
-  int (* bt_disable)();
-  int (* bt_is_enabled)();
-} sBluedroidFunctions;
-
-bool EnsureBluetoothInit() {
-  if (sBluedroidFunctions.tried_initialization)
-  {
-    return sBluedroidFunctions.initialized;
-  }
-
-  sBluedroidFunctions.initialized = false;
-  sBluedroidFunctions.tried_initialization = true;
-  
-  void* handle = dlopen("libbluedroid.so", RTLD_LAZY);
-
-  if(!handle) {
-    NS_ERROR("Failed to open libbluedroid.so, bluetooth cannot run");
-    return false;
-  }
-
-  sBluedroidFunctions.bt_enable = (int (*)())dlsym(handle, "bt_enable");
-  if(sBluedroidFunctions.bt_enable == NULL) {
-    NS_ERROR("Failed to attach bt_enable function");
-    return false;
-  }
-  sBluedroidFunctions.bt_disable = (int (*)())dlsym(handle, "bt_disable");
-  if(sBluedroidFunctions.bt_disable == NULL) {
-    NS_ERROR("Failed to attach bt_disable function");
-    return false;
-  }
-  sBluedroidFunctions.bt_is_enabled = (int (*)())dlsym(handle, "bt_is_enabled");
-  if(sBluedroidFunctions.bt_is_enabled == NULL) {
-    NS_ERROR("Failed to attach bt_is_enabled function");
-    return false;
-  }
-  sBluedroidFunctions.initialized = true;
-  return true;
-}
-
-int IsBluetoothEnabled()
-{
-  return sBluedroidFunctions.bt_is_enabled();
-}
-
-int EnableBluetooth()
-{
-  return sBluedroidFunctions.bt_enable();
-}
-
-int DisableBluetooth()
-{
-  return sBluedroidFunctions.bt_disable();
-}
-
-
-}
-}
-}
deleted file mode 100644
--- a/dom/bluetooth/BluetoothFirmware.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- 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_bluetoothfirmware_h__
-#define mozilla_dom_bluetooth_bluetoothfirmware_h__
-
-namespace mozilla {
-namespace dom {
-namespace bluetooth {
-
-bool EnsureBluetoothInit();
-int IsBluetoothEnabled();
-int EnableBluetooth();
-int DisableBluetooth();
-
-}
-}
-}
-
-#endif
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -1,281 +1,285 @@
 /* -*- 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 "base/basictypes.h"
 #include "BluetoothManager.h"
 #include "BluetoothCommon.h"
-#include "BluetoothFirmware.h"
 #include "BluetoothAdapter.h"
-#include "BluetoothUtils.h"
+#include "BluetoothService.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
 
-#include "nsIURI.h"
-#include "nsIURL.h"
-#include "nsPIDOMWindow.h"
-
-#include "jsapi.h"
+#include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
+#include "nsIDOMDOMRequest.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
-#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");
-
-  if (!rs) {
-    NS_WARNING("No DOMRequest Service!");
-    return;
-  }
-
-  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)
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothManager, 
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothManager,
                                                   nsDOMEventTargetHelper)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(enabled)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothManager, 
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothManager,
                                                 nsDOMEventTargetHelper)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(enabled)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothManager)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothManager)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothManager)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothManager, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothManager, nsDOMEventTargetHelper)
 
-class ToggleBtResultTask : public nsRunnable
+class GetAdapterTask : public BluetoothReplyRunnable
 {
-  public:
-    ToggleBtResultTask(nsRefPtr<BluetoothManager>& aManager, 
-                       nsCOMPtr<nsIDOMDOMRequest>& aReq,
-                       bool aEnabled,
-                       bool aResult)
-      : mEnabled(aEnabled),
-        mResult(aResult)
-    {
-      MOZ_ASSERT(!NS_IsMainThread());
+public:
+  GetAdapterTask(BluetoothManager* aManager,
+                 nsIDOMDOMRequest* aReq) :
+    BluetoothReplyRunnable(aReq),
+    mManagerPtr(aManager)
+  {
+  }
 
-      mDOMRequest.swap(aReq);
-      mManagerPtr.swap(aManager);
+  bool
+  ParseSuccessfulReply(jsval* aValue)
+  {
+    nsCOMPtr<nsIDOMBluetoothAdapter> adapter;
+    *aValue = JSVAL_VOID;
+
+    const nsString& path =
+      mReply->get_BluetoothReplySuccess().value().get_nsString();
+    adapter = BluetoothAdapter::Create(mManagerPtr->GetOwner(),
+                                       path);
+
+    nsresult rv;
+    nsIScriptContext* sc = mManagerPtr->GetContextForEventHandlers(&rv);
+    if (!sc) {
+      NS_WARNING("Cannot create script context!");
+      SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
+      return false;
     }
 
-    NS_IMETHOD Run() 
-    {
-      MOZ_ASSERT(NS_IsMainThread());
-
-      // Update bt power status to BluetoothAdapter only if loading bluetooth 
-      // firmware succeeds.
-      if (mResult) {
-        mManagerPtr->SetEnabledInternal(mEnabled);
-      }
-
-      FireEnabled(mResult, mDOMRequest);
-
-      //mAdapterPtr must be null before returning to prevent the background 
-      //thread from racing to release it during the destruction of this runnable.
-      mManagerPtr = NULL;
-      mDOMRequest = NULL;
-
-      return NS_OK;
+    rv = nsContentUtils::WrapNative(sc->GetNativeContext(),
+                                    sc->GetNativeGlobal(),
+                                    adapter,
+                                    aValue);
+    bool result = NS_SUCCEEDED(rv) ? true : false;
+    if (!result) {
+      NS_WARNING("Cannot create native object!");
+      SetError(NS_LITERAL_STRING("BluetoothNativeObjectError"));
     }
 
-  private:
-    nsRefPtr<BluetoothManager> mManagerPtr;
-    nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
-    bool mEnabled;
-    bool mResult;
+    return result;
+  }
+
+  void
+  ReleaseMembers()
+  {
+    BluetoothReplyRunnable::ReleaseMembers();
+    mManagerPtr = nsnull;
+  }
+  
+private:
+  nsRefPtr<BluetoothManager> mManagerPtr;
 };
 
-class ToggleBtTask : public nsRunnable
+class ToggleBtResultTask : public BluetoothReplyRunnable
 {
-  public:
-    ToggleBtTask(bool aEnabled, nsIDOMDOMRequest* aReq,
-                 BluetoothManager* aManager)
-      : mEnabled(aEnabled),        
-        mManagerPtr(aManager),
-        mDOMRequest(aReq)
-    {
-      MOZ_ASSERT(NS_IsMainThread());
-    }
-
-    NS_IMETHOD Run() 
-    {
-      MOZ_ASSERT(!NS_IsMainThread());
-
-      bool result;
-
-#ifdef MOZ_WIDGET_GONK
-      // Platform specific check for gonk until object is divided in
-      // different implementations per platform. Linux doesn't require
-      // bluetooth firmware loading, but code should work otherwise.
-      if(!EnsureBluetoothInit()) {
-        NS_ERROR("Failed to load bluedroid library.\n");
-        return NS_ERROR_FAILURE;
-      }
+public:
+  ToggleBtResultTask(BluetoothManager* aManager,
+                     nsIDOMDOMRequest* aReq,
+                     bool aEnabled)
+    : BluetoothReplyRunnable(aReq),
+      mManagerPtr(aManager),
+      mEnabled(aEnabled)
+  {
+  }
 
-      // return 1 if it's enabled, 0 if it's disabled, and -1 on error
-      int isEnabled = IsBluetoothEnabled();
+  ~ToggleBtResultTask()
+  {
+  }
+  
+  bool
+  ParseSuccessfulReply(jsval* aValue)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    *aValue = JSVAL_VOID;
+    mManagerPtr->SetEnabledInternal(mEnabled);
+    return true;
+  }
 
-      if ((isEnabled == 1 && mEnabled) || (isEnabled == 0 && !mEnabled)) {
-        result = true;
-      } else if (isEnabled < 0) {
-        result = false;
-      } else if (mEnabled) {
-        result = (EnableBluetooth() == 0) ? true : false;
-      } else {
-        result = (DisableBluetooth() == 0) ? true : false;
-      }
-#else
-      result = true;
-      NS_WARNING("No bluetooth firmware loading support in this build configuration, faking a success event instead");
-#endif
-
-      // Create a result thread and pass it to Main Thread, 
-      nsCOMPtr<nsIRunnable> resultRunnable = new ToggleBtResultTask(mManagerPtr, mDOMRequest, mEnabled, result);
-
-      if (NS_FAILED(NS_DispatchToMainThread(resultRunnable))) {
-        NS_WARNING("Failed to dispatch to main thread!");
-      }
-
-      return NS_OK;
-    }
-
-  private:
-    bool mEnabled;
-    nsRefPtr<BluetoothManager> mManagerPtr;
-    nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
+  void
+  ReleaseMembers()
+  {
+    BluetoothReplyRunnable::ReleaseMembers();
+    // mManagerPtr must be null before returning to prevent the background
+    // thread from racing to release it during the destruction of this runnable.
+    mManagerPtr = nsnull;
+  }
+  
+private:
+  nsRefPtr<BluetoothManager> mManagerPtr;
+  bool mEnabled;
 };
 
 BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow) :
-  mEnabled(false),
-  mName(nsDependentCString("/"))
+  mEnabled(false)
 {
   BindToOwner(aWindow);
+  mName.AssignLiteral("/");
 }
 
 BluetoothManager::~BluetoothManager()
 {
-  if(NS_FAILED(UnregisterBluetoothEventHandler(mName, this))) {
-    NS_WARNING("Failed to unregister object with observer!");
+  BluetoothService* bs = BluetoothService::Get();
+  // We can be null on shutdown, where this might happen
+  if (bs) {
+    if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mName, this))) {
+      NS_WARNING("Failed to unregister object with observer!");
+    }
   }
 }
 
 NS_IMETHODIMP
 BluetoothManager::SetEnabled(bool aEnabled, nsIDOMDOMRequest** aDomRequest)
 {
+  BluetoothService* bs = BluetoothService::Get();
+  MOZ_ASSERT(bs);
+
   nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
 
   if (!rs) {
-    NS_ERROR("No DOMRequest Service!");
+    NS_WARNING("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIDOMDOMRequest> request;
   nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
-  NS_ENSURE_SUCCESS(rv, rv);
-  
-  if (!mToggleBtThread) {
-    mToggleBtThread = new LazyIdleThread(15000, NS_LITERAL_CSTRING("Bluetooth"));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create DOM request!");
+    return NS_ERROR_FAILURE;
   }
 
-  nsCOMPtr<nsIRunnable> r = new ToggleBtTask(aEnabled, request, this);
-
-  rv = mToggleBtThread->Dispatch(r, NS_DISPATCH_NORMAL);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsRefPtr<BluetoothReplyRunnable> results = new ToggleBtResultTask(this, request, aEnabled);
+  if (aEnabled) {
+    if (NS_FAILED(bs->Start(results))) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+  else {
+    if (NS_FAILED(bs->Stop(results))) {
+      return NS_ERROR_FAILURE;
+    }
+  }
 
   request.forget(aDomRequest);
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BluetoothManager::GetEnabled(bool* aEnabled)
 {
   *aEnabled = mEnabled;
-  return NS_OK; 
+  return NS_OK;
 }
 
 NS_IMETHODIMP
-BluetoothManager::GetDefaultAdapter(nsIDOMBluetoothAdapter** aAdapter)
+BluetoothManager::GetDefaultAdapter(nsIDOMDOMRequest** aAdapter)
 {
-  nsCString path;
-  nsresult rv = GetDefaultAdapterPathInternal(path);
-  if(NS_FAILED(rv)) {
-    NS_WARNING("Cannot fetch adapter path!");
+  BluetoothService* bs = BluetoothService::Get();
+  MOZ_ASSERT(bs);
+  
+  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+
+  if (!rs) {
+    NS_WARNING("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
   }
-  nsRefPtr<BluetoothAdapter> adapter = BluetoothAdapter::Create(path);
-  adapter.forget(aAdapter);
+
+  nsCOMPtr<nsIDOMDOMRequest> request;
+  nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create DOMRequest!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<BluetoothReplyRunnable> results = new GetAdapterTask(this, request);
+
+  if (NS_FAILED(bs->GetDefaultAdapterPathInternal(results))) {
+    return NS_ERROR_FAILURE;
+  }
+  request.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;
+  BluetoothService* bs = BluetoothService::Get();
+  MOZ_ASSERT(bs);
+  
+  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING("/"), manager))) {
+    NS_ERROR("Failed to register object with observer!");
+    return nsnull;
   }
+  
   return manager.forget();
 }
 
 nsresult
 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;
+    *aBluetoothManager = nsnull;
     return NS_OK;
   }
 
   nsRefPtr<BluetoothManager> bluetoothManager = BluetoothManager::Create(aWindow);
-
+  if (!bluetoothManager) {
+    NS_ERROR("Cannot create bluetooth manager!");
+    return NS_ERROR_FAILURE;
+  }
   bluetoothManager.forget(aBluetoothManager);
   return NS_OK;
 }
 
-void BluetoothManager::Notify(const BluetoothEvent& aData) {
-  printf("Received an manager message!\n");
+void
+BluetoothManager::Notify(const BluetoothSignal& aData)
+{
+#ifdef DEBUG
+  nsCString warningMsg;
+  warningMsg.AssignLiteral("Not handling manager signal: ");
+  warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
+  NS_WARNING(warningMsg.get());
+#endif
 }
--- a/dom/bluetooth/BluetoothManager.h
+++ b/dom/bluetooth/BluetoothManager.h
@@ -5,50 +5,47 @@
  * 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 BluetoothManager : public nsDOMEventTargetHelper
                        , public nsIDOMBluetoothManager
-                       , public BluetoothEventObserver
+                       , public BluetoothSignalObserver
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMBLUETOOTHMANAGER
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothManager,
                                            nsDOMEventTargetHelper)
 
 
   inline void SetEnabledInternal(bool aEnabled) {mEnabled = aEnabled;}
 
   static already_AddRefed<BluetoothManager>
   Create(nsPIDOMWindow* aWindow);
-  void Notify(const BluetoothEvent& aData);
+  void Notify(const BluetoothSignal& aData);
 private:
   BluetoothManager() {}
   BluetoothManager(nsPIDOMWindow* aWindow);
   ~BluetoothManager();
   bool mEnabled;
-  nsCString mName;
+  nsString mName;
 
   NS_DECL_EVENT_HANDLER(enabled)
-
-  nsCOMPtr<nsIEventTarget> mToggleBtThread;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 nsresult NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
                                 nsIDOMBluetoothManager** aBluetoothManager);
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothNullServiceFactory.cpp
@@ -0,0 +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 "BluetoothService.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+BluetoothService*
+BluetoothService::Create()
+{
+  NS_WARNING("Bluetooth not implemented for this platform!");
+  return nsnull;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothReplyRunnable.cpp
@@ -0,0 +1,76 @@
+/* -*- 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 "base/basictypes.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
+#include "nsIDOMDOMRequest.h"
+#include "jsapi.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+nsresult
+BluetoothReplyRunnable::FireReply(const jsval& aVal)
+{
+  nsCOMPtr<nsIDOMRequestService> rs =
+    do_GetService("@mozilla.org/dom/dom-request-service;1");
+  
+  if (!rs) {
+    NS_WARNING("No DOMRequest Service!");
+    return NS_ERROR_FAILURE;
+  }
+  
+  
+  return mReply->type() == BluetoothReply::TBluetoothReplySuccess ?
+    rs->FireSuccess(mDOMRequest, aVal) :
+    rs->FireError(mDOMRequest, mReply->get_BluetoothReplyError().error());
+}
+
+nsresult
+BluetoothReplyRunnable::FireErrorString()
+{
+  nsCOMPtr<nsIDOMRequestService> rs =
+    do_GetService("@mozilla.org/dom/dom-request-service;1");
+  
+  if (!rs) {
+    NS_WARNING("No DOMRequest Service!");
+    return NS_ERROR_FAILURE;
+  }
+  
+  return rs->FireError(mDOMRequest, mErrorString);
+}
+
+NS_IMETHODIMP
+BluetoothReplyRunnable::Run()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsresult rv;
+
+  MOZ_ASSERT(mDOMRequest);
+
+  if (mReply->type() != BluetoothReply::TBluetoothReplySuccess) {
+    rv = FireReply(JSVAL_VOID);
+  } else {
+    jsval v; 
+    if (!ParseSuccessfulReply(&v)) {
+      rv = FireErrorString();
+    } else {
+      rv = FireReply(v);
+    }
+  }
+
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Could not fire DOMRequest!");
+  }
+
+  ReleaseMembers();
+  if (mDOMRequest) {
+    NS_WARNING("mDOMRequest still alive! Deriving class should call BluetoothReplyRunnable::ReleaseMembers()!");
+  }
+
+  return rv;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothReplyRunnable.h
@@ -0,0 +1,87 @@
+/* -*- 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_bluetoothreplyrunnable_h__
+#define mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
+
+#include "BluetoothCommon.h"
+#include "nsThreadUtils.h"
+#include "jsapi.h"
+
+class nsIDOMDOMRequest;
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothReply;
+
+class BluetoothReplyRunnable : public nsRunnable
+{
+public:
+  NS_DECL_NSIRUNNABLE
+
+  BluetoothReplyRunnable(nsIDOMDOMRequest* aReq) :
+    mDOMRequest(aReq)
+  {
+  }
+
+  void SetReply(BluetoothReply* aReply)
+  {
+    mReply = aReply;
+  }
+
+  void SetError(const nsAString& aError)
+  {
+    mErrorString = aError;
+  }
+
+  virtual void ReleaseMembers()
+  {
+    mDOMRequest = nsnull;
+  }
+
+protected:
+  virtual ~BluetoothReplyRunnable()
+  {
+  }
+  
+  virtual bool ParseSuccessfulReply(jsval* aValue) = 0;
+
+  // This is an autoptr so we don't have to bring the ipdl include into the
+  // header. We assume we'll only be running this once and it should die on
+  // scope out of Run() anyways.
+  nsAutoPtr<BluetoothReply> mReply;
+
+private:
+  nsresult FireReply(const jsval& aVal);
+  nsresult FireErrorString();
+  
+  nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
+  nsString mErrorString;
+};
+
+class BluetoothVoidReplyRunnable : public BluetoothReplyRunnable
+{
+public:
+  BluetoothVoidReplyRunnable(nsIDOMDOMRequest* aReq) :
+    BluetoothReplyRunnable(aReq)
+  {
+  }
+
+  virtual void ReleaseMembers()
+  {
+    BluetoothReplyRunnable::ReleaseMembers();
+  }
+protected:
+  virtual bool ParseSuccessfulReply(jsval* aValue)
+  {
+    *aValue = JSVAL_VOID;
+    return true;
+  }
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -0,0 +1,242 @@
+/* -*- 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 "base/basictypes.h"
+
+#include "BluetoothService.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
+
+#include "nsIDOMDOMRequest.h"
+#include "nsThreadUtils.h"
+#include "nsXPCOMCIDInternal.h"
+#include "nsObserverService.h"
+#include "mozilla/Services.h"
+#include "mozilla/LazyIdleThread.h"
+#include "mozilla/Util.h"
+
+using namespace mozilla;
+
+USING_BLUETOOTH_NAMESPACE
+
+nsRefPtr<BluetoothService> gBluetoothService;
+nsCOMPtr<nsIThread> gToggleBtThread;
+int gPendingInitCount = 0;
+bool gInShutdown = false;
+
+NS_IMPL_ISUPPORTS1(BluetoothService, nsIObserver)
+
+class ToggleBtAck : public nsRunnable
+{
+public:
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    gPendingInitCount--;
+    
+    if (gPendingInitCount) {
+      return NS_OK;
+    }
+    
+    if (gInShutdown) {
+      gBluetoothService = nsnull;
+    }
+
+    nsCOMPtr<nsIThread> t;
+    gToggleBtThread.swap(t);
+    t->Shutdown();
+    return NS_OK;
+  }
+};
+
+class ToggleBtTask : public nsRunnable
+{
+public:
+  ToggleBtTask(bool aEnabled,
+               BluetoothReplyRunnable* aRunnable)
+    : mEnabled(aEnabled),
+      mRunnable(aRunnable)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+  }
+
+  NS_IMETHOD Run() 
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    nsString replyError;
+    if (mEnabled) {
+      if (NS_FAILED(gBluetoothService->StartInternal())) {
+        replyError.AssignLiteral("Bluetooth service not available - We should never reach this point!");
+      }
+    }
+    else {
+      if (NS_FAILED(gBluetoothService->StopInternal())) {        
+        replyError.AssignLiteral("Bluetooth service not available - We should never reach this point!");
+      }
+    }
+
+    // Always has to be called since this is where we take care of our reference
+    // count for runnables. If there's an error, replyError won't be empty, so
+    // consider our status flipped.
+    nsCOMPtr<nsIRunnable> ackTask = new ToggleBtAck();
+    if (NS_FAILED(NS_DispatchToMainThread(ackTask))) {
+      NS_WARNING("Failed to dispatch to main thread!");
+    }
+    
+    if (!mRunnable) {
+      return NS_OK;
+    }
+    
+    // Reply will be deleted by the runnable after running on main thread
+    BluetoothReply* reply;
+    if (!replyError.IsEmpty()) {
+      reply = new BluetoothReply(BluetoothReplyError(replyError));
+    }
+    else {
+      reply = new BluetoothReply(BluetoothReplySuccess());
+    }
+    mRunnable->SetReply(reply);
+      
+    if (NS_FAILED(NS_DispatchToMainThread(mRunnable))) {
+      NS_WARNING("Failed to dispatch to main thread!");
+    }
+    
+    return NS_OK;
+  }
+
+private:
+  bool mEnabled;
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
+};
+
+nsresult
+BluetoothService::RegisterBluetoothSignalHandler(const nsAString& aNodeName,
+                                                 BluetoothSignalObserver* aHandler)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  BluetoothSignalObserverList* ol;
+  if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
+    ol = new BluetoothSignalObserverList();
+    mBluetoothSignalObserverTable.Put(aNodeName, ol);
+  }
+  ol->AddObserver(aHandler);
+  return NS_OK;
+}
+
+nsresult
+BluetoothService::UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
+                                                   BluetoothSignalObserver* aHandler)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  BluetoothSignalObserverList* ol;
+  if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
+    NS_WARNING("Node does not exist to remove BluetoothSignalListener from!");
+    return NS_OK;
+  }
+  ol->RemoveObserver(aHandler);
+  if (ol->Length() == 0) {
+    mBluetoothSignalObserverTable.Remove(aNodeName);
+  }
+  return NS_OK;
+}
+
+nsresult
+BluetoothService::DistributeSignal(const BluetoothSignal& signal)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // Notify observers that a message has been sent
+  BluetoothSignalObserverList* ol;
+  if (!mBluetoothSignalObserverTable.Get(signal.path(), &ol)) {
+    return NS_OK;
+  }
+  ol->Broadcast(signal);
+  return NS_OK;
+}
+
+nsresult
+BluetoothService::StartStopBluetooth(BluetoothReplyRunnable* aResultRunnable,
+                                     bool aStart)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // If we're shutting down, bail early.
+  if (gInShutdown && aStart) {
+    NS_ERROR("Start called while in shutdown!");
+    return NS_ERROR_FAILURE;
+  }
+  if (!gToggleBtThread) {
+    nsresult rv = NS_NewNamedThread("BluetoothCtrl",
+                                    getter_AddRefs(gToggleBtThread));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  nsCOMPtr<nsIRunnable> r = new ToggleBtTask(aStart, aResultRunnable);
+  if (NS_FAILED(gToggleBtThread->Dispatch(r, NS_DISPATCH_NORMAL))) {
+    NS_WARNING("Cannot dispatch firmware loading task!");
+    return NS_ERROR_FAILURE;
+  }
+  gPendingInitCount++;
+  return NS_OK;
+}
+
+nsresult
+BluetoothService::Start(BluetoothReplyRunnable* aResultRunnable)
+{
+  return StartStopBluetooth(aResultRunnable, true);
+}
+
+nsresult
+BluetoothService::Stop(BluetoothReplyRunnable* aResultRunnable)
+{
+  return StartStopBluetooth(aResultRunnable, false);
+}
+
+// static
+BluetoothService*
+BluetoothService::Get()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // If we already exist, exit early
+  if (gBluetoothService) {
+    return gBluetoothService;
+  }
+  
+  // If we're in shutdown, don't create a new instance
+  if (gInShutdown) {
+    NS_WARNING("BluetoothService returns null during shutdown");
+    return nsnull;
+  }
+
+  // Create new instance, register, return
+  gBluetoothService = BluetoothService::Create();
+  if (!gBluetoothService) {
+    NS_WARNING("Cannot create bluetooth service!");
+    return nsnull;
+  }
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  MOZ_ASSERT(obs);
+
+  if (NS_FAILED(obs->AddObserver(gBluetoothService, "xpcom-shutdown", false))) {
+    NS_ERROR("AddObserver failed!");
+  }
+  return gBluetoothService;
+}
+
+nsresult
+BluetoothService::Observe(nsISupports* aSubject, const char* aTopic,
+                          const PRUnichar* aData)
+{
+  NS_ASSERTION(!strcmp(aTopic, "xpcom-shutdown"),
+               "BluetoothService got unexpected topic!");
+  gInShutdown = true;
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (obs && NS_FAILED(obs->RemoveObserver(this, "xpcom-shutdown"))) {
+    NS_WARNING("Can't unregister bluetooth service with xpcom shutdown!");
+  }
+
+  return Stop(nsnull);
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothService.h
@@ -0,0 +1,171 @@
+/* -*- 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_bluetootheventservice_h__
+#define mozilla_dom_bluetooth_bluetootheventservice_h__
+
+#include "nsThreadUtils.h"
+#include "nsClassHashtable.h"
+#include "nsIObserver.h"
+#include "BluetoothCommon.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothSignal;
+class BluetoothReplyRunnable;
+class BluetoothNamedValue;
+
+class BluetoothService : public nsIObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  /** 
+   * 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 RegisterBluetoothSignalHandler(const nsAString& aNodeName,
+                                          BluetoothSignalObserver* 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 UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
+                                            BluetoothSignalObserver* aMsgHandler);
+
+  /** 
+   * Distribute a signal to the observer list
+   *
+   * @param aSignal Signal object to distribute
+   *
+   * @return NS_OK if signal distributed, NS_ERROR_FAILURE on error
+   */
+  nsresult DistributeSignal(const BluetoothSignal& aEvent);
+
+  /** 
+   * Start bluetooth services. Starts up any threads and connections that
+   * bluetooth needs to operate on the current platform. Assumed to be run on
+   * the main thread with delayed return for blocking startup functions via
+   * runnable.
+   *
+   * @param aResultRunnable Runnable object to execute after bluetooth has
+   * either come up or failed. Runnable should check existence of
+   * BluetoothService via Get() function to see if service started correctly.
+   *
+   * @return NS_OK on initialization starting correctly, NS_ERROR_FAILURE
+   * otherwise
+   */
+  nsresult Start(BluetoothReplyRunnable* aResultRunnable);
+
+  /** 
+   * Stop bluetooth services. Starts up any threads and connections that
+   * bluetooth needs to operate on the current platform. Assumed to be run on
+   * the main thread with delayed return for blocking startup functions via
+   * runnable.
+   *
+   * @param aResultRunnable Runnable object to execute after bluetooth has
+   * either shut down or failed. Runnable should check lack of existence of
+   * BluetoothService via Get() function to see if service stopped correctly.
+   *
+   * @return NS_OK on initialization starting correctly, NS_ERROR_FAILURE
+   * otherwise
+   */
+  nsresult Stop(BluetoothReplyRunnable* aResultRunnable);
+
+  /** 
+   * Returns the BluetoothService singleton. Only to be called from main thread.
+   *
+   * @param aService Pointer to return singleton into. 
+   *
+   * @return NS_OK on proper assignment, NS_ERROR_FAILURE otherwise (if service
+   * has not yet been started, for instance)
+   */
+  static BluetoothService* Get();
+  
+  /**
+   * Returns the path of the default adapter, implemented via a platform
+   * specific method.
+   *
+   * @return Default adapter path/name on success, NULL otherwise
+   */
+  virtual nsresult GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable) = 0;
+
+  /** 
+   * Stop device discovery (platform specific implementation)
+   *
+   * @param aAdapterPath Adapter to stop discovery on
+   *
+   * @return NS_OK if discovery stopped correctly, false otherwise
+   */
+  virtual nsresult StopDiscoveryInternal(const nsAString& aAdapterPath,
+                                         BluetoothReplyRunnable* aRunnable) = 0;
+
+  /** 
+   * Start device discovery (platform specific implementation)
+   *
+   * @param aAdapterPath Adapter to start discovery on
+   *
+   * @return NS_OK if discovery stopped correctly, false otherwise
+   */
+  virtual nsresult StartDiscoveryInternal(const nsAString& aAdapterPath,
+                                          BluetoothReplyRunnable* aRunnable) = 0;
+
+  /** 
+   * Platform specific startup functions go here. Usually deals with member
+   * variables, so not static. Guaranteed to be called outside of main thread.
+   *
+   * @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult StartInternal() = 0;
+
+  /** 
+   * Platform specific startup functions go here. Usually deals with member
+   * variables, so not static. Guaranteed to be called outside of main thread.
+   *
+   * @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult StopInternal() = 0;
+
+protected:
+  BluetoothService()
+  {
+    mBluetoothSignalObserverTable.Init();
+  }
+
+  virtual ~BluetoothService()
+  {
+  }
+
+  nsresult StartStopBluetooth(BluetoothReplyRunnable* aResultRunnable,
+                              bool aStart);
+  // This function is implemented in platform-specific BluetoothServiceFactory
+  // files
+  static BluetoothService* Create();
+
+  typedef mozilla::ObserverList<BluetoothSignal> BluetoothSignalObserverList;
+  typedef nsClassHashtable<nsStringHashKey, BluetoothSignalObserverList >
+  BluetoothSignalObserverTable;
+
+  BluetoothSignalObserverTable mBluetoothSignalObserverTable;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
deleted file mode 100644
--- a/dom/bluetooth/BluetoothUtils.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -*- 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,46 +10,63 @@ 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 = \
+CPPSRCS += \
+  BluetoothService.cpp \
   BluetoothManager.cpp \
   BluetoothAdapter.cpp \
-  BluetoothFirmware.cpp \
+  BluetoothDevice.cpp \
+  BluetoothDeviceEvent.cpp \
+  BluetoothReplyRunnable.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 \
+  nsIDOMBluetoothDevice.idl \
+  nsIDOMBluetoothDeviceEvent.idl \
   $(NULL)
 
+ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
+VPATH += \
+	$(srcdir)/linux \
+	$(srcdir)/gonk \
+	$(NULL)
+LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
+CPPSRCS += \
+	BluetoothDBusService.cpp \
+	BluetoothGonkService.cpp \
+	BluetoothGonkServiceFactory.cpp \
+	$(NULL)
+else
+ifdef MOZ_ENABLE_DBUS
+VPATH += $(srcdir)/linux
+LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
+CPPSRCS += \
+	BluetoothDBusService.cpp \
+	BluetoothDBusServiceFactory.cpp \
+	$(NULL)
+CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
+CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
+else
+CPPSRCS += BluetoothNullServiceFactory.cpp
+endif
+endif
+
+LOCAL_INCLUDES += -I$(DEPTH)/ipc/ipdl/_ipdlheaders/mozilla/dom/bluetooth/
+
+# Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
+# subdirectory
+LOCAL_INCLUDES += $(VPATH:%=-I%)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
-ifdef MOZ_ENABLE_DBUS
-CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
-CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
-endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/gonk/BluetoothGonkService.cpp
@@ -0,0 +1,150 @@
+/* -*- 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 "BluetoothGonkService.h"
+#include "BluetoothDBusService.h"
+
+#include "nsDebug.h"
+#include "nsError.h"
+#include <dlfcn.h>
+
+USING_BLUETOOTH_NAMESPACE
+
+static struct BluedroidFunctions
+{
+  bool initialized;
+  bool tried_initialization;
+
+  BluedroidFunctions() :
+    initialized(false),
+    tried_initialization(false)
+  {
+  }
+
+  int (* bt_enable)();
+  int (* bt_disable)();
+  int (* bt_is_enabled)();
+} sBluedroidFunctions;
+
+bool
+EnsureBluetoothInit()
+{
+  if (sBluedroidFunctions.tried_initialization)
+  {
+    return sBluedroidFunctions.initialized;
+  }
+
+  sBluedroidFunctions.initialized = false;
+  sBluedroidFunctions.tried_initialization = true;
+  
+  void* handle = dlopen("libbluedroid.so", RTLD_LAZY);
+
+  if (!handle) {
+    NS_ERROR("Failed to open libbluedroid.so, bluetooth cannot run");
+    return false;
+  }
+
+  sBluedroidFunctions.bt_enable = (int (*)())dlsym(handle, "bt_enable");
+  if (!sBluedroidFunctions.bt_enable) {
+    NS_ERROR("Failed to attach bt_enable function");
+    return false;
+  }
+  sBluedroidFunctions.bt_disable = (int (*)())dlsym(handle, "bt_disable");
+  if (!sBluedroidFunctions.bt_disable) {
+    NS_ERROR("Failed to attach bt_disable function");
+    return false;
+  }
+  sBluedroidFunctions.bt_is_enabled = (int (*)())dlsym(handle, "bt_is_enabled");
+  if (!sBluedroidFunctions.bt_is_enabled) {
+    NS_ERROR("Failed to attach bt_is_enabled function");
+    return false;
+  }
+  sBluedroidFunctions.initialized = true;
+  return true;
+}
+
+int
+IsBluetoothEnabled()
+{
+  return sBluedroidFunctions.bt_is_enabled();
+}
+
+int
+EnableBluetooth()
+{
+  return sBluedroidFunctions.bt_enable();
+}
+
+int
+DisableBluetooth()
+{
+  return sBluedroidFunctions.bt_disable();
+}
+
+nsresult
+StartStopGonkBluetooth(bool aShouldEnable)
+{
+  bool result;
+  
+  // Platform specific check for gonk until object is divided in
+  // different implementations per platform. Linux doesn't require
+  // bluetooth firmware loading, but code should work otherwise.
+  if (!EnsureBluetoothInit()) {
+    NS_ERROR("Failed to load bluedroid library.\n");
+    return NS_ERROR_FAILURE;
+  }
+
+  // return 1 if it's enabled, 0 if it's disabled, and -1 on error
+  int isEnabled = IsBluetoothEnabled();
+
+  if ((isEnabled == 1 && aShouldEnable) || (isEnabled == 0 && !aShouldEnable)) {
+    result = true;
+  } else if (isEnabled < 0) {
+    result = false;
+  } else if (aShouldEnable) {
+    result = (EnableBluetooth() == 0) ? true : false;
+  } else {
+    result = (DisableBluetooth() == 0) ? true : false;
+  }
+  if (!result) {
+    NS_WARNING("Could not set gonk bluetooth firmware!");
+    return NS_ERROR_FAILURE;
+  }
+  
+  return NS_OK;
+}
+
+nsresult
+BluetoothGonkService::StartInternal()
+{
+  NS_ASSERTION(!NS_IsMainThread(), "This should not run on the main thread!");
+
+  nsresult ret;
+
+  ret = StartStopGonkBluetooth(true);
+
+  if (NS_FAILED(ret)) {
+    return ret;    
+  }
+
+  return BluetoothDBusService::StartInternal();
+}
+
+nsresult
+BluetoothGonkService::StopInternal()
+{
+  NS_ASSERTION(!NS_IsMainThread(), "This should not run on the main thread!");
+  nsresult ret;
+
+  ret = StartStopGonkBluetooth(false);
+
+  if (NS_FAILED(ret)) {
+    return ret;    
+  }
+
+  return BluetoothDBusService::StopInternal();
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/gonk/BluetoothGonkService.h
@@ -0,0 +1,48 @@
+/* -*- 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_bluetoothgonkservice_h__
+#define mozilla_dom_bluetooth_bluetoothgonkservice_h__
+
+#include "BluetoothCommon.h"
+#include "BluetoothDBusService.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+/**
+ * BluetoothService 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.
+ */
+
+class BluetoothGonkService : public BluetoothDBusService
+{
+public:
+  /** 
+   * 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
+   */
+  virtual nsresult StartInternal();
+
+  /** 
+   * Stop the platform specific connection. Must be called from main
+   * thread.
+   *
+   * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
+   * otherwise
+   */
+  virtual nsresult StopInternal();
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/gonk/BluetoothGonkServiceFactory.cpp
@@ -0,0 +1,15 @@
+/* -*- 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 "BluetoothGonkService.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+BluetoothService*
+BluetoothService::Create()
+{
+  return new BluetoothGonkService();
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/BluetoothTypes.ipdlh
@@ -0,0 +1,62 @@
+/* -*- 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/. */
+
+namespace mozilla {
+namespace dom {
+namespace bluetooth {
+
+/**
+ * Value structure for returns from bluetooth. Currently modeled after dbus
+ * returns, which can be a 32-bit int, an UTF16 string, a bool, or an array of
+ * UTF16 strings. Can also hold key-value pairs for dictionary-ish access.
+ * 
+ */
+union BluetoothValue
+{
+  uint32_t;
+  nsString;
+  bool;
+  nsString[];
+  BluetoothNamedValue[];
+};
+
+/**
+ * Key-value pair for dicts returned by the bluetooth backend. Used for things
+ * like property updates, where the property will have a name and a type.
+ * 
+ */
+struct BluetoothNamedValue
+{
+  nsString name;
+  BluetoothValue value;
+};
+
+struct BluetoothSignal
+{
+  nsString name;
+  nsString path;
+  BluetoothValue value;
+};
+
+struct BluetoothReplySuccess
+{
+  BluetoothValue value;
+};
+
+struct BluetoothReplyError
+{
+  nsString error;
+};
+
+union BluetoothReply
+{
+  BluetoothReplySuccess;
+  BluetoothReplyError;
+};
+
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/ipdl.mk
@@ -0,0 +1,7 @@
+# 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/.
+
+IPDLSRCS = \
+  BluetoothTypes.ipdlh \
+  $(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -0,0 +1,577 @@
+/* -*- 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 "base/basictypes.h"
+#include "BluetoothDBusService.h"
+#include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
+
+#include <cstdio>
+#include <dbus/dbus.h>
+
+#include "nsIDOMDOMRequest.h"
+#include "nsAutoPtr.h"
+#include "nsThreadUtils.h"
+#include "nsDebug.h"
+#include "nsClassHashtable.h"
+#include "mozilla/ipc/DBusThread.h"
+#include "mozilla/ipc/DBusUtils.h"
+#include "mozilla/ipc/RawDBusConnection.h"
+#include "mozilla/Util.h"
+
+/**
+ * Some rules for dealing with memory in DBus:
+ * - A DBusError only needs to be deleted if it's been set, not just
+ *   initialized. This is why LOG_AND_FREE... is called only when an error is
+ *   set, and the macro cleans up the error itself.
+ * - A DBusMessage needs to be unrefed when it is newed explicitly. DBusMessages
+ *   from signals do not need to be unrefed, as they will be cleaned by DBus
+ *   after DBUS_HANDLER_RESULT_HANDLED is returned from the filter.
+ */
+
+using namespace mozilla;
+using namespace mozilla::ipc;
+USING_BLUETOOTH_NAMESPACE
+
+#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"
+
+typedef struct {
+  const char* name;
+  int type;
+} Properties;
+
+static Properties remote_device_properties[] = {
+  {"Address", DBUS_TYPE_STRING},
+  {"Name", DBUS_TYPE_STRING},
+  {"Icon", DBUS_TYPE_STRING},
+  {"Class", DBUS_TYPE_UINT32},
+  {"UUIDs", DBUS_TYPE_ARRAY},
+  {"Services", DBUS_TYPE_ARRAY},
+  {"Paired", DBUS_TYPE_BOOLEAN},
+  {"Connected", DBUS_TYPE_BOOLEAN},
+  {"Trusted", DBUS_TYPE_BOOLEAN},
+  {"Blocked", DBUS_TYPE_BOOLEAN},
+  {"Alias", DBUS_TYPE_STRING},
+  {"Nodes", DBUS_TYPE_ARRAY},
+  {"Adapter", DBUS_TYPE_OBJECT_PATH},
+  {"LegacyPairing", DBUS_TYPE_BOOLEAN},
+  {"RSSI", DBUS_TYPE_INT16},
+  {"TX", DBUS_TYPE_UINT32},
+  {"Broadcaster", DBUS_TYPE_BOOLEAN}
+};
+
+static Properties adapter_properties[] = {
+  {"Address", DBUS_TYPE_STRING},
+  {"Name", DBUS_TYPE_STRING},
+  {"Class", DBUS_TYPE_UINT32},
+  {"Powered", DBUS_TYPE_BOOLEAN},
+  {"Discoverable", DBUS_TYPE_BOOLEAN},
+  {"DiscoverableTimeout", DBUS_TYPE_UINT32},
+  {"Pairable", DBUS_TYPE_BOOLEAN},
+  {"PairableTimeout", DBUS_TYPE_UINT32},
+  {"Discovering", DBUS_TYPE_BOOLEAN},
+  {"Devices", DBUS_TYPE_ARRAY},
+  {"UUIDs", DBUS_TYPE_ARRAY},
+};
+
+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'"
+};
+
+class DistributeBluetoothSignalTask : public nsRunnable {
+  BluetoothSignal mSignal;
+public:
+  DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
+    mSignal(aSignal)
+  {
+  }
+
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    BluetoothService* bs = BluetoothService::Get();
+    MOZ_ASSERT(bs);
+    return bs->DistributeSignal(mSignal);
+  }  
+};
+
+
+bool
+IsDBusMessageError(DBusMessage* aMsg, nsAString& aError)
+{
+  DBusError err;
+  dbus_error_init(&err);
+  if (dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_ERROR) {
+    const char* error_msg;
+    if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_STRING,
+                               &error_msg, DBUS_TYPE_INVALID) ||
+        !error_msg) {
+      if (dbus_error_is_set(&err)) {
+        aError = NS_ConvertUTF8toUTF16(err.message);
+        LOG_AND_FREE_DBUS_ERROR(&err);
+        return true;
+      }
+    } else {
+      aError = NS_ConvertUTF8toUTF16(error_msg);
+      return true;
+    }
+  }
+  return false;
+}
+
+void
+DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable,
+                       const BluetoothValue& aValue, const nsAString& aError)
+{
+  // Reply will be deleted by the runnable after running on main thread
+  BluetoothReply* reply;
+  if (!aError.IsEmpty()) {
+    nsString err(aError);
+    reply = new BluetoothReply(BluetoothReplyError(err));
+  }
+  else {
+    reply = new BluetoothReply(BluetoothReplySuccess(aValue));
+  }
+  
+  aRunnable->SetReply(reply);
+  if (NS_FAILED(NS_DispatchToMainThread(aRunnable))) {
+    NS_WARNING("Failed to dispatch to main thread!");
+  }
+}
+  
+void
+GetObjectPathCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  DBusError err;
+  dbus_error_init(&err);
+  nsRefPtr<BluetoothReplyRunnable> replyRunnable =
+    dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));
+
+  NS_ASSERTION(replyRunnable, "Callback reply runnable is null!");
+
+  nsString replyError;
+  nsString replyPath;
+
+  nsTArray<BluetoothNamedValue> replyValues;
+  BluetoothValue v;
+  if (!IsDBusMessageError(aMsg, replyError)) {
+    NS_ASSERTION(dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN,
+                 "Got dbus callback that's not a METHOD_RETURN!");
+    const char* object_path;
+    if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_OBJECT_PATH,
+                               &object_path, DBUS_TYPE_INVALID) ||
+        !object_path) {
+      if (dbus_error_is_set(&err)) {
+        replyError = NS_ConvertUTF8toUTF16(err.message);
+        LOG_AND_FREE_DBUS_ERROR(&err);
+      }
+    } else {
+      v = NS_ConvertUTF8toUTF16(object_path);
+    }
+  }
+  DispatchBluetoothReply(replyRunnable, v, replyError);
+}
+
+void
+GetVoidCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  DBusError err;
+  dbus_error_init(&err);
+  nsRefPtr<BluetoothReplyRunnable> replyRunnable =
+    dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));
+
+  NS_ASSERTION(replyRunnable, "Callback reply runnable is null!");
+
+  nsString replyError;
+  BluetoothValue v;
+  if (!IsDBusMessageError(aMsg, replyError) &&
+      dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
+      !dbus_message_get_args(aMsg, &err, DBUS_TYPE_INVALID)) {
+    if (dbus_error_is_set(&err)) {
+      replyError = NS_ConvertUTF8toUTF16(err.message);
+      LOG_AND_FREE_DBUS_ERROR(&err);
+    }
+  }
+  DispatchBluetoothReply(replyRunnable, v, replyError);  
+}
+
+bool
+GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
+            int aPropertiesTypeLen, int* aPropIndex,
+            InfallibleTArray<BluetoothNamedValue>& aProperties)
+{
+  DBusMessageIter prop_val, array_val_iter;
+  char* property = NULL;
+  uint32_t array_type;
+  int i, type;
+
+  if (dbus_message_iter_get_arg_type(&aIter) != DBUS_TYPE_STRING) {    
+    return false;
+  }
+
+  dbus_message_iter_get_basic(&aIter, &property);
+
+  if (!dbus_message_iter_next(&aIter) ||
+      dbus_message_iter_get_arg_type(&aIter) != DBUS_TYPE_VARIANT) {
+    return false;
+  }
+
+  for (i = 0; i <  aPropertiesTypeLen; i++) {
+    if (!strncmp(property, aPropertyTypes[i].name, strlen(property))) {      
+      break;
+    }
+  }
+
+  if (i == aPropertiesTypeLen) {
+    return false;
+  }
+
+  nsString propertyName;
+  propertyName.AssignASCII(aPropertyTypes[i].name);
+  *aPropIndex = i;
+
+  dbus_message_iter_recurse(&aIter, &prop_val);
+  type = aPropertyTypes[*aPropIndex].type;
+
+  NS_ASSERTION(dbus_message_iter_get_arg_type(&prop_val) == type,
+               "Iterator not type we expect!");
+  
+  BluetoothValue propertyValue;
+  switch (type) {
+    case DBUS_TYPE_STRING:
+    case DBUS_TYPE_OBJECT_PATH:
+      const char* c;
+      dbus_message_iter_get_basic(&prop_val, &c);
+      propertyValue = NS_ConvertUTF8toUTF16(c);
+      break;
+    case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_INT16:
+      uint32_t i;
+      dbus_message_iter_get_basic(&prop_val, &i);
+      propertyValue = i;
+      break;
+    case DBUS_TYPE_BOOLEAN:
+      bool b;
+      dbus_message_iter_get_basic(&prop_val, &b);
+      propertyValue = b;
+      break;
+    case DBUS_TYPE_ARRAY:
+      dbus_message_iter_recurse(&prop_val, &array_val_iter);
+      array_type = dbus_message_iter_get_arg_type(&array_val_iter);
+      if (array_type == DBUS_TYPE_OBJECT_PATH ||
+          array_type == DBUS_TYPE_STRING){
+        InfallibleTArray<nsString> arr;
+        do {
+          const char* tmp;
+          dbus_message_iter_get_basic(&array_val_iter, &tmp);
+          nsString s;
+          s = NS_ConvertUTF8toUTF16(tmp);
+          arr.AppendElement(s);
+        } while (dbus_message_iter_next(&array_val_iter));
+        propertyValue = arr;
+      } else {
+        NS_WARNING("Received array type that's not a string array!");
+      }
+      break;
+    default:
+      NS_NOTREACHED("Cannot find dbus message type!");
+  }
+  aProperties.AppendElement(BluetoothNamedValue(propertyName, propertyValue));
+  return true;
+}
+
+void 
+ParseProperties(DBusMessageIter* aIter, 
+                Properties* aPropertyTypes,
+                const int aPropertiesTypeLen,
+                InfallibleTArray<BluetoothNamedValue>& aProperties)
+{
+  DBusMessageIter dict_entry, dict;
+  int prop_index = -1;
+
+  NS_ASSERTION(dbus_message_iter_get_arg_type(aIter) == DBUS_TYPE_ARRAY,
+               "Trying to parse a property from something that's not an array!");
+
+  dbus_message_iter_recurse(aIter, &dict);
+
+  do {
+    NS_ASSERTION(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY,
+                 "Trying to parse a property from something that's not an dict!");
+    dbus_message_iter_recurse(&dict, &dict_entry);
+
+    if (!GetProperty(dict_entry, aPropertyTypes, aPropertiesTypeLen, &prop_index,
+                     aProperties)) {
+      NS_WARNING("Can't create property!");
+      return;
+    }
+  } while (dbus_message_iter_next(&dict));
+}
+
+void
+ParsePropertyChange(DBusMessage* aMsg, Properties* aPropertyTypes,
+                    const int aPropertiesTypeLen,
+                    InfallibleTArray<BluetoothNamedValue>& aProperties)
+{
+  DBusMessageIter iter;
+  DBusError err;
+  int prop_index = -1;
+  
+  dbus_error_init(&err);
+  if (!dbus_message_iter_init(aMsg, &iter)) {
+    LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
+    return;
+  }
+    
+  if (!GetProperty(iter, aPropertyTypes, aPropertiesTypeLen,
+                   &prop_index, aProperties)) {
+    NS_WARNING("Can't get property!");
+  }
+}
+
+// Called by dbus during WaitForAndDispatchEventNative()
+// This function is called on the IOThread
+static
+DBusHandlerResult
+EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
+{
+  NS_ASSERTION(!NS_IsMainThread(), "Shouldn't be called from Main Thread!");
+  
+  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;
+  }  
+
+  if (dbus_message_get_path(aMsg) == NULL) {
+    LOG("DBusMessage %s has no bluetooth destination, ignoring\n",
+        dbus_message_get_member(aMsg));
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  DBusError err;
+  nsString signalPath;
+  nsString signalName;
+  dbus_error_init(&err);
+  signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(aMsg));
+  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));
+
+  signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(aMsg));
+  BluetoothValue v;
+  
+  if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceFound")) {
+
+    DBusMessageIter iter;
+
+    NS_ASSERTION(dbus_message_iter_init(aMsg, &iter),
+                 "Can't create message iterator!");
+
+    InfallibleTArray<BluetoothNamedValue> value;
+    const char* addr;
+    dbus_message_iter_get_basic(&iter, &addr);
+    value.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Address"),
+                                            NS_ConvertUTF8toUTF16(addr)));
+    
+    if (dbus_message_iter_next(&iter)) {
+      ParseProperties(&iter,
+                      remote_device_properties,
+                      ArrayLength(remote_device_properties),
+                      value);
+      NS_ASSERTION(value.Length() != 0, "Properties returned empty!");
+      v = value;
+    } else {
+      NS_WARNING("DBus iterator not as long as expected!");
+    }
+  } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceDisappeared")) {
+    const char* str;
+    if (!dbus_message_get_args(aMsg, &err,
+                               DBUS_TYPE_STRING, &str,
+                               DBUS_TYPE_INVALID)) {
+      LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
+    }
+    v = NS_ConvertUTF8toUTF16(str);
+  } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceCreated")) {
+    const char* str;
+    if (!dbus_message_get_args(aMsg, &err,
+                               DBUS_TYPE_OBJECT_PATH, &str,
+                               DBUS_TYPE_INVALID)) {
+      LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
+    }
+    v = NS_ConvertUTF8toUTF16(str);
+  } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "PropertyChanged")) {
+    InfallibleTArray<BluetoothNamedValue> value;
+    ParsePropertyChange(aMsg,
+                        (Properties*)&adapter_properties,
+                        ArrayLength(adapter_properties),
+                        value);
+    NS_ASSERTION(value.Length() != 0, "Properties returned empty!");
+    v = value;
+  }
+
+  BluetoothSignal signal(signalName, signalPath, v);
+  
+  nsRefPtr<DistributeBluetoothSignalTask>
+    t = new DistributeBluetoothSignalTask(signal);
+  if (NS_FAILED(NS_DispatchToMainThread(t))) {
+    NS_WARNING("Failed to dispatch to main thread!");
+  }
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+nsresult
+BluetoothDBusService::StartInternal()
+{
+  // This could block. It should never be run on the main thread.
+  MOZ_ASSERT(!NS_IsMainThread());
+  
+  if (!StartDBus()) {
+    NS_WARNING("Cannot start DBus thread!");
+    return NS_ERROR_FAILURE;
+  }
+  
+  if (mConnection) {
+    return NS_OK;    
+  }
+
+  if (NS_FAILED(EstablishDBusConnection())) {
+    NS_WARNING("Cannot start DBus connection!");
+    StopDBus();
+    return NS_ERROR_FAILURE;
+  }
+	
+  // Add a filter for all incoming messages_base
+  if (!dbus_connection_add_filter(mConnection, EventFilter,
+                                  NULL, NULL)) {
+    NS_WARNING("Cannot create DBus Event Filter for DBus Thread!");
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::StopInternal()
+{
+  // This could block. It should never be run on the main thread.
+  MOZ_ASSERT(!NS_IsMainThread());
+  
+  if (!mConnection) {
+    StopDBus();
+    return NS_OK;
+  }
+  dbus_connection_remove_filter(mConnection, EventFilter, NULL);
+  mConnection = nsnull;
+  mBluetoothSignalObserverTable.Clear();
+  StopDBus();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable)
+{
+  if (!mConnection) {
+    NS_ERROR("Bluetooth service not started yet!");
+    return NS_ERROR_FAILURE;
+  }
+  NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+
+  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+
+  if (!dbus_func_args_async(mConnection,
+                            1000,
+                            GetObjectPathCallback,
+                            (void*)aRunnable,
+                            "/",
+                            "org.bluez.Manager",
+                            "DefaultAdapter",
+                            DBUS_TYPE_INVALID)) {
+    NS_WARNING("Could not start async function!");
+    return NS_ERROR_FAILURE;
+  }
+  runnable.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::SendDiscoveryMessage(const nsAString& aAdapterPath,
+                                           const char* aMessageName,
+                                           BluetoothReplyRunnable* aRunnable)
+{
+  if (!mConnection) {
+    NS_WARNING("Bluetooth service not started yet!");
+    return NS_ERROR_FAILURE;
+  }
+  NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+
+  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+
+  const char* s = NS_ConvertUTF16toUTF8(aAdapterPath).get();
+  if (!dbus_func_args_async(mConnection,
+                            1000,
+                            GetVoidCallback,
+                            (void*)aRunnable,
+                            s,
+                            DBUS_ADAPTER_IFACE,
+                            aMessageName,
+                            DBUS_TYPE_INVALID)) {
+    NS_WARNING("Could not start async function!");
+    return NS_ERROR_FAILURE;
+  }
+  runnable.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::StopDiscoveryInternal(const nsAString& aAdapterPath,
+                                            BluetoothReplyRunnable* aRunnable)
+{
+  return SendDiscoveryMessage(aAdapterPath, "StopDiscovery", aRunnable);
+}
+ 
+nsresult
+BluetoothDBusService::StartDiscoveryInternal(const nsAString& aAdapterPath,
+                                             BluetoothReplyRunnable* aRunnable)
+{
+  return SendDiscoveryMessage(aAdapterPath, "StartDiscovery", aRunnable);
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -0,0 +1,84 @@
+/* -*- 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_bluetoothdbuseventservice_h__
+#define mozilla_dom_bluetooth_bluetoothdbuseventservice_h__
+
+#include "BluetoothCommon.h"
+#include "mozilla/ipc/RawDBusConnection.h"
+#include "BluetoothService.h"
+
+class DBusMessage;
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+/**
+ * BluetoothService functions are used to dispatch messages to Bluetooth DOM
+ * objects on the main thread, as well as provide platform independent 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.
+ */
+
+class BluetoothDBusService : public BluetoothService
+                           , private mozilla::ipc::RawDBusConnection
+{
+public:
+  /** 
+   * Set up variables and start the platform specific connection. Must
+   * be called from outside main thread.
+   *
+   * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
+   * otherwise
+   */
+  virtual nsresult StartInternal();
+
+  /** 
+   * Stop the platform specific connection. Must be called from outside main
+   * thread.
+   *
+   * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
+   * otherwise
+   */
+  virtual nsresult StopInternal();
+
+  /** 
+   * Returns the path of the default adapter, implemented via a platform
+   * specific method.
+   *
+   * @return Default adapter path/name on success, NULL otherwise
+   */
+  virtual nsresult GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable);
+
+  /** 
+   * Start device discovery (platform specific implementation)
+   *
+   * @param aAdapterPath Adapter to start discovery on
+   *
+   * @return NS_OK if discovery stopped correctly, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult StartDiscoveryInternal(const nsAString& aAdapterPath,
+                                          BluetoothReplyRunnable* aRunnable);
+  /** 
+   * Stop device discovery (platform specific implementation)
+   *
+   * @param aAdapterPath Adapter to stop discovery on
+   *
+   * @return NS_OK if discovery stopped correctly, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult StopDiscoveryInternal(const nsAString& aAdapterPath,
+                                         BluetoothReplyRunnable* aRunnable);
+
+private:
+  nsresult SendDiscoveryMessage(const nsAString& aAdapterPath,
+                                const char* aMessageName,
+                                BluetoothReplyRunnable* aRunnable);
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/linux/BluetoothDBusServiceFactory.cpp
@@ -0,0 +1,15 @@
+/* -*- 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 "BluetoothDBusService.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+BluetoothService*
+BluetoothService::Create()
+{
+  return new BluetoothDBusService();
+}
--- a/dom/bluetooth/nsIDOMBluetoothAdapter.idl
+++ b/dom/bluetooth/nsIDOMBluetoothAdapter.idl
@@ -1,12 +1,36 @@
 /* -*- 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 "nsIDOMEventTarget.idl"
 
-[scriptable, builtinclass, uuid(fe6602d2-f32f-4b95-bf66-028452bbe6d2)]
+interface nsIDOMDOMRequest;
+interface nsIDOMBluetoothDevice;
+
+[scriptable, builtinclass, uuid(48df7f05-2bbc-4ac8-aa88-9fecd4c24028)]
 interface nsIDOMBluetoothAdapter : nsIDOMEventTarget
 {
+  readonly attribute DOMString address;
+  [binaryname(AdapterClass)] readonly attribute unsigned long class;
+  readonly attribute bool enabled;
+  readonly attribute bool discovering;
+
+  [implicit_jscontext]
+  readonly attribute jsval devices;
+
+  readonly attribute DOMString name;
+  readonly attribute bool discoverable;
+  // Unit: sec
+  readonly attribute unsigned long discoverableTimeout;
+
+  nsIDOMDOMRequest startDiscovery();
+  nsIDOMDOMRequest stopDiscovery();
+  // Fired when discoverying and any device is discovered.
+  attribute nsIDOMEventListener ondevicefound;
+  // Fired when any device is out of discoverable range.
+  attribute nsIDOMEventListener ondevicedisappeared;
+  // Fired when a property of the adapter is changed
+  attribute nsIDOMEventListener onpropertychanged;
 };
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/nsIDOMBluetoothDevice.idl
@@ -0,0 +1,19 @@
+/* -*- 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 "nsIDOMEventTarget.idl"
+
+[scriptable, builtinclass, uuid(2c446123-b5dd-4631-80f6-eda91befd8c9)]
+interface nsIDOMBluetoothDevice : nsIDOMEventTarget
+{
+  readonly attribute DOMString address;
+  readonly attribute DOMString name;
+
+  [binaryname(DeviceClass)] readonly attribute unsigned long class;
+  readonly attribute bool connected;
+  readonly attribute bool paired;
+  attribute nsIDOMEventListener onpropertychanged;
+};
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/nsIDOMBluetoothDeviceEvent.idl
@@ -0,0 +1,15 @@
+/* -*- 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 "nsIDOMEvent.idl"
+
+interface nsIDOMBluetoothDevice;
+
+[scriptable, builtinclass, uuid(49294da3-b698-4a7f-aca2-3f9bc44c7625)]
+interface nsIDOMBluetoothDeviceEvent : nsIDOMEvent
+{
+  readonly attribute nsIDOMBluetoothDevice device;
+};
--- a/dom/bluetooth/nsIDOMBluetoothManager.idl
+++ b/dom/bluetooth/nsIDOMBluetoothManager.idl
@@ -4,16 +4,16 @@
  * 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 "nsIDOMEventTarget.idl"
 
 interface nsIDOMDOMRequest;
 interface nsIDOMBluetoothAdapter;
 
-[scriptable, builtinclass, uuid(9d4bcbad-8904-4985-b366-036d32959312)]
+[scriptable, builtinclass, uuid(1442c310-8233-4670-8aa9-752ad673bae0)]
 interface nsIDOMBluetoothManager : nsIDOMEventTarget
 {
   readonly attribute bool enabled;
-  readonly attribute nsIDOMBluetoothAdapter defaultAdapter;
 
+  nsIDOMDOMRequest getDefaultAdapter();
   nsIDOMDOMRequest setEnabled(in boolean enabled);
 };
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -14,46 +14,29 @@
 #include "nsIXPConnect.h"
 
 #include "jsfriendapi.h"
 #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
-#if defined(MOZ_WIDGET_GONK)
-#include <android/log.h>
-#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkBluetooth", args);
-#else
-#define BTDEBUG true
-#define LOG(args...) if(BTDEBUG) printf(args);
-#endif
+USING_WORKERS_NAMESPACE
 
-
-USING_WORKERS_NAMESPACE
 using namespace mozilla::dom::gonk;
 using namespace mozilla::ipc;
 #ifdef MOZ_WIDGET_GONK
 using namespace mozilla::system;
 #endif
-#ifdef MOZ_B2G_BT
-using namespace mozilla::dom::bluetooth;
-#endif
 
 namespace {
 
 NS_DEFINE_CID(kRadioInterfaceLayerCID, NS_RADIOINTERFACELAYER_CID);
 NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID);
 
 // Doesn't carry a reference, we're owned by services.
 SystemWorkerManager *gInstance = nsnull;
@@ -224,25 +207,16 @@ SystemWorkerManager::Init()
   }
 
   rv = InitWifi(cx);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to initialize WiFi Networking!");
     return rv;
   }
 
-#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);
   if (!obs) {
     NS_WARNING("Failed to get observer service!");
@@ -265,19 +239,17 @@ SystemWorkerManager::Shutdown()
 
   mShutdown = true;
 
 #ifdef MOZ_WIDGET_GONK
   ShutdownAutoMounter();
 #endif
 
   StopRil();
-#ifdef MOZ_B2G_BT
-  StopDBus();
-#endif
+
   mRILWorker = nsnull;
   nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
   if (wifi) {
     wifi->Shutdown();
     wifi = nsnull;
   }
   mWifiWorker = nsnull;
 
@@ -380,39 +352,16 @@ SystemWorkerManager::InitWifi(JSContext 
 {
   nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
   NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
 
   mWifiWorker = worker;
   return NS_OK;
 }
 
-nsresult
-SystemWorkerManager::InitBluetooth(JSContext *cx)
-{
-#ifdef MOZ_B2G_BT
-#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;
-}
-
 NS_IMPL_ISUPPORTS2(SystemWorkerManager, nsIObserver, nsIInterfaceRequestor)
 
 NS_IMETHODIMP
 SystemWorkerManager::Observe(nsISupports *aSubject, const char *aTopic,
                              const PRUnichar *aData)
 {
   if (!strcmp(aTopic, WORKERS_SHUTDOWN_TOPIC)) {
     Shutdown();
--- a/dom/system/gonk/SystemWorkerManager.h
+++ b/dom/system/gonk/SystemWorkerManager.h
@@ -40,18 +40,17 @@ public:
   GetInterfaceRequestor();
 
 private:
   SystemWorkerManager();
   ~SystemWorkerManager();
 
   nsresult InitRIL(JSContext *cx);
   nsresult InitWifi(JSContext *cx);
-  nsresult InitBluetooth(JSContext *cx);
-  
+
   nsCOMPtr<nsIWorkerHolder> mRILWorker;
   nsCOMPtr<nsIWorkerHolder> mWifiWorker;
 
   bool mShutdown;
 };
 
 }
 }
--- a/ipc/dbus/DBusThread.cpp
+++ b/ipc/dbus/DBusThread.cpp
@@ -41,33 +41,32 @@
 #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 "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, "GonkDBus", args);
 #else
 #define BTDEBUG true
-#define LOG(args...) if(BTDEBUG) printf(args);
+#define LOG(args...) if (BTDEBUG) printf(args);
 #endif
 
 #define DEFAULT_INITIAL_POLLFD_COUNT 8
 
 // Functions for converting between unix events in the poll struct,
 // and their dbus definitions
 
 // TODO Add Wakeup to this list once we've moved to ics
@@ -126,24 +125,22 @@ struct PollFdComparator {
 // DBus Thread Class prototype
 
 struct DBusThread : public RawDBusConnection
 {
   DBusThread();
   ~DBusThread();
 
   bool StartEventLoop();
-  void StopEventLoop();
+  bool StopEventLoop();
   bool IsEventLoopRunning();
-  static void* EventLoop(void* aPtr);
+  void EventLoop();
 
   // Thread members
-  pthread_t mThread;
-  Mutex mMutex;
-  bool mIsRunning;
+  nsCOMPtr<nsIThread> mThread;
 
   // Information about the sockets we're polling. Socket counts
   // increase/decrease depending on how many add/remove watch signals
   // we're received via the control sockets.
   nsTArray<pollfd> mPollData;
   nsTArray<DBusWatch*> mWatchData;
 
   // Sockets for receiving dbus control information (watch
@@ -168,62 +165,62 @@ AddWatch(DBusWatch *aWatch, void *aData)
   DBusThread *dbt = (DBusThread *)aData;
 
   if (dbus_watch_get_enabled(aWatch)) {
     // note that we can't just send the watch and inspect it later
     // because we may get a removeWatch call before this data is reacted
     // to by our eventloop and remove this watch..  reading the add first
     // and then inspecting the recently deceased watch would be bad.
     char control = DBUS_EVENT_LOOP_ADD;
-    if(write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
+    if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
       LOG("Cannot write DBus add watch control data to socket!\n");
       return false;
     }
 
     // TODO change this to dbus_watch_get_unix_fd once we move to ics
     int fd = dbus_watch_get_fd(aWatch);
-    if(write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
+    if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
       LOG("Cannot write DBus add watch descriptor data to socket!\n");
       return false;
     }
 
     unsigned int flags = dbus_watch_get_flags(aWatch);
-    if(write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
+    if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
       LOG("Cannot write DBus add watch flag data to socket!\n");
       return false;
     }
 
-    if(write(dbt->mControlFdW.get(), &aWatch, sizeof(DBusWatch*)) < 0) {
+    if (write(dbt->mControlFdW.get(), &aWatch, sizeof(DBusWatch*)) < 0) {
       LOG("Cannot write DBus add watch struct data to socket!\n");
       return false;
     }
   }
   return true;
 }
 
 static void
 RemoveWatch(DBusWatch *aWatch, void *aData)
 {
   DBusThread *dbt = (DBusThread *)aData;
 
   char control = DBUS_EVENT_LOOP_REMOVE;
-  if(write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
+  if (write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
     LOG("Cannot write DBus remove watch control data to socket!\n");
     return;
   }
 
   // TODO change this to dbus_watch_get_unix_fd once we move to ics
   int fd = dbus_watch_get_fd(aWatch);
-  if(write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
+  if (write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
     LOG("Cannot write DBus remove watch descriptor data to socket!\n");
     return;
   }
 
   unsigned int flags = dbus_watch_get_flags(aWatch);
-  if(write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
+  if (write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
     LOG("Cannot write DBus remove watch flag data to socket!\n");
     return;
   }
 }
 
 static void
 ToggleWatch(DBusWatch *aWatch, void *aData)
 {
@@ -235,107 +232,107 @@ ToggleWatch(DBusWatch *aWatch, void *aDa
 }
 
 static void
 HandleWatchAdd(DBusThread* aDbt)
 {
   DBusWatch *watch;
   int newFD;
   unsigned int flags;
-  if(read(aDbt->mControlFdR.get(), &newFD, sizeof(int)) < 0) {
+  if (read(aDbt->mControlFdR.get(), &newFD, sizeof(int)) < 0) {
     LOG("Cannot read DBus watch add descriptor data from socket!\n");
     return;
   }
-  if(read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
+  if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
     LOG("Cannot read DBus watch add flag data from socket!\n");
     return;
   }
-  if(read(aDbt->mControlFdR.get(), &watch, sizeof(DBusWatch *)) < 0) {
+  if (read(aDbt->mControlFdR.get(), &watch, sizeof(DBusWatch *)) < 0) {
     LOG("Cannot read DBus watch add watch data from socket!\n");
     return;
   }
   short events = DBusFlagsToUnixEvents(flags);
 
   pollfd p;
   p.fd = newFD;
   p.revents = 0;
   p.events = events;
-  if(aDbt->mPollData.Contains(p, PollFdComparator())) return;
+  if (aDbt->mPollData.Contains(p, PollFdComparator())) return;
   aDbt->mPollData.AppendElement(p);
   aDbt->mWatchData.AppendElement(watch);
 }
 
-static void HandleWatchRemove(DBusThread* aDbt) {
+static void HandleWatchRemove(DBusThread* aDbt)
+{
   int removeFD;
   unsigned int flags;
 
-  if(read(aDbt->mControlFdR.get(), &removeFD, sizeof(int)) < 0) {
+  if (read(aDbt->mControlFdR.get(), &removeFD, sizeof(int)) < 0) {
     LOG("Cannot read DBus watch remove descriptor data from socket!\n");
     return;
   }
-  if(read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
+  if (read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
     LOG("Cannot read DBus watch remove flag data from socket!\n");
     return;
   }
   short events = DBusFlagsToUnixEvents(flags);
   pollfd p;
   p.fd = removeFD;
   p.events = events;
   int index = aDbt->mPollData.IndexOf(p, 0, PollFdComparator());
   // There are times where removes can be requested for watches that
   // haven't been added (for example, whenever gecko comes up after
   // adapters have already been enabled), so check to make sure we're
   // using the watch in the first place
-  if(index < 0) {
+  if (index < 0) {
     LOG("DBus requested watch removal of non-existant socket, ignoring...");
     return;
   }
   aDbt->mPollData.RemoveElementAt(index);
 
   // DBusWatch pointers are maintained by DBus, so we won't leak by
   // removing.
   aDbt->mWatchData.RemoveElementAt(index);
 }
 
 // DBus Thread Implementation
 
-DBusThread::DBusThread() : mMutex("DBusGonk.mMutex")
-                         , mIsRunning(false)
+DBusThread::DBusThread()
 {
 }
 
 DBusThread::~DBusThread()
 {
 
 }
 
 bool
 DBusThread::SetUpEventLoop()
 {
   // If we already have a connection, exit
-  if(mConnection) {
+  if (mConnection) {
     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
   nsresult rv = EstablishDBusConnection();
-  if(NS_FAILED(rv)) {
+  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) {
+  for (uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
     dbus_bus_add_match(mConnection,
                        DBUS_SIGNALS[i],
                        &err);
     if (dbus_error_is_set(&err)) {
       LOG_AND_FREE_DBUS_ERROR(&err);
       return false;
     }
   }
@@ -363,94 +360,81 @@ DBusThread::TearDownData()
 bool
 DBusThread::TearDownEventLoop()
 {
   MOZ_ASSERT(mConnection);
 
   DBusError err;
   dbus_error_init(&err);
 
-  for(uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
+  for (uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
     dbus_bus_remove_match(mConnection,
                           DBUS_SIGNALS[i],
                           &err);
     if (dbus_error_is_set(&err)) {
       LOG_AND_FREE_DBUS_ERROR(&err);
     }
   }
 
   return true;
 }
 
-void*
-DBusThread::EventLoop(void *aPtr)
+void
+DBusThread::EventLoop()
 {
-  DBusThread* dbt = static_cast<DBusThread*>(aPtr);
-  MOZ_ASSERT(dbt);
+  dbus_connection_set_watch_functions(mConnection, AddWatch,
+                                      RemoveWatch, ToggleWatch, this, NULL);
 
-  dbus_connection_set_watch_functions(dbt->mConnection, AddWatch,
-                                      RemoveWatch, ToggleWatch, aPtr, NULL);
-
-  dbt->mIsRunning = true;
   LOG("DBus Event Loop Starting\n");
   while (1) {
-    poll(dbt->mPollData.Elements(), dbt->mPollData.Length(), -1);
+    poll(mPollData.Elements(), mPollData.Length(), -1);
 
-    for (uint32_t i = 0; i < dbt->mPollData.Length(); i++) {
-      if (!dbt->mPollData[i].revents) {
+    for (uint32_t i = 0; i < mPollData.Length(); i++) {
+      if (!mPollData[i].revents) {
         continue;
       }
 
-      if (dbt->mPollData[i].fd == dbt->mControlFdR.get()) {
+      if (mPollData[i].fd == mControlFdR.get()) {
         char data;
-        while (recv(dbt->mControlFdR.get(), &data, sizeof(char), MSG_DONTWAIT)
+        while (recv(mControlFdR.get(), &data, sizeof(char), MSG_DONTWAIT)
                != -1) {
           switch (data) {
-          case DBUS_EVENT_LOOP_EXIT:
-          {
-            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);
-            break;
-          }
-          case DBUS_EVENT_LOOP_REMOVE:
-          {
-            HandleWatchRemove(dbt);
-            break;
-          }
+            case DBUS_EVENT_LOOP_EXIT:
+              LOG("DBus Event Loop Exiting\n");
+              dbus_connection_set_watch_functions(mConnection,
+                                                  NULL, NULL, NULL, NULL, NULL);
+              TearDownEventLoop();
+              return;
+            case DBUS_EVENT_LOOP_ADD:
+              HandleWatchAdd(this);
+              break;
+            case DBUS_EVENT_LOOP_REMOVE:
+              HandleWatchRemove(this);
+              break;
           }
         }
       } else {
-        short events = dbt->mPollData[i].revents;
+        short events = mPollData[i].revents;
         unsigned int flags = UnixEventsToDBusFlags(events);
-        dbus_watch_handle(dbt->mWatchData[i], flags);
-        dbt->mPollData[i].revents = 0;
+        dbus_watch_handle(mWatchData[i], flags);
+        mPollData[i].revents = 0;
         // Break at this point since we don't know if the operation
         // was destructive
         break;
       }
     }
-    while (dbus_connection_dispatch(dbt->mConnection) ==
+    while (dbus_connection_dispatch(mConnection) ==
            DBUS_DISPATCH_DATA_REMAINS)
     {}
   }
 }
 
 bool
 DBusThread::StartEventLoop()
 {
-  MutexAutoLock lock(mMutex);
-  mIsRunning = false;
-
   // socketpair opens two sockets for the process to communicate on.
   // This is how android's implementation of the dbus event loop
   // communicates with itself in relation to IPC signals. These
   // sockets are contained sequentially in the same struct in the
   // android code, but we break them out into class members here.
   // Therefore we read into a local array and then copy.
 
   int sockets[2];
@@ -469,112 +453,76 @@ 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;
   }
+  if (NS_FAILED(NS_NewNamedThread("DBus Poll",
+                                  getter_AddRefs(mThread),
+                                  NS_NewNonOwningRunnableMethod(this,
+                                                                &DBusThread::EventLoop)))) {
+    NS_WARNING("Cannot create DBus Thread!");
+    return false;    
+  }
   LOG("DBus Thread Starting\n");
-  pthread_create(&(mThread), NULL, DBusThread::EventLoop, this);
   return true;
 }
 
-void
+bool
 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 Thread!\n");
-    }
-    void *ret;
-    LOG("DBus Thread Joining\n");
-    pthread_join(mThread, &ret);
-    LOG("DBus Thread Joined\n");
-    TearDownData();
+  if (!mThread) {
+    return true;
+  }
+  char data = DBUS_EVENT_LOOP_EXIT;
+  ssize_t wret = write(mControlFdW.get(), &data, sizeof(char));
+  if(wret < 0) {
+    NS_ERROR("Cannot write exit flag to Dbus Thread!");
+    return false;
   }
-  mIsRunning = false;
-}
-
-bool
-DBusThread::IsEventLoopRunning()
-{
-  MutexAutoLock lock(mMutex);
-  return mIsRunning;
+  LOG("DBus Thread Joining\n");
+  nsCOMPtr<nsIThread> tmpThread;
+  mThread.swap(tmpThread);
+  if(NS_FAILED(tmpThread->Shutdown())) {
+    NS_WARNING("DBus thread shutdown failed!");
+  }
+  LOG("DBus Thread Joined\n");
+  TearDownData();
+  return true;
 }
 
 // Startup/Shutdown utility functions
 
-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);
-    lock.Notify();
-  }
-}
-
-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();
-  }
-}
-
 bool
 StartDBus()
 {
-  Monitor monitor("StartDBus.monitor");
-  bool success;
-  {
-    MonitorAutoLock lock(monitor);
-
-    XRE_GetIOMessageLoop()->PostTask(
-      FROM_HERE,
-      NewRunnableFunction(ConnectDBus, &monitor, &success));
-    lock.Wait();
+  MOZ_ASSERT(!NS_IsMainThread());
+  if (sDBusThread) {
+    NS_WARNING("Trying to start DBus Thread that is already currently running, skipping.");
+    return true;
   }
-  return success;
+  nsAutoPtr<DBusThread> thread(new DBusThread());
+  if (!thread->StartEventLoop()) {
+    NS_WARNING("Cannot start DBus event loop!");
+    return false;
+  }
+  sDBusThread = thread;
+  return true;
 }
 
 bool
 StopDBus()
 {
-  Monitor monitor("StopDBus.monitor");
-  bool success;
-  {
-    MonitorAutoLock lock(monitor);
+  MOZ_ASSERT(!NS_IsMainThread());
+  if (!sDBusThread) {
+    return true;
+  }
 
-    XRE_GetIOMessageLoop()->PostTask(
-      FROM_HERE,
-      NewRunnableFunction(DisconnectDBus, &monitor, &success));
-    lock.Wait();
-  }
-  return success;
+  nsAutoPtr<DBusThread> thread(sDBusThread);
+  sDBusThread = nsnull;  
+  return thread->StopEventLoop();
 }
 
 }
 }
--- a/ipc/dbus/DBusUtils.cpp
+++ b/ipc/dbus/DBusUtils.cpp
@@ -33,129 +33,131 @@
 #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) {
+  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 *);
+  DBusCallback user_cb;
   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);
+      req->user_cb(msg, req->user);
     }
     dbus_message_unref(msg);
   }
 
   //dbus_message_unref(req->method);
   dbus_pending_call_cancel(call);
   dbus_pending_call_unref(call);
   free(req);
 }
 
+dbus_bool_t dbus_func_send_async(DBusConnection *conn,
+                                 DBusMessage *msg,
+                                 int timeout_ms,
+                                 void (*user_cb)(DBusMessage*,
+                                                 void*),
+                                 void *user) {
+  dbus_async_call_t *pending;
+  dbus_bool_t reply = FALSE;
+
+  // Freed at end of dbus_func_args_async_callback (becomes "req")
+  pending = (dbus_async_call_t *)malloc(sizeof(dbus_async_call_t));
+  DBusPendingCall *call;
+
+  pending->user_cb = user_cb;
+  pending->user = user;
+
+  reply = dbus_connection_send_with_reply(conn, msg,
+                                          &call,
+                                          timeout_ms);
+  if (reply) {
+    dbus_pending_call_set_notify(call,
+                                 dbus_func_args_async_callback,
+                                 pending,
+                                 NULL);
+  }
+
+  if (msg) dbus_message_unref(msg);
+  return reply;
+}
+
 static dbus_bool_t dbus_func_args_async_valist(DBusConnection *conn,
                                                int timeout_ms,
-                                               void (*user_cb)(DBusMessage *,
-                                                               void *,
+                                               void (*user_cb)(DBusMessage*,
                                                                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;
-
+  DBusMessage *msg = NULL;  
   /* 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);
-    }
-  }
-
+  return dbus_func_send_async(conn, msg, timeout_ms, user_cb, user);
 done:
   if (msg) dbus_message_unref(msg);
-  return reply;
+  return FALSE;
 }
 
 dbus_bool_t dbus_func_args_async(DBusConnection *conn,
                                  int timeout_ms,
-                                 void (*reply)(DBusMessage *, void *, void*),
+                                 void (*reply)(DBusMessage *, 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,
+                                    reply, user,
                                     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.
@@ -168,17 +170,16 @@ DBusMessage * dbus_func_args_timeout_val
                                             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 */
--- a/ipc/dbus/DBusUtils.h
+++ b/ipc/dbus/DBusUtils.h
@@ -45,59 +45,68 @@ public:
     if (mMsg) dbus_message_unref(mMsg);
   }
   operator DBusMessage*() { return mMsg; }
   DBusMessage* get() { return mMsg; }
 private:
   DBusMessage* mMsg;
 };
 
+typedef void (*DBusCallback)(DBusMessage *, void *);
+
+
 void log_and_free_dbus_error(DBusError* err,
                              const char* function,
                              DBusMessage* msg = NULL);
-dbus_bool_t dbus_func_args_async(DBusConnection *conn,
+
+dbus_bool_t dbus_func_send_async(DBusConnection* conn,
+                                 DBusMessage* msg,
                                  int timeout_ms,
-                                 void (*reply)(DBusMessage *, void *, void *),
-                                 void *user,
-                                 void *nat,
-                                 const char *path,
-                                 const char *ifc,
-                                 const char *func,
+                                 DBusCallback user_cb,
+                                 void* user);
+
+dbus_bool_t dbus_func_args_async(DBusConnection* conn,
+                                 int timeout_ms,
+                                 DBusCallback reply,
+                                 void* user,
+                                 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,
+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,
+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,
+DBusMessage*  dbus_func_args_timeout(DBusConnection* conn,
                                      int timeout_ms,
-                                     const char *path,
-                                     const char *ifc,
-                                     const char *func,
+                                     const char* path,
+                                     const char* ifc,
+                                     const char* func,
                                      int first_arg_type,
                                      ...);
 
-DBusMessage * dbus_func_args_timeout_valist(DBusConnection *conn,
+DBusMessage*  dbus_func_args_timeout_valist(DBusConnection* conn,
                                             int timeout_ms,
-                                            DBusError *err,
-                                            const char *path,
-                                            const char *ifc,
-                                            const char *func,
+                                            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
@@ -24,10 +24,10 @@ nsresult RawDBusConnection::EstablishDBu
     return NS_ERROR_FAILURE;
   }
   dbus_connection_set_exit_on_disconnect(mConnection, FALSE);
   return NS_OK;
 }
 
 void RawDBusConnection::ScopedDBusConnectionPtrTraits::release(DBusConnection* ptr)
 {
-  if(ptr) dbus_connection_unref(ptr);
+  if (ptr) dbus_connection_unref(ptr);
 }
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -20,18 +20,19 @@ EXPORT_LIBRARY = 1
 
 ##-----------------------------------------------------------------------------
 ## When you add IPDL files to a source directory, list the directory here.
 ##
 IPDLDIRS =  \
   uriloader/exthandler \
   dom/devicestorage \
   dom/indexedDB/ipc \
+  dom/bluetooth/ipc \
   dom/plugins/ipc  \
-  dom/ipc  \
+  dom/ipc \
   dom/sms/src/ipc \
   dom/src/storage \
   gfx/layers/ipc \
   hal/sandbox \
   ipc/testshell  \
   js/ipc  \
   layout/ipc \
   netwerk/ipc  \