Bug 755943 - 'Electrolysize b2g-bluetooth'. r=qDot+cjones.
authorBen Turner <bent.mozilla@gmail.com>
Thu, 13 Sep 2012 09:37:14 -0700
changeset 110597 8604438c67ad8f9f39f81063f878209ac9b78372
parent 110596 a41731220fecc9d2d4c26ae8d7d731c36528a98b
child 110598 150886c947f07dfb5ad59eb3af862f8510eb8d66
push idunknown
push userunknown
push dateunknown
reviewersqDot
bugs755943
milestone18.0a1
Bug 755943 - 'Electrolysize b2g-bluetooth'. r=qDot+cjones.
dom/Makefile.in
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothCommon.h
dom/bluetooth/BluetoothDevice.cpp
dom/bluetooth/BluetoothManager.cpp
dom/bluetooth/BluetoothNullServiceFactory.cpp
dom/bluetooth/BluetoothPropertyContainer.cpp
dom/bluetooth/BluetoothPropertyEvent.cpp
dom/bluetooth/BluetoothReplyRunnable.cpp
dom/bluetooth/BluetoothService.cpp
dom/bluetooth/BluetoothService.h
dom/bluetooth/Makefile.in
dom/bluetooth/gonk/BluetoothGonkService.cpp
dom/bluetooth/gonk/BluetoothGonkService.h
dom/bluetooth/gonk/BluetoothGonkServiceFactory.cpp
dom/bluetooth/ipc/BluetoothChild.cpp
dom/bluetooth/ipc/BluetoothChild.h
dom/bluetooth/ipc/BluetoothMessageUtils.h
dom/bluetooth/ipc/BluetoothParent.cpp
dom/bluetooth/ipc/BluetoothParent.h
dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
dom/bluetooth/ipc/BluetoothServiceChildProcess.h
dom/bluetooth/ipc/PBluetooth.ipdl
dom/bluetooth/ipc/PBluetoothRequest.ipdl
dom/bluetooth/ipc/ipdl.mk
dom/bluetooth/linux/BluetoothDBusService.cpp
dom/bluetooth/linux/BluetoothDBusService.h
dom/bluetooth/linux/BluetoothDBusServiceFactory.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/Makefile.in
dom/ipc/PContent.ipdl
layout/build/Makefile.in
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -41,16 +41,17 @@ PARALLEL_DIRS = \
   $(NULL)
 
 PARALLEL_DIRS += \
   apps \
   base \
   activities \
   bindings \
   battery \
+  bluetooth \
   browser-element \
   contacts \
   alarm \
   devicestorage \
   file \
   media \
   messages \
   power \
@@ -75,22 +76,16 @@ PARALLEL_DIRS += \
 ifdef MOZ_B2G_RIL
 PARALLEL_DIRS += \
   telephony \
   wifi \
   icc \
   $(NULL)
 endif
 
-ifdef MOZ_B2G_BT
-PARALLEL_DIRS += \
-  bluetooth \
-  $(NULL)
-endif
-
 ifdef MOZ_PAY
 PARALLEL_DIRS += \
   payment \
   $(NULL)
 endif
 
 # bindings/test is here, because it needs to build after bindings/, and
 # we build subdirectories before ourselves.
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -4,32 +4,32 @@
  * 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 "BluetoothDevice.h"
 #include "BluetoothPropertyEvent.h"
 #include "BluetoothService.h"
-#include "BluetoothTypes.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothUtils.h"
 #include "GeneratedEvents.h"
 
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsIDOMBluetoothDeviceEvent.h"
 #include "nsIDOMBluetoothDeviceAddressEvent.h"
 #include "nsIDOMDOMRequest.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 using namespace mozilla;
 
 USING_BLUETOOTH_NAMESPACE
 
 DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
@@ -144,19 +144,19 @@ BluetoothAdapter::BluetoothAdapter(nsPID
   }
 }
 
 BluetoothAdapter::~BluetoothAdapter()
 {
   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!");
-    }
+    // XXXbent I don't see anything about LOCAL_AGENT_PATH or REMOTE_AGENT_PATH
+    //         here. Probably a bug? Maybe use UnregisterAll.
+    bs->UnregisterBluetoothSignalHandler(mPath, this);
   }
   Unroot();
 }
 
 void
 BluetoothAdapter::Unroot()
 {
   if (!mIsRooted) {
@@ -251,25 +251,19 @@ BluetoothAdapter::Create(nsPIDOMWindow* 
 {
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     NS_WARNING("BluetoothService not available!");
     return nullptr;
   }
 
   nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aOwner, aValue);
-  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(adapter->GetPath(), adapter))) {
-    NS_WARNING("Failed to register object with observer!");
-    return nullptr;
-  }
 
-  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(REMOTE_AGENT_PATH), adapter))) {
-    NS_WARNING("Failed to register remote agent object with observer!");
-    return nullptr;
-  }
+  bs->RegisterBluetoothSignalHandler(adapter->GetPath(), adapter);
+  bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(REMOTE_AGENT_PATH), adapter);
 
   return adapter.forget();
 }
 
 void
 BluetoothAdapter::Notify(const BluetoothSignal& aData)
 {
   InfallibleTArray<BluetoothNamedValue> arr;
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -2,19 +2,19 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluetoothcommon_h__
 #define mozilla_dom_bluetooth_bluetoothcommon_h__
 
-#include "nsString.h"
+#include "mozilla/Observer.h"
+#include "nsStringGlue.h"
 #include "nsTArray.h"
-#include "mozilla/Observer.h"
 
 #define BEGIN_BLUETOOTH_NAMESPACE \
   namespace mozilla { namespace dom { namespace bluetooth {
 #define END_BLUETOOTH_NAMESPACE \
   } /* namespace bluetooth */ } /* namespace dom */ } /* namespace mozilla */
 #define USING_BLUETOOTH_NAMESPACE \
   using namespace mozilla::dom::bluetooth;
 
@@ -36,14 +36,16 @@ class BluetoothSignal;
 typedef mozilla::Observer<BluetoothSignal> BluetoothSignalObserver;
 
 // Enums for object types, currently used for shared function lookups
 // (get/setproperty, etc...). Possibly discernable via dbus paths, but this
 // method is future-proofed for platform independence.
 enum BluetoothObjectType {
   TYPE_MANAGER = 0,
   TYPE_ADAPTER = 1,
-  TYPE_DEVICE = 2 
+  TYPE_DEVICE = 2,
+
+  TYPE_INVALID
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluetoothcommon_h__
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -2,25 +2,25 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "BluetoothDevice.h"
 #include "BluetoothPropertyEvent.h"
-#include "BluetoothTypes.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothUtils.h"
 #include "BluetoothServiceUuid.h"
 
 #include "nsIDOMDOMRequest.h"
 #include "nsDOMClassInfo.h"
 #include "nsContentUtils.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 DOMCI_DATA(BluetoothDevice, BluetoothDevice)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDevice)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothDevice,
@@ -64,19 +64,17 @@ BluetoothDevice::BluetoothDevice(nsPIDOM
   }
 }
 
 BluetoothDevice::~BluetoothDevice()
 {
   BluetoothService* bs = BluetoothService::Get();
   // bs can be null on shutdown, where destruction might happen.
   if (bs) {
-    if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mPath, this))) {
-      NS_WARNING("Failed to unregister object with observer!");
-    }
+    bs->UnregisterBluetoothSignalHandler(mPath, this);
   }
   Unroot();
 }
 
 void
 BluetoothDevice::Root()
 {
   if (!mIsRooted) {
@@ -102,18 +100,18 @@ BluetoothDevice::SetPropertyByValue(cons
   if (name.EqualsLiteral("Name")) {
     mName = value.get_nsString();
   } else if (name.EqualsLiteral("Path")) {
     mPath = value.get_nsString();
     NS_WARNING(NS_ConvertUTF16toUTF8(mPath).get());
     BluetoothService* bs = BluetoothService::Get();
     if (!bs) {
       NS_WARNING("BluetoothService not available!");
-    } else if (NS_FAILED(bs->RegisterBluetoothSignalHandler(mPath, this))) {
-      NS_WARNING("Failed to register object with observer!");
+    } else {
+      bs->RegisterBluetoothSignalHandler(mPath, this);
     }
   } else if (name.EqualsLiteral("Address")) {
     mAddress = value.get_nsString();
   } else if (name.EqualsLiteral("Class")) {
     mClass = value.get_uint32_t();
   } else if (name.EqualsLiteral("Icon")) {
     mIcon = value.get_nsString();
   } else if (name.EqualsLiteral("Connected")) {
@@ -172,20 +170,19 @@ BluetoothDevice::Create(nsPIDOMWindow* a
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     NS_WARNING("BluetoothService not available!");
     return nullptr;
   }
 
   nsRefPtr<BluetoothDevice> device = new BluetoothDevice(aOwner, aAdapterPath,
                                                          aValue);
-  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(device->mPath, device))) {
-    NS_WARNING("Failed to register object with observer!");
-    return nullptr;
-  }
+
+  bs->RegisterBluetoothSignalHandler(device->mPath, device);
+
   return device.forget();
 }
 
 void
 BluetoothDevice::Notify(const BluetoothSignal& aData)
 {
   if (aData.name().EqualsLiteral("PropertyChanged")) {
     // Get BluetoothNamedValue, make sure array length is 1
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -4,27 +4,27 @@
  * 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 "BluetoothAdapter.h"
 #include "BluetoothService.h"
-#include "BluetoothTypes.h"
 #include "BluetoothReplyRunnable.h"
 
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsIDOMDOMRequest.h"
 #include "nsIPermissionManager.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "mozilla/Util.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 using namespace mozilla;
 
 USING_BLUETOOTH_NAMESPACE
 
 DOMCI_DATA(BluetoothManager, BluetoothManager)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothManager)
deleted file mode 100644
--- a/dom/bluetooth/BluetoothNullServiceFactory.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "BluetoothService.h"
-
-USING_BLUETOOTH_NAMESPACE
-
-BluetoothService*
-BluetoothService::Create()
-{
-  NS_WARNING("Bluetooth not implemented for this platform!");
-  return nullptr;
-}
--- a/dom/bluetooth/BluetoothPropertyContainer.cpp
+++ b/dom/bluetooth/BluetoothPropertyContainer.cpp
@@ -2,18 +2,18 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "BluetoothPropertyContainer.h"
 #include "BluetoothService.h"
-#include "BluetoothTypes.h"
 #include "nsIDOMDOMRequest.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 nsresult
 BluetoothPropertyContainer::FirePropertyAlreadySet(nsIDOMWindow* aOwner,
                                                    nsIDOMDOMRequest** aRequest)
 {
   nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
--- a/dom/bluetooth/BluetoothPropertyEvent.cpp
+++ b/dom/bluetooth/BluetoothPropertyEvent.cpp
@@ -1,19 +1,19 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "BluetoothPropertyEvent.h"
-#include "BluetoothTypes.h"
 
 #include "nsDOMClassInfo.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 // static
 already_AddRefed<BluetoothPropertyEvent>
 BluetoothPropertyEvent::Create(const nsAString& aPropertyName)
 {
   NS_ASSERTION(!aPropertyName.IsEmpty(), "Empty Property String!");
--- a/dom/bluetooth/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/BluetoothReplyRunnable.cpp
@@ -1,18 +1,18 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
-#include "BluetoothTypes.h"
 #include "BluetoothReplyRunnable.h"
 #include "nsIDOMDOMRequest.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 BluetoothReplyRunnable::BluetoothReplyRunnable(nsIDOMDOMRequest* aReq)
   : mDOMRequest(aReq)
 {}
 
 void
@@ -81,19 +81,19 @@ BluetoothReplyRunnable::Run()
     }
   }
 
   if (NS_FAILED(rv)) {
     NS_WARNING("Could not fire DOMRequest!");
   }
 
   ReleaseMembers();
-  if (mDOMRequest) {
-    NS_WARNING("mDOMRequest still alive! Deriving class should call BluetoothReplyRunnable::ReleaseMembers()!");
-  }
+  MOZ_ASSERT(!mDOMRequest,
+             "mDOMRequest still alive! Deriving class should call "
+             "BluetoothReplyRunnable::ReleaseMembers()!");
 
   return rv;
 }
 
 BluetoothVoidReplyRunnable::BluetoothVoidReplyRunnable(nsIDOMDOMRequest* aReq)
   : BluetoothReplyRunnable(aReq)
 {}
 
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -2,43 +2,117 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "BluetoothService.h"
+
 #include "BluetoothManager.h"
-#include "BluetoothTypes.h"
+#include "BluetoothParent.h"
 #include "BluetoothReplyRunnable.h"
+#include "BluetoothServiceChildProcess.h"
 
 #include "jsapi.h"
 #include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/unused.h"
 #include "mozilla/Util.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "nsContentUtils.h"
 #include "nsIDOMDOMRequest.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
+#include "nsISystemMessagesInternal.h"
+#include "nsITimer.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMCIDInternal.h"
-#include "nsISystemMessagesInternal.h"
+#include "nsXULAppAPI.h"
+
+#if defined(MOZ_B2G_BT)
+# if defined(MOZ_BLUETOOTH_GONK)
+#  include "BluetoothGonkService.h"
+# elif defined(MOZ_BLUETOOTH_DBUS)
+#  include "BluetoothDBusService.h"
+# else
+#  error No_suitable_backend_for_bluetooth!
+# endif
+#endif
 
 #define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
 #define BLUETOOTH_ENABLED_SETTING "bluetooth.enabled"
 
+#define DEFAULT_SHUTDOWN_TIMER_MS 5000
+
 using namespace mozilla;
-
+using namespace mozilla::dom;
 USING_BLUETOOTH_NAMESPACE
 
-static nsRefPtr<BluetoothService> gBluetoothService;
-static bool gInShutdown = false;
+namespace {
+
+StaticRefPtr<BluetoothService> gBluetoothService;
+
+bool gInShutdown = false;
+
+bool
+IsMainProcess()
+{
+  return XRE_GetProcessType() == GeckoProcessType_Default;
+}
+
+PLDHashOperator
+RemoveAllSignalHandlers(const nsAString& aKey,
+                        nsAutoPtr<BluetoothSignalObserverList>& aData,
+                        void* aUserArg)
+{
+  aData->RemoveObserver(static_cast<BluetoothSignalObserver*>(aUserArg));
+  return aData->Length() ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
+}
+
+void
+ShutdownTimeExceeded(nsITimer* aTimer, void* aClosure)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  *static_cast<bool*>(aClosure) = true;
+}
 
-NS_IMPL_ISUPPORTS1(BluetoothService, nsIObserver)
+void
+GetAllBluetoothActors(InfallibleTArray<BluetoothParent*>& aActors)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aActors.IsEmpty());
+
+  nsAutoTArray<ContentParent*, 20> contentActors;
+  ContentParent::GetAll(contentActors);
+
+  for (uint32_t contentIndex = 0;
+       contentIndex < contentActors.Length();
+       contentIndex++) {
+    MOZ_ASSERT(contentActors[contentIndex]);
+
+    AutoInfallibleTArray<PBluetoothParent*, 5> bluetoothActors;
+    contentActors[contentIndex]->ManagedPBluetoothParent(bluetoothActors);
+
+    for (uint32_t bluetoothIndex = 0;
+         bluetoothIndex < bluetoothActors.Length();
+         bluetoothIndex++) {
+      MOZ_ASSERT(bluetoothActors[bluetoothIndex]);
+
+      BluetoothParent* actor =
+        static_cast<BluetoothParent*>(bluetoothActors[bluetoothIndex]);
+      aActors.AppendElement(actor);
+    }
+  }
+}
+
+} // anonymous namespace
 
 class BluetoothService::ToggleBtAck : public nsRunnable
 {
 public:
   ToggleBtAck(bool aEnabled)
     : mEnabled(aEnabled)
   {
     MOZ_ASSERT(!NS_IsMainThread());
@@ -118,100 +192,171 @@ private:
 class BluetoothService::StartupTask : public nsISettingsServiceCallback
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD Handle(const nsAString& aName, const jsval& aResult, JSContext* aCx)
   {
     MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(gBluetoothService);
 
     if (!aResult.isBoolean()) {
       NS_WARNING("Setting for '" BLUETOOTH_ENABLED_SETTING "' is not a boolean!");
       return NS_OK;
     }
 
-    return aResult.toBoolean() ? gBluetoothService->Start() : NS_OK;
+    // It is theoretically possible to shut down before the first settings check
+    // has completed (though extremely unlikely).
+    if (gBluetoothService) {
+      return gBluetoothService->HandleStartupSettingsCheck(aResult.toBoolean());
+    }
+
+    return NS_OK;
   }
 
   NS_IMETHOD HandleError(const nsAString& aName, JSContext* aCx)
   {
     NS_WARNING("Unable to get value for '" BLUETOOTH_ENABLED_SETTING "'");
     return NS_OK;
   }
 };
 
 NS_IMPL_ISUPPORTS1(BluetoothService::StartupTask, nsISettingsServiceCallback);
 
+NS_IMPL_ISUPPORTS1(BluetoothService, nsIObserver)
+
 BluetoothService::~BluetoothService()
 {
-  if (!gBluetoothService) {
-    return;
+  Cleanup();
+}
+
+// static
+BluetoothService*
+BluetoothService::Create()
+{
+#if defined(MOZ_B2G_BT)
+  if (!IsMainProcess()) {
+    return BluetoothServiceChildProcess::Create();
+  }
+#endif
+
+#if defined(MOZ_BLUETOOTH_GONK)
+  return new BluetoothGonkService();
+#elif defined(MOZ_BLUETOOTH_DBUS)
+  return new BluetoothDBusService();
+#else
+  NS_WARNING("No platform support for bluetooth!");
+  return nullptr;
+#endif
+}
+
+bool
+BluetoothService::Init()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  NS_ENSURE_TRUE(obs, false);
+
+  if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
+                                 false))) {
+    NS_WARNING("Failed to add shutdown observer!");
+    return false;
   }
 
