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 99622 b1bab07e4390fa5ab6e2a4163b3cf081ebdd9f08
parent 99621 1dfcb36d7c176f9f9e88a128889e0ae48da482e7
child 99623 486769aaada148702503ef3b1d91a5c2a20793da
push id23140
push useremorley@mozilla.com
push dateWed, 18 Jul 2012 12:33:13 +0000
treeherdermozilla-central@134e66224b04 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent, mrbkap
bugs740744
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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  \