-  if (NS_FAILED(gBluetoothService->UnregisterBluetoothSignalHandler(
-      NS_LITERAL_STRING(LOCAL_AGENT_PATH), gBluetoothService))) {
-    NS_WARNING("Unresgister observer to register local agent failed!");
+  // Only the main process should observe bluetooth settings changes.
+  if (IsMainProcess() &&
+      NS_FAILED(obs->AddObserver(this, MOZSETTINGS_CHANGED_ID, false))) {
+    NS_WARNING("Failed to add settings change observer!");
+    return false;
+  }
+
+  RegisterBluetoothSignalHandler(NS_LITERAL_STRING(LOCAL_AGENT_PATH), this);
+  mRegisteredForLocalAgent = true;
+
+  return true;
+}
+
+void
+BluetoothService::Cleanup()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mRegisteredForLocalAgent) {
+    UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(LOCAL_AGENT_PATH), this);
+    mRegisteredForLocalAgent = false;
+  }
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (obs &&
+      (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
+       NS_FAILED(obs->RemoveObserver(this, MOZSETTINGS_CHANGED_ID)))) {
+    NS_WARNING("Can't unregister observers!");
   }
 }
 
-nsresult
+void
 BluetoothService::RegisterBluetoothSignalHandler(const nsAString& aNodeName,
                                                  BluetoothSignalObserver* aHandler)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aHandler);
+
   BluetoothSignalObserverList* ol;
   if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
     ol = new BluetoothSignalObserverList();
     mBluetoothSignalObserverTable.Put(aNodeName, ol);
   }
   ol->AddObserver(aHandler);
-  return NS_OK;
 }
 
-nsresult
+void
 BluetoothService::UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
                                                    BluetoothSignalObserver* aHandler)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aHandler);
+
   BluetoothSignalObserverList* ol;
-  if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
-    NS_WARNING("Node does not exist to remove BluetoothSignalListener from!");
-    return NS_OK;
+  if (mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
+    ol->RemoveObserver(aHandler);
+    if (ol->Length() == 0) {
+      mBluetoothSignalObserverTable.Remove(aNodeName);
+    }
   }
-  ol->RemoveObserver(aHandler);
-  if (ol->Length() == 0) {
-    mBluetoothSignalObserverTable.Remove(aNodeName);
+  else {
+    NS_WARNING("Node was never registered!");
   }
-  return NS_OK;
 }
 
-nsresult
-BluetoothService::DistributeSignal(const BluetoothSignal& signal)
+void
+BluetoothService::UnregisterAllSignalHandlers(BluetoothSignalObserver* aHandler)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aHandler);
+
+  mBluetoothSignalObserverTable.Enumerate(RemoveAllSignalHandlers, aHandler);
+}
+
+void
+BluetoothService::DistributeSignal(const BluetoothSignal& aSignal)
 {
   MOZ_ASSERT(NS_IsMainThread());
   // Notify observers that a message has been sent
   BluetoothSignalObserverList* ol;
-  if (!mBluetoothSignalObserverTable.Get(signal.path(), &ol)) {
+  if (!mBluetoothSignalObserverTable.Get(aSignal.path(), &ol)) {
 #if DEBUG
-    nsString msg;
-    msg.AssignLiteral("No observer registered for path");
-    msg.Append(signal.path());
-    NS_WARNING(NS_ConvertUTF16toUTF8(msg).get());
+    nsAutoCString msg("No observer registered for path ");
+    msg.Append(NS_ConvertUTF16toUTF8(aSignal.path()));
+    NS_WARNING(msg.get());
 #endif
-    return NS_OK;
+    return;
   }
-#if DEBUG
-  if (ol->Length() == 0) {
-    NS_WARNING("Distributing to observer list of 0");
-  }
-#endif
-  ol->Broadcast(signal);
-  return NS_OK;
+  MOZ_ASSERT(ol->Length());
+  ol->Broadcast(aSignal);
 }
 
 nsresult
 BluetoothService::StartStopBluetooth(bool aStart)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
 #ifdef DEBUG
@@ -262,55 +407,70 @@ BluetoothService::SetEnabled(bool aEnabl
 
   if (aEnabled == mEnabled) {
     // Nothing to do, maybe something failed.
     return;
   }
 
   mEnabled = aEnabled;
 
+  AutoInfallibleTArray<BluetoothParent*, 10> childActors;
+  GetAllBluetoothActors(childActors);
+
+  for (uint32_t index = 0; index < childActors.Length(); index++) {
+    unused << childActors[index]->SendEnabled(aEnabled);
+  }
+
   BluetoothManagerList::ForwardIterator iter(mLiveManagers);
   while (iter.HasMore()) {
-    if (NS_FAILED(iter.GetNext()->FireEnabledDisabledEvent(mEnabled))) {
+    if (NS_FAILED(iter.GetNext()->FireEnabledDisabledEvent(aEnabled))) {
       NS_WARNING("FireEnabledDisabledEvent failed!");
     }
   }
 }
 
 nsresult
-BluetoothService::Start()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  return StartStopBluetooth(true);
-}
-
-nsresult
-BluetoothService::Stop()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  return StartStopBluetooth(false);
-}
-
-nsresult
 BluetoothService::HandleStartup()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mSettingsCheckInProgress);
 
   nsCOMPtr<nsISettingsService> settings =
     do_GetService("@mozilla.org/settingsService;1");
   NS_ENSURE_TRUE(settings, NS_ERROR_UNEXPECTED);
 
   nsCOMPtr<nsISettingsServiceLock> settingsLock;
   nsresult rv = settings->CreateLock(getter_AddRefs(settingsLock));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<StartupTask> callback = new StartupTask();
   rv = settingsLock->Get(BLUETOOTH_ENABLED_SETTING, callback);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  mSettingsCheckInProgress = true;
+  return NS_OK;
+}
+
+nsresult
+BluetoothService::HandleStartupSettingsCheck(bool aEnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!mSettingsCheckInProgress) {
+    // Somehow the enabled setting was changed before our first settings check
+    // completed. Don't do anything.
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(!IsEnabled());
+
+  if (aEnable) {
+    return StartStopBluetooth(true);
+  }
+
   return NS_OK;
 }
 
 nsresult
 BluetoothService::HandleSettingsChanged(const nsAString& aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -360,51 +520,106 @@ BluetoothService::HandleSettingsChanged(
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (!value.isBoolean()) {
     MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.enabled'!");
     return NS_ERROR_UNEXPECTED;
   }
 
+  if (mSettingsCheckInProgress) {
+    // Somehow the setting for bluetooth has been flipped before our first
+    // settings check completed. Flip this flag so that we ignore the result
+    // of that check whenever it finishes.
+    mSettingsCheckInProgress = false;
+  }
+
   if (value.toBoolean() == IsEnabled()) {
     // Nothing to do here.
     return NS_OK;
   }
 
   nsresult rv;
 
   if (IsEnabled()) {
-    rv = Stop();
+    rv = StartStopBluetooth(false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
-  rv = Start();
+  rv = StartStopBluetooth(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 BluetoothService::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  // This is a two phase shutdown. First we notify all child processes that
+  // bluetooth is going away, and then we wait for them to acknowledge. Then we
+  // close down all the bluetooth machinery.
+
   gInShutdown = true;
 
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  if (obs &&
-      (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
-       NS_FAILED(obs->RemoveObserver(this, MOZSETTINGS_CHANGED_ID)))) {
-    NS_WARNING("Can't unregister observers!");
+  Cleanup();
+
+  AutoInfallibleTArray<BluetoothParent*, 10> childActors;
+  GetAllBluetoothActors(childActors);
+
+  if (!childActors.IsEmpty()) {
+    // Notify child processes that they should stop using bluetooth now.
+    for (uint32_t index = 0; index < childActors.Length(); index++) {
+      childActors[index]->BeginShutdown();
+    }
+
+    // Create a timer to ensure that we don't wait forever for a child process
+    // or the bluetooth threads to finish. If we don't get a timer or can't use
+    // it for some reason then we skip all the waiting entirely since we really
+    // can't afford to hang on shutdown.
+    nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
+    MOZ_ASSERT(timer);
+
+    if (timer) {
+      bool timeExceeded = false;
+
+      if (NS_SUCCEEDED(timer->InitWithFuncCallback(ShutdownTimeExceeded,
+                                                   &timeExceeded,
+                                                   DEFAULT_SHUTDOWN_TIMER_MS,
+                                                   nsITimer::TYPE_ONE_SHOT))) {
+        nsIThread* currentThread = NS_GetCurrentThread();
+        MOZ_ASSERT(currentThread);
+
+        // Wait for those child processes to acknowledge.
+        while (!timeExceeded && !childActors.IsEmpty()) {
+          if (!NS_ProcessNextEvent(currentThread)) {
+            MOZ_ASSERT(false, "Something horribly wrong here!");
+            break;
+          }
+          GetAllBluetoothActors(childActors);
+        }
+
+        if (NS_FAILED(timer->Cancel())) {
+          MOZ_NOT_REACHED("Failed to cancel shutdown timer, this will crash!");
+        }
+      }
+      else {
+        MOZ_ASSERT(false, "Failed to initialize shutdown timer!");
+      }
+    }
   }
 
-  return Stop();
+  if (IsEnabled() && NS_FAILED(StartStopBluetooth(false))) {
+    MOZ_ASSERT(false, "Failed to deliver stop message!");
+  }
+
+  return NS_OK;
 }
 
 void
 BluetoothService::RegisterManager(BluetoothManager* aManager)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(!mLiveManagers.Contains(aManager));
@@ -440,34 +655,22 @@ BluetoothService::Get()
     NS_WARNING("BluetoothService can't be created during shutdown");
     return nullptr;
   }
 
   // Create new instance, register, return
   nsRefPtr<BluetoothService> service = BluetoothService::Create();
   NS_ENSURE_TRUE(service, nullptr);
 
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  NS_ENSURE_TRUE(obs, nullptr);
-
-  if (NS_FAILED(obs->AddObserver(service, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
-                                 false)) ||
-      NS_FAILED(obs->AddObserver(service, MOZSETTINGS_CHANGED_ID, false))) {
-    NS_WARNING("AddObserver failed!");
+  if (!service->Init()) {
+    service->Cleanup();
     return nullptr;
   }
 
-  gBluetoothService.swap(service);
-
-  if (NS_FAILED(gBluetoothService->RegisterBluetoothSignalHandler(
-    NS_LITERAL_STRING(LOCAL_AGENT_PATH), gBluetoothService))) {
-    NS_WARNING("Resgister observer to register local agent failed!");
-    return nullptr;
-  }
-
+  gBluetoothService = service;
   return gBluetoothService;
 }
 
 nsresult
 BluetoothService::Observe(nsISupports* aSubject, const char* aTopic,
                           const PRUnichar* aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -16,16 +16,18 @@
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothManager;
 class BluetoothNamedValue;
 class BluetoothReplyRunnable;
 class BluetoothSignal;
 
+typedef mozilla::ObserverList<BluetoothSignal> BluetoothSignalObserverList;
+
 class BluetoothService : public nsIObserver
                        , public BluetoothSignalObserver
 {
   class ToggleBtAck;
   friend class ToggleBtAck;
 
   class ToggleBtTask;
   friend class ToggleBtTask;
@@ -38,165 +40,128 @@ public:
   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);
+  virtual void
+  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
+   */
+  virtual void
+  UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
+                                   BluetoothSignalObserver* aMsgHandler);
+
+  /** 
+   * Remove a message handlers for the given observer.
+   * Must be called from the main thread.
    *
-   * @return NS_OK on successful removal from observer service,
-   * NS_ERROR_FAILED otherwise
+   * @param aMsgHandler Weak pointer to the object
    */
-  nsresult UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
-                                            BluetoothSignalObserver* aMsgHandler);
+  void
+  UnregisterAllSignalHandlers(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.
-   * @return NS_OK on initialization starting correctly, NS_ERROR_FAILURE
-   * otherwise
-   */
-  nsresult Start();
-
-  /** 
-   * 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.
-   *
-   * @return NS_OK on initialization starting correctly, NS_ERROR_FAILURE
-   * otherwise
-   */
-  nsresult Stop();
-
-  /**
-   * Called when XPCOM first creates this service.
-   */
-  nsresult HandleStartup();
-
-  /**
-   * Called when "mozsettings-changed" observer topic fires.
-   */
-  nsresult HandleSettingsChanged(const nsAString& aData);
-
-  /**
-   * Called when XPCOM is shutting down.
-   */
-  nsresult HandleShutdown();
+  void
+  DistributeSignal(const BluetoothSignal& aEvent);
 
   /**
    * Called when a BluetoothManager is created.
    */
-  void RegisterManager(BluetoothManager* aManager);
+  void
+  RegisterManager(BluetoothManager* aManager);
 
   /**
    * Called when a BluetoothManager is destroyed.
    */
-  void UnregisterManager(BluetoothManager* aManager);
+  void
+  UnregisterManager(BluetoothManager* aManager);
 
   /**
    * Called when get a Bluetooth Signal from BluetoothDBusService
    *
    */
-  void Notify(const BluetoothSignal& aParam);
+  void
+  Notify(const BluetoothSignal& aParam);
 
   /**
    * 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();
+  static BluetoothService*
+  Get();
 
-  static already_AddRefed<BluetoothService> FactoryCreate()
+  static already_AddRefed<BluetoothService>
+  FactoryCreate()
   {
     nsRefPtr<BluetoothService> service = Get();
     return service.forget();
   }
 
   /**
    * 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;
+  virtual nsresult
+  GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable) = 0;
 
   /**
    * Returns the properties of paired devices, implemented via a platform
    * specific method.
    *
    * @return NS_OK on success, NS_ERROR_FAILURE otherwise
    */
-  virtual nsresult GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
-                                                     BluetoothReplyRunnable* aRunnable) = 0;
+  virtual nsresult
+  GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
+                                    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;
+  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;
+  virtual nsresult
+  StartDiscoveryInternal(const nsAString& aAdapterPath,
+                         BluetoothReplyRunnable* aRunnable) = 0;
 
   /** 
    * Fetches the propertes for the specified object
    *
    * @param aType Type of the object (see BluetoothObjectType in BluetoothCommon.h)
    * @param aPath Path of the object
    * @param aRunnable Runnable to return to after receiving callback
    *
@@ -263,71 +228,132 @@ public:
                       int aType,
                       bool aAuth,
                       bool aEncrypt,
                       BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual bool
   CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable) = 0;
 
-  virtual bool SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode) = 0;
-  virtual bool SetPasskeyInternal(const nsAString& aDeviceAddress, uint32_t aPasskey) = 0;
-  virtual bool SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm) = 0;
-  virtual bool SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow) = 0;
+  virtual bool
+  SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode) = 0;
+
+  virtual bool
+  SetPasskeyInternal(const nsAString& aDeviceAddress, uint32_t aPasskey) = 0;
 
-  virtual bool IsEnabled()
+  virtual bool
+  SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm) = 0;
+
+  virtual bool
+  SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow) = 0;
+
+  bool
+  IsEnabled() const
   {
     return mEnabled;
   }
 
 protected:
   BluetoothService()
-  : mEnabled(false)
+  : mEnabled(false), mSettingsCheckInProgress(false),
+    mRegisteredForLocalAgent(false)
 #ifdef DEBUG
     , mLastRequestedEnable(false)
 #endif
   {
     mBluetoothSignalObserverTable.Init();
   }
 
-  ~BluetoothService();
+  virtual ~BluetoothService();
+
+  bool
+  Init();
+
+  void
+  Cleanup();
+
+  nsresult
+  StartStopBluetooth(bool aStart);
+
+  /** 
+   * 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;
 
-  nsresult StartStopBluetooth(bool aStart);
+  /** 
+   * 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;
+
+  /**
+   * Called when XPCOM first creates this service.
+   */
+  virtual nsresult
+  HandleStartup();
+
+  /**
+   * Called when the startup settings check has completed.
+   */
+  nsresult
+  HandleStartupSettingsCheck(bool aEnable);
+
+  /**
+   * Called when "mozsettings-changed" observer topic fires.
+   */
+  nsresult
+  HandleSettingsChanged(const nsAString& aData);
+
+  /**
+   * Called when XPCOM is shutting down.
+   */
+  virtual nsresult
+  HandleShutdown();
 
   // Called by ToggleBtAck.
-  void SetEnabled(bool aEnabled);
+  void
+  SetEnabled(bool aEnabled);
 
-  // This function is implemented in platform-specific BluetoothServiceFactory
-  // files
-  static BluetoothService* Create();
+  // Called by Get().
+  static BluetoothService*
+  Create();
 
   /**
    * Due to the fact that some operations require multiple calls, a
    * CommandThread is created that can run blocking, platform-specific calls
    * where either no asynchronous equivilent exists, or else where multiple
    * asynchronous calls would require excessive runnable bouncing between main
    * thread and IO thread.
    *
    * For instance, when we retrieve an Adapter object, we would like it to come
    * with all of its properties filled in and registered as an agent, which
    * requires a minimum of 3 calls to platform specific code on some platforms.
    *
    */
   nsCOMPtr<nsIThread> mBluetoothCommandThread;
 
-  typedef mozilla::ObserverList<BluetoothSignal> BluetoothSignalObserverList;
   typedef nsClassHashtable<nsStringHashKey, BluetoothSignalObserverList >
   BluetoothSignalObserverTable;
 
   BluetoothSignalObserverTable mBluetoothSignalObserverTable;
 
   typedef nsTObserverArray<BluetoothManager*> BluetoothManagerList;
   BluetoothManagerList mLiveManagers;
 
   bool mEnabled;
+  bool mSettingsCheckInProgress;
+  bool mRegisteredForLocalAgent;
+
 #ifdef DEBUG
   bool mLastRequestedEnable;
 #endif
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -13,79 +13,83 @@
 # limitations under the License.
 
 DEPTH            = @DEPTH@
 topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/dom/dom-config.mk
+
+VPATH += $(srcdir)/ipc
+
+EXPORTS_NAMESPACES = \
+  mozilla/dom/bluetooth \
+  mozilla/dom/bluetooth/ipc \
+  $(NULL)
+
+EXPORTS_mozilla/dom/bluetooth = BluetoothCommon.h
+EXPORTS_mozilla/dom/bluetooth/ipc = BluetoothMessageUtils.h
+
+ifneq (,$(MOZ_B2G_BT))
 
 MODULE           = dom
 LIBRARY_NAME     = dombluetooth_s
 XPIDL_MODULE     = dom_bluetooth
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 
-include $(topsrcdir)/dom/dom-config.mk
-
 CPPSRCS += \
   BluetoothService.cpp \
   BluetoothManager.cpp \
   BluetoothAdapter.cpp \
   BluetoothDevice.cpp \
   BluetoothPropertyEvent.cpp \
   BluetoothReplyRunnable.cpp \
   BluetoothPropertyContainer.cpp \
   BluetoothUtils.cpp \
+  BluetoothChild.cpp \
+  BluetoothParent.cpp \
+  BluetoothServiceChildProcess.cpp \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMNavigatorBluetooth.idl \
   nsIDOMBluetoothManager.idl \
   nsIDOMBluetoothAdapter.idl \
   nsIDOMBluetoothDevice.idl \
   nsIDOMBluetoothDeviceEvent.idl \
   nsIDOMBluetoothDeviceAddressEvent.idl \
   nsIDOMBluetoothPropertyEvent.idl \
   $(NULL)
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 VPATH += \
-	$(srcdir)/linux \
-	$(srcdir)/gonk \
-	$(NULL)
+  $(srcdir)/linux \
+  $(srcdir)/gonk \
+  $(NULL)
 LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
 CPPSRCS += \
-	BluetoothDBusService.cpp \
-	BluetoothGonkService.cpp \
-	BluetoothGonkServiceFactory.cpp \
-	$(NULL)
+  BluetoothDBusService.cpp \
+  BluetoothGonkService.cpp \
+  $(NULL)
+DEFINES += -DMOZ_BLUETOOTH_GONK
 else
 ifdef MOZ_ENABLE_DBUS
 VPATH += $(srcdir)/linux
 LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
-CPPSRCS += \
-	BluetoothDBusService.cpp \
-	BluetoothDBusServiceFactory.cpp \
-	$(NULL)
+CPPSRCS += BluetoothDBusService.cpp
 CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
 CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
-else
-CPPSRCS += BluetoothNullServiceFactory.cpp
+DEFINES += -DMOZ_BLUETOOTH_DBUS
 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%)
 
-# Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
-# subdirectory
-LOCAL_INCLUDES += $(VPATH:%=-I%)
+endif # MOZ_B2G_BT
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
-
-
-XPIDL_FLAGS += \
-  -I$(topsrcdir)/dom/interfaces/base \
-  -I$(topsrcdir)/dom/interfaces/events \
-  $(NULL)
--- a/dom/bluetooth/gonk/BluetoothGonkService.cpp
+++ b/dom/bluetooth/gonk/BluetoothGonkService.cpp
@@ -124,50 +124,40 @@ StartStopGonkBluetooth(bool aShouldEnabl
   if (!result) {
     NS_WARNING("Could not set gonk bluetooth firmware!");
     return NS_ERROR_FAILURE;
   }
   
   return NS_OK;
 }
 
-int
-BluetoothGonkService::IsEnabledInternal()
-{
-  if (!EnsureBluetoothInit()) {
-    NS_ERROR("Failed to load bluedroid library.\n");
-    return false;
-  }
-  return IsBluetoothEnabled();
-}
-
 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 ret;
   }
 
   return BluetoothDBusService::StartInternal();
 }
 
 nsresult
 BluetoothGonkService::StopInternal()
 {
   NS_ASSERTION(!NS_IsMainThread(), "This should not run on the main thread!");
 
   nsresult ret;
 
   ret = BluetoothDBusService::StopInternal();
 
   if (NS_FAILED(ret)) {
-    return ret;    
+    return ret;
   }
 
   return StartStopGonkBluetooth(false);
 }
 
--- a/dom/bluetooth/gonk/BluetoothGonkService.h
+++ b/dom/bluetooth/gonk/BluetoothGonkService.h
@@ -20,17 +20,17 @@
 
 #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
+ * 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 BluetoothGonkService : public BluetoothDBusService
 {
@@ -47,18 +47,13 @@ public:
   /** 
    * 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();
-
-  /**
-   * @return true if bluetooth daemon is enabled, false otherwise
-   */
-  virtual int IsEnabledInternal();
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
deleted file mode 100644
--- a/dom/bluetooth/gonk/BluetoothGonkServiceFactory.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Copyright 2012 Mozilla Foundation and Mozilla contributors
- *
- * 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 "BluetoothGonkService.h"
-
-USING_BLUETOOTH_NAMESPACE
-
-BluetoothService*
-BluetoothService::Create()
-{
-  return new BluetoothGonkService();
-}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/BluetoothChild.cpp
@@ -0,0 +1,168 @@
+/* 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 "BluetoothChild.h"
+
+#include "mozilla/Assertions.h"
+#include "nsDebug.h"
+#include "nsThreadUtils.h"
+#include "nsTraceRefcnt.h"
+
+#include "BluetoothReplyRunnable.h"
+#include "BluetoothService.h"
+#include "BluetoothServiceChildProcess.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+namespace {
+
+BluetoothServiceChildProcess* gBluetoothService;
+
+} // anonymous namespace
+
+/*******************************************************************************
+ * BluetoothChild
+ ******************************************************************************/
+
+BluetoothChild::BluetoothChild(BluetoothServiceChildProcess* aBluetoothService)
+: mShutdownState(Running)
+{
+  MOZ_COUNT_CTOR(BluetoothChild);
+  MOZ_ASSERT(!gBluetoothService);
+  MOZ_ASSERT(aBluetoothService);
+
+  gBluetoothService = aBluetoothService;
+}
+
+BluetoothChild::~BluetoothChild()
+{
+  MOZ_COUNT_DTOR(BluetoothChild);
+  MOZ_ASSERT(gBluetoothService);
+  MOZ_ASSERT(mShutdownState == Dead);
+
+  gBluetoothService = nullptr;
+}
+
+void
+BluetoothChild::BeginShutdown()
+{
+  // Only do something here if we haven't yet begun the shutdown sequence.
+  if (mShutdownState == Running) {
+    SendStopNotifying();
+    mShutdownState = SentStopNotifying;
+  }
+}
+
+void
+BluetoothChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  MOZ_ASSERT(gBluetoothService);
+
+  gBluetoothService->NoteDeadActor();
+
+#ifdef DEBUG
+  mShutdownState = Dead;
+#endif
+}
+
+bool
+BluetoothChild::RecvNotify(const BluetoothSignal& aSignal)
+{
+  MOZ_ASSERT(gBluetoothService);
+
+  gBluetoothService->DistributeSignal(aSignal);
+  return true;
+}
+
+bool
+BluetoothChild::RecvEnabled(const bool& aEnabled)
+{
+  MOZ_ASSERT(gBluetoothService);
+
+  gBluetoothService->SetEnabled(aEnabled);
+  return true;
+}
+
+bool
+BluetoothChild::RecvBeginShutdown()
+{
+  if (mShutdownState != Running && mShutdownState != SentStopNotifying) {
+    MOZ_ASSERT(false, "Bad state!");
+    return false;
+  }
+
+  SendStopNotifying();
+  mShutdownState = SentStopNotifying;
+
+  return true;
+}
+
+bool
+BluetoothChild::RecvNotificationsStopped()
+{
+  if (mShutdownState != SentStopNotifying) {
+    MOZ_ASSERT(false, "Bad state!");
+    return false;
+  }
+
+  Send__delete__(this);
+  return true;
+}
+
+PBluetoothRequestChild*
+BluetoothChild::AllocPBluetoothRequest(const Request& aRequest)
+{
+  MOZ_NOT_REACHED("Caller is supposed to manually construct a request!");
+  return nullptr;
+}
+
+bool
+BluetoothChild::DeallocPBluetoothRequest(PBluetoothRequestChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+/*******************************************************************************
+ * BluetoothRequestChild
+ ******************************************************************************/
+
+BluetoothRequestChild::BluetoothRequestChild(
+                                         BluetoothReplyRunnable* aReplyRunnable)
+: mReplyRunnable(aReplyRunnable)
+{
+  MOZ_COUNT_CTOR(BluetoothRequestChild);
+  MOZ_ASSERT(aReplyRunnable);
+}
+
+BluetoothRequestChild::~BluetoothRequestChild()
+{
+  MOZ_COUNT_DTOR(BluetoothRequestChild);
+}
+
+void
+BluetoothRequestChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  // Nothing needed here.
+}
+
+bool
+BluetoothRequestChild::Recv__delete__(const BluetoothReply& aReply)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mReplyRunnable);
+
+  nsRefPtr<BluetoothReplyRunnable> replyRunnable;
+  mReplyRunnable.swap(replyRunnable);
+
+  if (replyRunnable) {
+    // XXXbent Need to fix this, it copies unnecessarily.
+    replyRunnable->SetReply(new BluetoothReply(aReply));
+    return NS_SUCCEEDED(NS_DispatchToCurrentThread(replyRunnable));
+  }
+
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/BluetoothChild.h
@@ -0,0 +1,103 @@
+/* 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_ipc_bluetoothchild_h__
+#define mozilla_dom_bluetooth_ipc_bluetoothchild_h__
+
+#include "mozilla/dom/bluetooth/BluetoothCommon.h"
+
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
+#include "mozilla/dom/bluetooth/PBluetoothChild.h"
+#include "mozilla/dom/bluetooth/PBluetoothRequestChild.h"
+
+#include "mozilla/Attributes.h"
+#include "nsAutoPtr.h"
+
+namespace mozilla {
+namespace dom {
+namespace bluetooth {
+
+class BluetoothServiceChildProcess;
+
+} // namespace bluetooth
+} // namespace dom
+} // namespace mozilla
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothReplyRunnable;
+
+/*******************************************************************************
+ * BluetoothChild
+ ******************************************************************************/
+
+class BluetoothChild : public PBluetoothChild
+{
+  friend class mozilla::dom::bluetooth::BluetoothServiceChildProcess;
+
+  enum ShutdownState
+  {
+    Running = 0,
+    SentStopNotifying,
+    ReceivedNotificationsStopped,
+    Dead
+  };
+
+  ShutdownState mShutdownState;
+
+protected:
+  BluetoothChild(BluetoothServiceChildProcess* aBluetoothService);
+  virtual ~BluetoothChild();
+
+  void
+  BeginShutdown();
+
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvNotify(const BluetoothSignal& aSignal);
+
+  virtual bool
+  RecvEnabled(const bool& aEnabled) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvBeginShutdown() MOZ_OVERRIDE;
+
+  virtual bool
+  RecvNotificationsStopped() MOZ_OVERRIDE;
+
+  virtual PBluetoothRequestChild*
+  AllocPBluetoothRequest(const Request& aRequest) MOZ_OVERRIDE;
+
+  virtual bool
+  DeallocPBluetoothRequest(PBluetoothRequestChild* aActor) MOZ_OVERRIDE;
+};
+
+/*******************************************************************************
+ * BluetoothRequestChild
+ ******************************************************************************/
+
+class BluetoothRequestChild : public PBluetoothRequestChild
+{
+  friend class mozilla::dom::bluetooth::BluetoothChild;
+
+  nsRefPtr<BluetoothReplyRunnable> mReplyRunnable;
+
+public:
+  BluetoothRequestChild(BluetoothReplyRunnable* aReplyRunnable);
+
+protected:
+  virtual ~BluetoothRequestChild();
+
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  virtual bool
+  Recv__delete__(const BluetoothReply& aReply) MOZ_OVERRIDE;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif // mozilla_dom_bluetooth_ipc_bluetoothchild_h__
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/BluetoothMessageUtils.h
@@ -0,0 +1,22 @@
+/* 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_ipc_bluetoothmessageutils_h__
+#define mozilla_dom_bluetooth_ipc_bluetoothmessageutils_h__
+
+#include "mozilla/dom/bluetooth/BluetoothCommon.h"
+#include "ipc/IPCMessageUtils.h"
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::dom::bluetooth::BluetoothObjectType>
+  : public EnumSerializer<mozilla::dom::bluetooth::BluetoothObjectType,
+                          mozilla::dom::bluetooth::TYPE_MANAGER,
+                          mozilla::dom::bluetooth::TYPE_INVALID>
+{ };
+
+} // namespace IPC
+
+#endif // mozilla_dom_bluetooth_ipc_bluetoothchild_h__
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/BluetoothParent.cpp
@@ -0,0 +1,377 @@
+/* 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 "BluetoothParent.h"
+
+#include "mozilla/Assertions.h"
+#include "mozilla/unused.h"
+#include "mozilla/Util.h"
+#include "nsDebug.h"
+#include "nsThreadUtils.h"
+#include "nsTraceRefcnt.h"
+
+#include "BluetoothReplyRunnable.h"
+#include "BluetoothService.h"
+
+using mozilla::unused;
+USING_BLUETOOTH_NAMESPACE
+
+/*******************************************************************************
+ * BluetoothRequestParent::ReplyRunnable
+ ******************************************************************************/
+
+class BluetoothRequestParent::ReplyRunnable : public BluetoothReplyRunnable
+{
+  BluetoothRequestParent* mRequest;
+
+public:
+  ReplyRunnable(BluetoothRequestParent* aRequest)
+  : BluetoothReplyRunnable(nullptr), mRequest(aRequest)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(aRequest);
+  }
+
+  NS_IMETHOD
+  Run() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(mReply);
+
+    if (mRequest) {
+      // Must do this first because Send__delete__ will delete mRequest.
+      mRequest->RequestComplete();
+
+      if (!mRequest->Send__delete__(mRequest, *mReply)) {
+        NS_WARNING("Failed to send response to child process!");
+        return NS_ERROR_FAILURE;
+      }
+    }
+
+    ReleaseMembers();
+    return NS_OK;
+  }
+
+  void
+  Revoke()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    mRequest = nullptr;
+  }
+
+  virtual bool
+  ParseSuccessfulReply(jsval* aValue) MOZ_OVERRIDE
+  {
+    MOZ_NOT_REACHED("This should never be called!");
+    return false;
+  }
+};
+
+/*******************************************************************************
+ * BluetoothParent
+ ******************************************************************************/
+
+BluetoothParent::BluetoothParent()
+: mShutdownState(Running)
+{
+  MOZ_COUNT_CTOR(BluetoothParent);
+}
+
+BluetoothParent::~BluetoothParent()
+{
+  MOZ_COUNT_DTOR(BluetoothParent);
+  MOZ_ASSERT(!mService);
+  MOZ_ASSERT(mShutdownState == Dead);
+}
+
+void
+BluetoothParent::BeginShutdown()
+{
+  // Only do something here if we haven't yet begun the shutdown sequence.
+  if (mShutdownState == Running) {
+    unused << SendBeginShutdown();
+    mShutdownState = SentBeginShutdown;
+  }
+}
+
+bool
+BluetoothParent::InitWithService(BluetoothService* aService)
+{
+  MOZ_ASSERT(aService);
+  MOZ_ASSERT(!mService);
+
+  if (!SendEnabled(aService->IsEnabled())) {
+    return false;
+  }
+
+  mService = aService;
+  return true;
+}
+
+void
+BluetoothParent::UnregisterAllSignalHandlers()
+{
+  MOZ_ASSERT(mService);
+  mService->UnregisterAllSignalHandlers(this);
+}
+
+void
+BluetoothParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mService) {
+    UnregisterAllSignalHandlers();
+#ifdef DEBUG
+    mService = nullptr;
+#endif
+  }
+
+#ifdef DEBUG
+  mShutdownState = Dead;
+#endif
+}
+
+bool
+BluetoothParent::RecvRegisterSignalHandler(const nsString& aNode)
+{
+  MOZ_ASSERT(mService);
+  mService->RegisterBluetoothSignalHandler(aNode, this);
+  return true;
+}
+
+bool
+BluetoothParent::RecvUnregisterSignalHandler(const nsString& aNode)
+{
+  MOZ_ASSERT(mService);
+  mService->UnregisterBluetoothSignalHandler(aNode, this);
+  return true;
+}
+
+bool
+BluetoothParent::RecvStopNotifying()
+{
+  MOZ_ASSERT(mService);
+
+  if (mShutdownState != Running && mShutdownState != SentBeginShutdown) {
+    MOZ_ASSERT(false, "Bad state!");
+    return false;
+  }
+
+  mShutdownState = ReceivedStopNotifying;
+
+  UnregisterAllSignalHandlers();
+
+  if (SendNotificationsStopped()) {
+    mShutdownState = SentNotificationsStopped;
+    return true;
+  }
+
+  return false;
+}
+
+bool
+BluetoothParent::RecvPBluetoothRequestConstructor(
+                                                PBluetoothRequestParent* aActor,
+                                                const Request& aRequest)
+{
+  BluetoothRequestParent* actor = static_cast<BluetoothRequestParent*>(aActor);
+
+#ifdef DEBUG
+  actor->mRequestType = aRequest.type();
+#endif
+
+  switch (aRequest.type()) {
+     case Request::TDefaultAdapterPathRequest:
+       return actor->DoRequest(aRequest.get_DefaultAdapterPathRequest());
+     case Request::TSetPropertyRequest:
+       return actor->DoRequest(aRequest.get_SetPropertyRequest());
+     case Request::TGetPropertyRequest:
+       return actor->DoRequest(aRequest.get_GetPropertyRequest());
+     case Request::TStartDiscoveryRequest:
+       return actor->DoRequest(aRequest.get_StartDiscoveryRequest());
+     case Request::TStopDiscoveryRequest:
+       return actor->DoRequest(aRequest.get_StopDiscoveryRequest());
+     case Request::TPairRequest:
+       return actor->DoRequest(aRequest.get_PairRequest());
+     case Request::TUnpairRequest:
+       return actor->DoRequest(aRequest.get_UnpairRequest());
+     case Request::TDevicePropertiesRequest:
+       return actor->DoRequest(aRequest.get_DevicePropertiesRequest());
+
+     default:
+       MOZ_NOT_REACHED("Unknown type!");
+       return false;
+  }
+
+  MOZ_NOT_REACHED("Should never get here!");
+  return false;
+}
+
+PBluetoothRequestParent*
+BluetoothParent::AllocPBluetoothRequest(const Request& aRequest)
+{
+  MOZ_ASSERT(mService);
+  return new BluetoothRequestParent(mService);
+}
+
+bool
+BluetoothParent::DeallocPBluetoothRequest(PBluetoothRequestParent* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+void
+BluetoothParent::Notify(const BluetoothSignal& aSignal)
+{
+  unused << SendNotify(aSignal);
+}
+
+/*******************************************************************************
+ * BluetoothRequestParent
+ ******************************************************************************/
+
+BluetoothRequestParent::BluetoothRequestParent(BluetoothService* aService)
+: mService(aService)
+#ifdef DEBUG
+  , mRequestType(Request::T__None)
+#endif
+{
+  MOZ_COUNT_CTOR(BluetoothRequestParent);
+  MOZ_ASSERT(aService);
+
+  mReplyRunnable = new ReplyRunnable(this);
+}
+
+BluetoothRequestParent::~BluetoothRequestParent()
+{
+  MOZ_COUNT_DTOR(BluetoothRequestParent);
+
+  // mReplyRunnable will be automatically revoked.
+}
+
+void
+BluetoothRequestParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mReplyRunnable.Revoke();
+}
+
+void
+BluetoothRequestParent::RequestComplete()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mReplyRunnable.IsPending());
+
+  mReplyRunnable.Forget();
+}
+
+bool
+BluetoothRequestParent::DoRequest(const DefaultAdapterPathRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TDefaultAdapterPathRequest);
+
+  nsresult rv = mService->GetDefaultAdapterPathInternal(mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const SetPropertyRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TSetPropertyRequest);
+
+  nsresult rv =
+    mService->SetProperty(aRequest.type(), aRequest.path(), aRequest.value(),
+                          mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const GetPropertyRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TGetPropertyRequest);
+
+  nsresult rv =
+    mService->GetProperties(aRequest.type(), aRequest.path(),
+                            mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const StartDiscoveryRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TStartDiscoveryRequest);
+
+  nsresult rv =
+    mService->StartDiscoveryInternal(aRequest.path(), mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const StopDiscoveryRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TStopDiscoveryRequest);
+
+  nsresult rv =
+    mService->StopDiscoveryInternal(aRequest.path(), mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const PairRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TPairRequest);
+
+  nsresult rv =
+    mService->CreatePairedDeviceInternal(aRequest.path(), aRequest.address(),
+                                         aRequest.timeoutMS(),
+                                         mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const UnpairRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TUnpairRequest);
+
+  nsresult rv =
+    mService->RemoveDeviceInternal(aRequest.path(), aRequest.address(),
+                                   mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const DevicePropertiesRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TDevicePropertiesRequest);
+
+  nsresult rv =
+    mService->GetPairedDevicePropertiesInternal(aRequest.addresses(),
+                                                mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/BluetoothParent.h
@@ -0,0 +1,152 @@
+/* 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_ipc_bluetoothparent_h__
+#define mozilla_dom_bluetooth_ipc_bluetoothparent_h__
+
+#include "mozilla/dom/bluetooth/BluetoothCommon.h"
+
+#include "mozilla/dom/bluetooth/PBluetoothParent.h"
+#include "mozilla/dom/bluetooth/PBluetoothRequestParent.h"
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Observer.h"
+#include "nsAutoPtr.h"
+#include "nsTArray.h"
+
+template <class T>
+class nsRevocableEventPtr;
+
+namespace mozilla {
+namespace dom {
+
+class ContentParent;
+
+} // namespace dom
+} // namespace mozilla
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothService;
+
+/*******************************************************************************
+ * BluetoothParent
+ ******************************************************************************/
+
+class BluetoothParent : public PBluetoothParent,
+                        public mozilla::Observer<BluetoothSignal>
+{
+  friend class mozilla::dom::ContentParent;
+
+  enum ShutdownState
+  {
+    Running = 0,
+    SentBeginShutdown,
+    ReceivedStopNotifying,
+    SentNotificationsStopped,
+    Dead
+  };
+
+  nsRefPtr<BluetoothService> mService;
+  ShutdownState mShutdownState;
+  bool mReceivedStopNotifying;
+  bool mSentBeginShutdown;
+
+public:
+  void
+  BeginShutdown();
+
+protected:
+  BluetoothParent();
+  virtual ~BluetoothParent();
+
+  bool
+  InitWithService(BluetoothService* aService);
+
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvRegisterSignalHandler(const nsString& aNode) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvUnregisterSignalHandler(const nsString& aNode) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvStopNotifying() MOZ_OVERRIDE;
+
+  virtual bool
+  RecvPBluetoothRequestConstructor(PBluetoothRequestParent* aActor,
+                                   const Request& aRequest) MOZ_OVERRIDE;
+
+  virtual PBluetoothRequestParent*
+  AllocPBluetoothRequest(const Request& aRequest) MOZ_OVERRIDE;
+
+  virtual bool
+  DeallocPBluetoothRequest(PBluetoothRequestParent* aActor) MOZ_OVERRIDE;
+
+  virtual void
+  Notify(const BluetoothSignal& aSignal) MOZ_OVERRIDE;
+
+private:
+  void
+  UnregisterAllSignalHandlers();
+};
+
+/*******************************************************************************
+ * BluetoothAdapterRequestParent
+ ******************************************************************************/
+
+class BluetoothRequestParent : public PBluetoothRequestParent
+{
+  class ReplyRunnable;
+  friend class BluetoothParent;
+
+  friend class ReplyRunnable;
+
+  nsRefPtr<BluetoothService> mService;
+  nsRevocableEventPtr<ReplyRunnable> mReplyRunnable;
+
+#ifdef DEBUG
+  Request::Type mRequestType;
+#endif
+
+protected:
+  BluetoothRequestParent(BluetoothService* aService);
+  virtual ~BluetoothRequestParent();
+
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  void
+  RequestComplete();
+
+  bool
+  DoRequest(const DefaultAdapterPathRequest& aRequest);
+
+  bool
+  DoRequest(const SetPropertyRequest& aRequest);
+
+  bool
+  DoRequest(const GetPropertyRequest& aRequest);
+
+  bool
+  DoRequest(const StartDiscoveryRequest& aRequest);
+
+  bool
+  DoRequest(const StopDiscoveryRequest& aRequest);
+
+  bool
+  DoRequest(const PairRequest& aRequest);
+
+  bool
+  DoRequest(const UnpairRequest& aRequest);
+
+  bool
+  DoRequest(const DevicePropertiesRequest& aRequest);
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif // mozilla_dom_bluetooth_ipc_bluetoothparent_h__
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
@@ -0,0 +1,303 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this file,
+* You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+
+#include "BluetoothServiceChildProcess.h"
+
+#include "mozilla/Assertions.h"
+#include "mozilla/dom/ContentChild.h"
+
+#include "BluetoothChild.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+namespace {
+
+BluetoothChild* gBluetoothChild;
+
+inline
+void
+SendRequest(BluetoothReplyRunnable* aRunnable, const Request& aRequest)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aRunnable);
+
+  NS_WARN_IF_FALSE(gBluetoothChild,
+                   "Calling methods on BluetoothServiceChildProcess during "
+                   "shutdown!");
+
+  if (gBluetoothChild) {
+    BluetoothRequestChild* actor = new BluetoothRequestChild(aRunnable);
+    gBluetoothChild->SendPBluetoothRequestConstructor(actor, aRequest);
+  }
+}
+
+} // anonymous namespace
+
+// static
+BluetoothServiceChildProcess*
+BluetoothServiceChildProcess::Create()
+{
+  MOZ_ASSERT(!gBluetoothChild);
+
+  mozilla::dom::ContentChild* contentChild =
+    mozilla::dom::ContentChild::GetSingleton();
+  MOZ_ASSERT(contentChild);
+
+  BluetoothServiceChildProcess* btService = new BluetoothServiceChildProcess();
+
+  gBluetoothChild = new BluetoothChild(btService);
+  contentChild->SendPBluetoothConstructor(gBluetoothChild);
+
+  return btService;
+}
+
+BluetoothServiceChildProcess::BluetoothServiceChildProcess()
+{
+}
+
+BluetoothServiceChildProcess::~BluetoothServiceChildProcess()
+{
+  gBluetoothChild = nullptr;
+}
+
+void
+BluetoothServiceChildProcess::NoteDeadActor()
+{
+  MOZ_ASSERT(gBluetoothChild);
+  gBluetoothChild = nullptr;
+}
+
+void
+BluetoothServiceChildProcess::RegisterBluetoothSignalHandler(
+                                              const nsAString& aNodeName,
+                                              BluetoothSignalObserver* aHandler)
+{
+  if (gBluetoothChild) {
+    gBluetoothChild->SendRegisterSignalHandler(nsString(aNodeName));
+  }
+  BluetoothService::RegisterBluetoothSignalHandler(aNodeName, aHandler);
+}
+
+void
+BluetoothServiceChildProcess::UnregisterBluetoothSignalHandler(
+                                              const nsAString& aNodeName,
+                                              BluetoothSignalObserver* aHandler)
+{
+  if (gBluetoothChild) {
+    gBluetoothChild->SendUnregisterSignalHandler(nsString(aNodeName));
+  }
+  BluetoothService::UnregisterBluetoothSignalHandler(aNodeName, aHandler);
+}
+
+nsresult
+BluetoothServiceChildProcess::GetDefaultAdapterPathInternal(
+                                              BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, DefaultAdapterPathRequest());
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::GetPairedDevicePropertiesInternal(
+                                     const nsTArray<nsString>& aDeviceAddresses,
+                                     BluetoothReplyRunnable* aRunnable)
+{
+  DevicePropertiesRequest request;
+  request.addresses().AppendElements(aDeviceAddresses);
+
+  SendRequest(aRunnable, request);
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::StopDiscoveryInternal(
+                                              const nsAString& aAdapterPath,
+                                              BluetoothReplyRunnable* aRunnable) 
+{
+  SendRequest(aRunnable, StopDiscoveryRequest(nsString(aAdapterPath)));
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::StartDiscoveryInternal(
+                                              const nsAString& aAdapterPath,
+                                              BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, StartDiscoveryRequest(nsString(aAdapterPath)));
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::GetProperties(BluetoothObjectType aType,
+                                            const nsAString& aPath,
+                                            BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, GetPropertyRequest(aType, nsString(aPath)));
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::SetProperty(BluetoothObjectType aType,
+                                          const nsAString& aPath,
+                                          const BluetoothNamedValue& aValue,
+                                          BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, SetPropertyRequest(aType, nsString(aPath), aValue));
+  return NS_OK;
+}
+
+bool
+BluetoothServiceChildProcess::GetDevicePath(const nsAString& aAdapterPath,
+                                            const nsAString& aDeviceAddress,
+                                            nsAString& aDevicePath)
+{
+  // XXXbent Right now this is adapted from BluetoothDBusService's
+  //         GetObjectPathFromAddress. This is basically a sync call that cannot
+  //         be forwarded to the parent process without blocking. Hopefully this
+  //         can be reworked.
+  nsAutoString path(aAdapterPath);
+  path.AppendLiteral("/dev_");
+  path.Append(aDeviceAddress);
+  path.ReplaceChar(':', '_');
+
+  aDevicePath = path;
+
+  return NS_OK;
+}
+
+bool
+BluetoothServiceChildProcess::AddReservedServicesInternal(
+                                   const nsAString& aAdapterPath,
+                                   const nsTArray<uint32_t>& aServices,
+                                   nsTArray<uint32_t>& aServiceHandlesContainer)
+{
+  MOZ_NOT_REACHED("This function isn't used!");
+  return false;
+}
+
+bool
+BluetoothServiceChildProcess::RemoveReservedServicesInternal(
+                                      const nsAString& aAdapterPath,
+                                      const nsTArray<uint32_t>& aServiceHandles)
+{
+  MOZ_NOT_REACHED("This function isn't used!");
+  return false;
+}
+
+nsresult
+BluetoothServiceChildProcess::CreatePairedDeviceInternal(
+                                              const nsAString& aAdapterPath,
+                                              const nsAString& aAddress,
+                                              int aTimeout,
+                                              BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable,
+              PairRequest(nsString(aAdapterPath), nsString(aAddress), aTimeout));
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::RemoveDeviceInternal(
+                                              const nsAString& aAdapterPath,
+                                              const nsAString& aObjectPath,
+                                              BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable,
+              UnpairRequest(nsString(aAdapterPath), nsString(aObjectPath)));
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::GetSocketViaService(
+                                              const nsAString& aObjectPath,
+                                              const nsAString& aService,
+                                              int aType,
+                                              bool aAuth,
+                                              bool aEncrypt,
+                                              BluetoothReplyRunnable* aRunnable)
+{
+  MOZ_NOT_REACHED("Implement me!");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+bool
+BluetoothServiceChildProcess::CloseSocket(int aFd,
+                                          BluetoothReplyRunnable* aRunnable)
+{
+  MOZ_NOT_REACHED("Implement me!");
+  return false;
+}
+
+bool
+BluetoothServiceChildProcess::SetPinCodeInternal(
+                                                const nsAString& aDeviceAddress,
+                                                const nsAString& aPinCode)
+{
+  MOZ_NOT_REACHED("Implement me!");
+  return false;
+}
+
+bool
+BluetoothServiceChildProcess::SetPasskeyInternal(
+                                                const nsAString& aDeviceAddress,
+                                                uint32_t aPasskey)
+{
+  MOZ_NOT_REACHED("Implement me!");
+  return false;
+}
+
+bool
+BluetoothServiceChildProcess::SetPairingConfirmationInternal(
+                                                const nsAString& aDeviceAddress,
+                                                bool aConfirm)
+{
+  MOZ_NOT_REACHED("Implement me!");
+  return false;
+}
+
+bool
+BluetoothServiceChildProcess::SetAuthorizationInternal(
+                                                const nsAString& aDeviceAddress,
+                                                bool aAllow)
+{
+  MOZ_NOT_REACHED("Implement me!");
+  return false;
+}
+
+nsresult
+BluetoothServiceChildProcess::HandleStartup()
+{
+  // Don't need to do anything here for startup since our Create function takes
+  // care of the actor machinery.
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::HandleShutdown()
+{
+  // If this process is shutting down then we need to disconnect ourselves from
+  // the parent.
+  if (gBluetoothChild) {
+    gBluetoothChild->BeginShutdown();
+  }
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::StartInternal()
+{
+  MOZ_NOT_REACHED("This should never be called!");
+  return NS_ERROR_FAILURE;
+}
+
+nsresult
+BluetoothServiceChildProcess::StopInternal()
+{
+  MOZ_NOT_REACHED("This should never be called!");
+  return NS_ERROR_FAILURE;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
@@ -0,0 +1,152 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_ipc_bluetoothservicechildprocess_h__
+#define mozilla_dom_bluetooth_ipc_bluetoothservicechildprocess_h__
+
+#include "BluetoothService.h"
+
+namespace mozilla {
+namespace dom {
+namespace bluetooth {
+
+class BluetoothChild;
+
+} // namespace bluetooth
+} // namespace dom
+} // namespace mozilla
+
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothServiceChildProcess : public BluetoothService
+{
+  friend class mozilla::dom::bluetooth::BluetoothChild;
+
+public:
+  static BluetoothServiceChildProcess*
+  Create();
+
+  virtual void
+  RegisterBluetoothSignalHandler(const nsAString& aNodeName,
+                                 BluetoothSignalObserver* aMsgHandler)
+                                 MOZ_OVERRIDE;
+
+  virtual void
+  UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
+                                   BluetoothSignalObserver* aMsgHandler)
+                                   MOZ_OVERRIDE;
+
+  virtual nsresult
+  GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual nsresult
+  GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
+                                    BluetoothReplyRunnable* aRunnable)
+                                    MOZ_OVERRIDE;
+
+  virtual nsresult
+  StopDiscoveryInternal(const nsAString& aAdapterPath,
+                        BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual nsresult
+  StartDiscoveryInternal(const nsAString& aAdapterPath,
+                         BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual nsresult
+  GetProperties(BluetoothObjectType aType,
+                const nsAString& aPath,
+                BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual nsresult
+  SetProperty(BluetoothObjectType aType,
+              const nsAString& aPath,
+              const BluetoothNamedValue& aValue,
+              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual bool
+  GetDevicePath(const nsAString& aAdapterPath,
+                const nsAString& aDeviceAddress,
+                nsAString& aDevicePath) MOZ_OVERRIDE;
+
+  virtual bool
+  AddReservedServicesInternal(const nsAString& aAdapterPath,
+                              const nsTArray<uint32_t>& aServices,
+                              nsTArray<uint32_t>& aServiceHandlesContainer)
+                              MOZ_OVERRIDE;
+
+  virtual bool
+  RemoveReservedServicesInternal(const nsAString& aAdapterPath,
+                                 const nsTArray<uint32_t>& aServiceHandles)
+                                 MOZ_OVERRIDE;
+
+  virtual nsresult
+  CreatePairedDeviceInternal(const nsAString& aAdapterPath,
+                             const nsAString& aAddress,
+                             int aTimeout,
+                             BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual nsresult
+  RemoveDeviceInternal(const nsAString& aAdapterPath,
+                       const nsAString& aObjectPath,
+                       BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual nsresult
+  GetSocketViaService(const nsAString& aObjectPath,
+                      const nsAString& aService,
+                      int aType,
+                      bool aAuth,
+                      bool aEncrypt,
+                      BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual bool
+  CloseSocket(int aFd, BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual bool
+  SetPinCodeInternal(const nsAString& aDeviceAddress,
+                     const nsAString& aPinCode) MOZ_OVERRIDE;
+
+  virtual bool
+  SetPasskeyInternal(const nsAString& aDeviceAddress,
+                     uint32_t aPasskey) MOZ_OVERRIDE;
+
+  virtual bool
+  SetPairingConfirmationInternal(const nsAString& aDeviceAddress,
+                                 bool aConfirm) MOZ_OVERRIDE;
+
+  virtual bool
+  SetAuthorizationInternal(const nsAString& aDeviceAddress,
+                           bool aAllow) MOZ_OVERRIDE;
+
+protected:
+  BluetoothServiceChildProcess();
+  virtual ~BluetoothServiceChildProcess();
+
+  void
+  NoteDeadActor();
+
+  void
+  NoteShutdownInitiated();
+
+  virtual nsresult
+  HandleStartup() MOZ_OVERRIDE;
+
+  virtual nsresult
+  HandleShutdown() MOZ_OVERRIDE;
+
+private:
+  // This method should never be called.
+  virtual nsresult
+  StartInternal() MOZ_OVERRIDE;
+
+  // This method should never be called.
+  virtual nsresult
+  StopInternal() MOZ_OVERRIDE;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif // mozilla_dom_bluetooth_ipc_bluetoothservicechildprocess_h__
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/PBluetooth.ipdl
@@ -0,0 +1,178 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PBluetoothRequest;
+include protocol PContent;
+
+include BluetoothTypes;
+
+include "mozilla/dom/bluetooth/ipc/BluetoothMessageUtils.h";
+
+using mozilla::dom::bluetooth::BluetoothObjectType;
+
+namespace mozilla {
+namespace dom {
+namespace bluetooth {
+
+/**
+ * Bluetooth request types.
+ */
+
+struct DefaultAdapterPathRequest
+{ };
+
+struct SetPropertyRequest
+{
+  BluetoothObjectType type;
+  nsString path;
+  BluetoothNamedValue value;
+};
+
+struct GetPropertyRequest
+{
+  BluetoothObjectType type;
+  nsString path;
+};
+
+struct StartDiscoveryRequest
+{
+  nsString path;
+};
+
+struct StopDiscoveryRequest
+{
+  nsString path;
+};
+
+struct PairRequest
+{
+  nsString path;
+  nsString address;
+  uint32_t timeoutMS;
+};
+
+struct UnpairRequest
+{
+  nsString path;
+  nsString address;
+};
+
+struct DevicePropertiesRequest
+{
+  nsString[] addresses;
+};
+
+union Request
+{
+  DefaultAdapterPathRequest;
+  SetPropertyRequest;
+  GetPropertyRequest;
+  StartDiscoveryRequest;
+  StopDiscoveryRequest;
+  PairRequest;
+  UnpairRequest;
+  DevicePropertiesRequest;
+};
+
+protocol PBluetooth
+{
+  manager PContent;
+  manages PBluetoothRequest;
+
+  /**
+   * The potential exists for a racy shutdown so the following sequence of
+   * messages is used to shutdown safely:
+   *
+   *   1. [BeginShutdown]       (Parent -> Child [Optional])
+   *   2. StopNotifying         (Child  -> Parent)
+   *   3. NotificationsStopped  (Parent -> Child)
+   *   4. __delete__()          (Child  -> Parent)
+   */
+
+child:
+  /**
+   * Sent when a settings change has enabled or disabled the bluetooth firmware.
+   */
+  Enabled(bool enabled);
+
+  /**
+   * Sent when a bluetooth signal is broadcasted to child processes.
+   */
+  Notify(BluetoothSignal signal);
+
+  /**
+   * Sent when the parent process is about to be shut down. See shutdown note
+   * above.
+   */
+  BeginShutdown();
+
+  /**
+   * Sent to inform the child process that it will no longer receive any
+   * messages from the parent. See shutdown note above.
+   */
+  NotificationsStopped();
+
+parent:
+  /**
+   * Sent when the child no longer needs to use bluetooth. See shutdown note
+   * above.
+   */
+  __delete__();
+
+  /**
+   * Sent when the child needs to receive signals related to the given node.
+   */
+  RegisterSignalHandler(nsString node);
+
+  /**
+   * Sent when the child no longer needs to receive signals related to the given
+   * node.
+   */
+  UnregisterSignalHandler(nsString node);
+
+  /**
+   * Sent when the child no longer needs to receive any messages from the
+   * parent. See shutdown note above.
+   */
+  StopNotifying();
+
+  /**
+   * Sent when the child makes an asynchronous request to the parent.
+   */
+  PBluetoothRequest(Request request);
+
+  /**
+   * FIXME: Bug 547703.
+   *
+   * This is the state machine we want:
+   *
+   * start state NOTIFYING:
+   *   send Enabled goto NOTIFYING;
+   *   send Notify goto NOTIFYING;
+   *   recv RegisterSignalHandler goto NOTIFYING;
+   *   recv UnregisterSignalHandler goto NOTIFYING;
+   *   send BeginShutdown goto PARENT_DONE;
+   *   recv StopNotifying goto CHILD_DONE;
+   *
+   * state PARENT_DONE:
+   *   recv RegisterSignalHandler goto PARENT_DONE;
+   *   recv UnregisterSignalHandler goto PARENT_DONE;
+   *   recv StopNotifying goto CHILD_DONE;
+   *
+   * state CHILD_DONE:
+   *   send Enabled goto CHILD_DONE;
+   *   send Notify goto CHILD_DONE;
+   *   send BeginShutdown goto CHILD_DONE;
+   *   send NotificationsStopped goto DONE;
+   *
+   * state DONE:
+   *   recv __delete__;
+   */
+};
+
+} // namespace bluetooth
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/ipc/PBluetoothRequest.ipdl
@@ -0,0 +1,28 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PBluetooth;
+
+include BluetoothTypes;
+
+namespace mozilla {
+namespace dom {
+namespace bluetooth {
+
+protocol PBluetoothRequest
+{
+  manager PBluetooth;
+
+child:
+  /**
+   * Sent when the asynchronous request has completed.
+   */
+  __delete__(BluetoothReply response);
+};
+
+} // namespace bluetooth
+} // namespace dom
+} // namespace mozilla
--- a/dom/bluetooth/ipc/ipdl.mk
+++ b/dom/bluetooth/ipc/ipdl.mk
@@ -1,7 +1,9 @@
 # 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 \
+  PBluetooth.ipdl \
+  PBluetoothRequest.ipdl \
   $(NULL)
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -14,32 +14,32 @@
 ** 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 "BluetoothServiceUuid.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 "nsDataHashtable.h"
 #include "mozilla/ipc/Socket.h"
 #include "mozilla/ipc/DBusThread.h"
 #include "mozilla/ipc/DBusUtils.h"
 #include "mozilla/ipc/RawDBusConnection.h"
 #include "mozilla/Util.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.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
@@ -189,17 +189,18 @@ public:
   Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
     BluetoothService* bs = BluetoothService::Get();
     if (!bs) {
       NS_WARNING("BluetoothService not available!");
       return NS_ERROR_FAILURE;
     }
-    return bs->DistributeSignal(mSignal);
+    bs->DistributeSignal(mSignal);
+    return NS_OK;
   }
 };
 
 static bool
 IsDBusMessageError(DBusMessage* aMsg, DBusError* aErr, nsAString& aErrorStr)
 {
   if (aErr && dbus_error_is_set(aErr)) {
     aErrorStr = NS_ConvertUTF8toUTF16(aErr->message);
@@ -235,16 +236,17 @@ DispatchBluetoothReply(BluetoothReplyRun
                        const BluetoothValue& aValue, const nsAString& aErrorStr)
 {
   // Reply will be deleted by the runnable after running on main thread
   BluetoothReply* reply;
   if (!aErrorStr.IsEmpty()) {
     nsString err(aErrorStr);
     reply = new BluetoothReply(BluetoothReplyError(err));
   } else {
+    MOZ_ASSERT(aValue.type() != BluetoothValue::T__None);
     reply = new BluetoothReply(BluetoothReplySuccess(aValue));
   }
   
   aRunnable->SetReply(reply);
   if (NS_FAILED(NS_DispatchToMainThread(aRunnable))) {
     NS_WARNING("Failed to dispatch to main thread!");
   }
 }
@@ -609,16 +611,20 @@ UnpackVoidMessage(DBusMessage* aMsg, DBu
   if (!IsDBusMessageError(aMsg, aErr, aErrorStr) &&
       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)) {
       aErrorStr = NS_ConvertUTF8toUTF16(err.message);
       LOG_AND_FREE_DBUS_ERROR(&err);
     }
   }
+  // XXXbent Need to figure out something better than this here.
+  if (aErrorStr.IsEmpty()) {
+    aValue = true;
+  }
 }
 
 void
 GetVoidCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
   RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                   UnpackVoidMessage);
 }
@@ -1101,24 +1107,16 @@ BluetoothDBusService::StopInternal()
 
   sAuthorizeReqTable.EnumerateRead(UnrefDBusMessages, nullptr);
   sAuthorizeReqTable.Clear();
 
   StopDBus();
   return NS_OK;
 }
 
-
-int
-BluetoothDBusService::IsEnabledInternal()
-{
-  // assume bluetooth is always enabled on desktop
-  return true;
-}
-
 class DefaultAdapterPropertiesRunnable : public nsRunnable
 {
 public:
   DefaultAdapterPropertiesRunnable(BluetoothReplyRunnable* aRunnable)
     : mRunnable(dont_AddRef(aRunnable))
   {
   }
 
@@ -1206,22 +1204,18 @@ BluetoothDBusService::GetDefaultAdapterP
   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!");
+  NS_ASSERTION(mConnection, "Must have a connection here!");
 
   nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
 
   NS_ConvertUTF16toUTF8 s(aAdapterPath);
   if (!dbus_func_args_async(mConnection,
                             1000,
                             GetVoidCallback,
                             (void*)aRunnable,
@@ -1235,23 +1229,31 @@ BluetoothDBusService::SendDiscoveryMessa
   runnable.forget();
   return NS_OK;
 }
 
 nsresult
 BluetoothDBusService::StopDiscoveryInternal(const nsAString& aAdapterPath,
                                             BluetoothReplyRunnable* aRunnable)
 {
+  if (!mConnection) {
+    NS_WARNING("Bluetooth service not started yet, no need to stop discovery.");
+    return NS_OK;
+  }
   return SendDiscoveryMessage(aAdapterPath, "StopDiscovery", aRunnable);
 }
  
 nsresult
 BluetoothDBusService::StartDiscoveryInternal(const nsAString& aAdapterPath,
                                              BluetoothReplyRunnable* aRunnable)
 {
+  if (!mConnection) {
+    NS_WARNING("Bluetooth service not started yet, cannot start discovery!");
+    return NS_ERROR_FAILURE;
+  }
   return SendDiscoveryMessage(aAdapterPath, "StartDiscovery", aRunnable);
 }
 
 class BluetoothPairedDevicePropertiesRunnable : public nsRunnable
 {
 public:
   BluetoothPairedDevicePropertiesRunnable(BluetoothReplyRunnable* aRunnable,
                                           const nsTArray<nsString>& aDeviceAddresses)
--- a/dom/bluetooth/linux/BluetoothDBusService.h
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -84,18 +84,16 @@ public:
   SetPasskeyInternal(const nsAString& aDeviceAddress, uint32_t aPasskey);
 
   virtual bool 
   SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm);
 
   virtual bool 
   SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow);
 
-  virtual int IsEnabledInternal();
-
 private:
   nsresult SendGetPropertyMessage(const nsAString& aPath,
                                   const char* aInterface,
                                   void (*aCB)(DBusMessage *, void *),
                                   BluetoothReplyRunnable* aRunnable);
   nsresult SendDiscoveryMessage(const nsAString& aAdapterPath,
                                 const char* aMessageName,
                                 BluetoothReplyRunnable* aRunnable);
deleted file mode 100644
--- a/dom/bluetooth/linux/BluetoothDBusServiceFactory.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "BluetoothDBusService.h"
-
-USING_BLUETOOTH_NAMESPACE
-
-BluetoothService*
-BluetoothService::Create()
-{
-  return new BluetoothDBusService();
-}
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -87,28 +87,30 @@
 
 #ifdef ACCESSIBILITY
 #include "nsIAccessibilityService.h"
 #endif
 
 #include "mozilla/dom/indexedDB/PIndexedDBChild.h"
 #include "mozilla/dom/sms/SmsChild.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
+#include "mozilla/dom/bluetooth/PBluetoothChild.h"
 
 #include "nsDOMFile.h"
 #include "nsIRemoteBlob.h"
 #include "ProcessUtils.h"
 #include "StructuredCloneUtils.h"
 #include "URIUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 
 using namespace base;
 using namespace mozilla::docshell;
+using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
 using namespace mozilla::places;
@@ -695,16 +697,40 @@ ContentChild::AllocPStorage(const Storag
 bool
 ContentChild::DeallocPStorage(PStorageChild* aActor)
 {
     StorageChild* child = static_cast<StorageChild*>(aActor);
     child->ReleaseIPDLReference();
     return true;
 }
 
+PBluetoothChild*
+ContentChild::AllocPBluetooth()
+{
+#ifdef MOZ_B2G_BT
+    MOZ_NOT_REACHED("No one should be allocating PBluetoothChild actors");
+    return nullptr;
+#else
+    MOZ_NOT_REACHED("No support for bluetooth on this platform!");
+    return nullptr;
+#endif
+}
+
+bool
+ContentChild::DeallocPBluetooth(PBluetoothChild* aActor)
+{
+#ifdef MOZ_B2G_BT
+    delete aActor;
+    return true;
+#else
+    MOZ_NOT_REACHED("No support for bluetooth on this platform!");
+    return false;
+#endif
+}
+
 bool
 ContentChild::RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
                                  const InfallibleTArray<ResourceMapping>& resources,
                                  const InfallibleTArray<OverrideMapping>& overrides,
                                  const nsCString& locale)
 {
     nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
     nsChromeRegistryContent* chromeRegistry =
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -130,16 +130,19 @@ public:
     virtual bool DeallocPExternalHelperApp(PExternalHelperAppChild *aService);
 
     virtual PSmsChild* AllocPSms();
     virtual bool DeallocPSms(PSmsChild*);
 
     virtual PStorageChild* AllocPStorage(const StorageConstructData& aData);
     virtual bool DeallocPStorage(PStorageChild* aActor);
 
+    virtual PBluetoothChild* AllocPBluetooth();
+    virtual bool DeallocPBluetooth(PBluetoothChild* aActor);
+
     virtual bool RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
                                     const InfallibleTArray<ResourceMapping>& resources,
                                     const InfallibleTArray<OverrideMapping>& overrides,
                                     const nsCString& locale);
 
     virtual bool RecvSetOffline(const bool& offline);
 
     virtual bool RecvNotifyVisited(const URIParams& aURI);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -21,16 +21,17 @@
 #include "IDBFactory.h"
 #include "IndexedDBParent.h"
 #include "IndexedDatabaseManager.h"
 #include "mozIApplication.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
 #include "mozilla/dom/PMemoryReportRequestParent.h"
 #include "mozilla/dom/StorageParent.h"
+#include "mozilla/dom/bluetooth/PBluetoothParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
 #include "mozilla/dom/sms/SmsParent.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/Preferences.h"
@@ -100,20 +101,26 @@
 # include "AndroidBridge.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsIVolume.h"
 #include "nsIVolumeService.h"
 #endif
 
+#ifdef MOZ_B2G_BT
+#include "BluetoothParent.h"
+#include "BluetoothService.h"
+#endif
+
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 static const char* sClipboardTextFlavors[] = { kUnicodeMime };
 
 using base::KillProcess;
+using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
 using namespace mozilla::places;
@@ -1453,16 +1460,56 @@ ContentParent::AllocPStorage(const Stora
 
 bool
 ContentParent::DeallocPStorage(PStorageParent* aActor)
 {
     delete aActor;
     return true;
 }
 
+PBluetoothParent*
+ContentParent::AllocPBluetooth()
+{
+#ifdef MOZ_B2G_BT
+    if (!AppProcessHasPermission(this, "bluetooth")) {
+        return nullptr;
+    }
+    return new mozilla::dom::bluetooth::BluetoothParent();
+#else
+    MOZ_NOT_REACHED("No support for bluetooth on this platform!");
+    return nullptr;
+#endif
+}
+
+bool
+ContentParent::DeallocPBluetooth(PBluetoothParent* aActor)
+{
+#ifdef MOZ_B2G_BT
+    delete aActor;
+    return true;
+#else
+    MOZ_NOT_REACHED("No support for bluetooth on this platform!");
+    return false;
+#endif
+}
+
+bool
+ContentParent::RecvPBluetoothConstructor(PBluetoothParent* aActor)
+{
+#ifdef MOZ_B2G_BT
+    nsRefPtr<BluetoothService> btService = BluetoothService::Get();
+    NS_ENSURE_TRUE(btService, false);
+
+    return static_cast<BluetoothParent*>(aActor)->InitWithService(btService);
+#else
+    MOZ_NOT_REACHED("No support for bluetooth on this platform!");
+    return false;
+#endif
+}
+
 void
 ContentParent::ReportChildAlreadyBlocked()
 {
     if (!mRunToCompletionDepth) {
 #ifdef DEBUG
         printf("Running to completion...\n");
 #endif
         mRunToCompletionDepth = 1;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -228,16 +228,20 @@ private:
     virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
 
     virtual PSmsParent* AllocPSms();
     virtual bool DeallocPSms(PSmsParent*);
 
     virtual PStorageParent* AllocPStorage(const StorageConstructData& aData);
     virtual bool DeallocPStorage(PStorageParent* aActor);
 
+    virtual PBluetoothParent* AllocPBluetooth();
+    virtual bool DeallocPBluetooth(PBluetoothParent* aActor);
+    virtual bool RecvPBluetoothConstructor(PBluetoothParent* aActor);
+
     virtual bool RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs);
     virtual bool RecvReadFontList(InfallibleTArray<FontListEntry>* retValue);
 
     virtual bool RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions);
 
     virtual bool RecvSetClipboardText(const nsString& text, const bool& isPrivateData, const int32_t& whichClipboard);
     virtual bool RecvGetClipboardText(const int32_t& whichClipboard, nsString* text);
     virtual bool RecvEmptyClipboard();
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -96,16 +96,18 @@ LOCAL_INCLUDES += \
 	-I$(topsrcdir)/dom/indexedDB/ipc \
 	-I$(topsrcdir)/extensions/cookie \
 	-I$(topsrcdir)/dom/base \
 	-I$(topsrcdir)/toolkit/xre \
 	-I$(topsrcdir)/hal/sandbox \
 	-I$(topsrcdir)/dom/sms/src/ipc \
 	-I$(topsrcdir)/dom/devicestorage \
 	-I$(topsrcdir)/widget/xpwidgets \
+	-I$(topsrcdir)/dom/bluetooth \
+	-I$(topsrcdir)/dom/bluetooth/ipc \
 	$(NULL)
 
 DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),$(findstring $(MOZ_WIDGET_TOOLKIT),android gtk2 gonk qt))
 DEFINES += -DMOZ_ENABLE_FREETYPE
 endif
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* 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 protocol PAudio;
 include protocol PBlob;
+include protocol PBluetooth;
 include protocol PBrowser;
 include protocol PCompositor;
 include protocol PCrashReporter;
 include protocol PExternalHelperApp;
 include protocol PDeviceStorageRequest;
 include protocol PHal;
 include protocol PImageBridge;
 include protocol PIndexedDB;
@@ -158,16 +159,17 @@ struct PrefSetting {
 
 rpc protocol PContent
 {
     parent opens PCompositor;
     parent opens PImageBridge;
 
     manages PAudio;
     manages PBlob;
+    manages PBluetooth;
     manages PBrowser;
     manages PCrashReporter;
     manages PDeviceStorageRequest;
     manages PExternalHelperApp;
     manages PHal;
     manages PIndexedDB;
     manages PMemoryReportRequest;
     manages PNecko;
@@ -262,16 +264,18 @@ parent:
     PIndexedDB();
 
     PNecko();
 
     PSms();
     
     PStorage(StorageConstructData data);
 
+    PBluetooth();
+
     // Services remoting
 
     async StartVisitedQuery(URIParams uri);
     async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
     async SetURITitle(URIParams uri, nsString title);
     
     // filepicker remoting
     sync ShowFilePicker(int16_t mode, int16_t selectedType, bool addToRecentDocs,
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -114,17 +114,17 @@ SHARED_LIBRARY_LIBS += \
 	$(NULL)
 LOCAL_INCLUDES	+= \
 	-I$(topsrcdir)/dom/system/android \
 	-I$(topsrcdir)/dom/system \
 	$(NULL)
 endif
 
 ifdef MOZ_B2G_BT #{
-SHARED_LIBRARY_LIBS	+= $(DEPTH)/dom/bluetooth/$(LIB_PREFIX)dombluetooth_s.$(LIB_SUFFIX)
+SHARED_LIBRARY_LIBS += $(DEPTH)/dom/bluetooth/$(LIB_PREFIX)dombluetooth_s.$(LIB_SUFFIX)
 endif #}
 
 SHARED_LIBRARY_LIBS	+= $(DEPTH)/dom/camera/$(LIB_PREFIX)domcamera_s.$(LIB_SUFFIX)
 
 ifdef MOZ_B2G_RIL #{
 SHARED_LIBRARY_LIBS	+= \
   $(DEPTH)/dom/system/gonk/$(LIB_PREFIX)domsystemgonk_s.$(LIB_SUFFIX) \
   $(DEPTH)/dom/telephony/$(LIB_PREFIX)domtelephony_s.$(LIB_SUFFIX) \