Bug 732639: Create event loop thread for bluetooth dbus on gonk/linux; r=cjones
☠☠ backed out by 2a0b7a536677 ☠ ☠
authorKyle Machulis <kyle@nonpolynomial.com>
Mon, 07 May 2012 14:04:59 -0700
changeset 94790 7a8607523522bfe8576614273bd8967469d60db1
parent 94789 9399d5faf9eee3a4289a035888a2a108342b2c3d
child 94791 6d4fbeb32fbf22a54c0c5cb18a1cca3588163de4
push idunknown
push userunknown
push dateunknown
reviewerscjones
bugs732639
milestone15.0a1
Bug 732639: Create event loop thread for bluetooth dbus on gonk/linux; r=cjones
configure.in
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothFirmware.cpp
dom/bluetooth/BluetoothFirmware.h
dom/bluetooth/Makefile.in
dom/system/gonk/Makefile.in
dom/system/gonk/SystemWorkerManager.cpp
dom/system/gonk/SystemWorkerManager.h
ipc/Makefile.in
ipc/dbus/DBusThread.cpp
ipc/dbus/DBusThread.h
ipc/dbus/DBusUtils.cpp
ipc/dbus/DBusUtils.h
ipc/dbus/Makefile.in
ipc/dbus/RawDBusConnection.cpp
ipc/dbus/RawDBusConnection.h
toolkit/library/Makefile.in
--- a/configure.in
+++ b/configure.in
@@ -286,17 +286,17 @@ if test -n "$gonkdir" ; then
     LD="$gonk_toolchain_prefix"ld
     AR="$gonk_toolchain_prefix"ar
     RANLIB="$gonk_toolchain_prefix"ranlib
     STRIP="$gonk_toolchain_prefix"strip
 
     STLPORT_CPPFLAGS="-I$gonkdir/ndk/sources/cxx-stl/stlport/stlport/"
     STLPORT_LIBS="-lstlport"
 
-    CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/arch-arm/include -isystem $gonkdir/bionic/libc/kernel/arch-arm -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice"
+    CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/arch-arm/include -isystem $gonkdir/bionic/libc/kernel/arch-arm -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice"
     CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
     CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions $CXXFLAGS $STLPORT_CPPFLAGS"
     LIBS="$LIBS $STLPORT_LIBS"
 
     dnl Add -llog by default, since we use it all over the place.
     LDFLAGS="-mandroid -L$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib -Wl,-rpath-link=$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib --sysroot=$gonkdir/out/target/product/$GONK_PRODUCT/obj/ -llog $LDFLAGS"
 
     dnl prevent cross compile section from using these flags as host flags
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -1,23 +1,23 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=40: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothAdapter.h"
+#include "BluetoothFirmware.h"
 
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
-#include <dlfcn.h>
 
 static void
 FireEnabled(bool aResult, nsIDOMDOMRequest* aDomRequest)
 {
   nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
 
   if (!rs) {
     NS_WARNING("No DOMRequest Service!");
@@ -29,66 +29,16 @@ FireEnabled(bool aResult, nsIDOMDOMReque
                                     rs->FireError(aDomRequest, 
                                                   NS_LITERAL_STRING("Bluetooth firmware loading failed"));
 
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Bluetooth firmware loading failed");
 }
 
 USING_BLUETOOTH_NAMESPACE
 
-static struct BluedroidFunctions {
-  bool initialized;
-  bool tried_initialization;
-
-  BluedroidFunctions() :
-    initialized(false),
-    tried_initialization(false)
-  {
-  }
-  
-  int (* bt_enable)();
-  int (* bt_disable)();
-  int (* bt_is_enabled)();
-} sBluedroidFunctions;
-
-static bool EnsureBluetoothInit() {
-  if (sBluedroidFunctions.tried_initialization)
-  {
-    return sBluedroidFunctions.initialized;
-  }
-
-  sBluedroidFunctions.initialized = false;
-  sBluedroidFunctions.tried_initialization = true;
-  
-  void* handle = dlopen("libbluedroid.so", RTLD_LAZY);
-
-  if(!handle) {
-    NS_ERROR("Failed to open libbluedroid.so, bluetooth cannot run");
-    return false;
-  }
-
-  sBluedroidFunctions.bt_enable = (int (*)())dlsym(handle, "bt_enable");
-  if(sBluedroidFunctions.bt_enable == NULL) {
-    NS_ERROR("Failed to attach bt_enable function");
-    return false;
-  }
-  sBluedroidFunctions.bt_disable = (int (*)())dlsym(handle, "bt_disable");
-  if(sBluedroidFunctions.bt_disable == NULL) {
-    NS_ERROR("Failed to attach bt_disable function");
-    return false;
-  }
-  sBluedroidFunctions.bt_is_enabled = (int (*)())dlsym(handle, "bt_is_enabled");
-  if(sBluedroidFunctions.bt_is_enabled == NULL) {
-    NS_ERROR("Failed to attach bt_is_enabled function");
-    return false;
-  }
-  sBluedroidFunctions.initialized = true;
-  return true;
-}
-
 class ToggleBtResultTask : public nsRunnable
 {
   public:
     ToggleBtResultTask(nsRefPtr<BluetoothAdapter>& adapterPtr, 
                        nsCOMPtr<nsIDOMDOMRequest>& req,
                        bool enabled,
                        bool result)
       : mResult(result),
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothFirmware.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothFirmware.h"
+
+#include "nsDebug.h"
+#include "nsError.h"
+#include <dlfcn.h>
+
+namespace mozilla {
+namespace dom {
+namespace bluetooth {
+
+bool EnsureBluetoothInit() {
+  if (sBluedroidFunctions.tried_initialization)
+  {
+    return sBluedroidFunctions.initialized;
+  }
+
+  sBluedroidFunctions.initialized = false;
+  sBluedroidFunctions.tried_initialization = true;
+  
+  void* handle = dlopen("libbluedroid.so", RTLD_LAZY);
+
+  if(!handle) {
+    NS_ERROR("Failed to open libbluedroid.so, bluetooth cannot run");
+    return false;
+  }
+
+  sBluedroidFunctions.bt_enable = (int (*)())dlsym(handle, "bt_enable");
+  if(sBluedroidFunctions.bt_enable == NULL) {
+    NS_ERROR("Failed to attach bt_enable function");
+    return false;
+  }
+  sBluedroidFunctions.bt_disable = (int (*)())dlsym(handle, "bt_disable");
+  if(sBluedroidFunctions.bt_disable == NULL) {
+    NS_ERROR("Failed to attach bt_disable function");
+    return false;
+  }
+  sBluedroidFunctions.bt_is_enabled = (int (*)())dlsym(handle, "bt_is_enabled");
+  if(sBluedroidFunctions.bt_is_enabled == NULL) {
+    NS_ERROR("Failed to attach bt_is_enabled function");
+    return false;
+  }
+  sBluedroidFunctions.initialized = true;
+  return true;
+}
+
+}
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothFirmware.h
@@ -0,0 +1,34 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluetoothfirmware_h__
+#define mozilla_dom_bluetooth_bluetoothfirmware_h__
+
+namespace mozilla {
+namespace dom {
+namespace bluetooth {
+
+static struct BluedroidFunctions {
+  bool initialized;
+  bool tried_initialization;
+
+  BluedroidFunctions() :
+    initialized(false),
+    tried_initialization(false)
+  {
+  }
+  
+  int (* bt_enable)();
+  int (* bt_disable)();
+  int (* bt_is_enabled)();
+} sBluedroidFunctions;
+
+bool EnsureBluetoothInit();
+}
+}
+}
+
+#endif
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -14,17 +14,30 @@ LIBRARY_NAME     = dombluetooth_s
 XPIDL_MODULE     = dom_bluetooth
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
 CPPSRCS = \
   BluetoothAdapter.cpp \
+  BluetoothFirmware.cpp \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMNavigatorBluetooth.idl \
   nsIDOMBluetoothAdapter.idl \
   $(NULL)
 
+ifneq (gonk,$(MOZ_WIDGET_TOOLKIT))
+CFLAGS += $(MOZ_DBUS_CFLAGS)
+CXXFLAGS += $(MOZ_DBUS_CFLAGS) -DHAVE_PTHREADS
+endif
+
 include $(topsrcdir)/config/rules.mk
 
+ifeq (Linux,$(OS_TARGET))
+ifdef MOZ_ENABLE_DBUS
+CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
+CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
+endif
+endif
+
--- a/dom/system/gonk/Makefile.in
+++ b/dom/system/gonk/Makefile.in
@@ -30,16 +30,17 @@ XPIDLSRCS = \
   nsIWorkerHolder.idl \
   $(NULL)
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/dom/base \
   -I$(topsrcdir)/dom/src/geolocation \
   -I$(topsrcdir)/dom/telephony \
   -I$(topsrcdir)/dom/wifi \
+  -I$(topsrcdir)/dom/bluetooth \
   -I$(topsrcdir)/content/events/src \
   $(NULL)
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += \
   AudioManager.cpp \
   GonkGPSGeolocationProvider.cpp \
   $(NULL)
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -44,25 +44,39 @@
 #include "nsIRadioInterfaceLayer.h"
 #include "nsIWifi.h"
 #include "nsIWorkerHolder.h"
 #include "nsIXPConnect.h"
 
 #include "jsfriendapi.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ipc/Ril.h"
+#ifdef MOZ_B2G_BT
+#include "mozilla/ipc/DBusThread.h"
+#include "BluetoothFirmware.h"
+#endif
 #include "nsContentUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsRadioInterfaceLayer.h"
 #include "WifiWorker.h"
 
+#undef LOG
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkBluetooth", args);
+#else
+#define BTDEBUG true
+#define LOG(args...) if(BTDEBUG) printf(args);
+#endif
+
 
 USING_WORKERS_NAMESPACE
 using namespace mozilla::dom::gonk;
+using namespace mozilla::dom::bluetooth;
 using namespace mozilla::ipc;
 
 namespace {
 
 NS_DEFINE_CID(kRadioInterfaceLayerCID, NS_RADIOINTERFACELAYER_CID);
 NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID);
 
 // Doesn't carry a reference, we're owned by services.
@@ -224,16 +238,21 @@ SystemWorkerManager::Init()
   }
 
   nsresult rv = InitRIL(cx);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = InitWifi(cx);
   NS_ENSURE_SUCCESS(rv, rv);
 
+#ifdef MOZ_B2G_BT
+  rv = InitBluetooth(cx);
+  NS_ENSURE_SUCCESS(rv, rv);
+#endif
+
   nsCOMPtr<nsIObserverService> obs =
     do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   if (!obs) {
     NS_WARNING("Failed to get observer service!");
     return NS_ERROR_FAILURE;
   }
 
   rv = obs->AddObserver(this, WORKERS_SHUTDOWN_TOPIC, false);
@@ -245,17 +264,19 @@ SystemWorkerManager::Init()
 void
 SystemWorkerManager::Shutdown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   mShutdown = true;
 
   StopRil();
-
+#ifdef MOZ_B2G_BT
+  StopDBus();
+#endif
   mRILWorker = nsnull;
   nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
   if (wifi) {
     wifi->Shutdown();
     wifi = nsnull;
   }
   mWifiWorker = nsnull;
 
@@ -358,16 +379,40 @@ SystemWorkerManager::InitWifi(JSContext 
 {
   nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
   NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
 
   mWifiWorker = worker;
   return NS_OK;
 }
 
+nsresult
+SystemWorkerManager::InitBluetooth(JSContext *cx)
+{
+#ifdef MOZ_B2G_BT
+#ifdef MOZ_WIDGET_GONK
+  // We need a platform specific check here to make sure of when we're
+  // running on an emulator. Therefore, if we're compiled with gonk,
+  // see if we can load functions out of bluedroid. If not, assume
+  // it's an emulator and don't start the bluetooth thread.
+  if(EnsureBluetoothInit()) {
+#endif
+#endif
+    StartDBus();
+#ifdef MOZ_B2G_BT
+#ifdef MOZ_WIDGET_GONK
+  }
+  else {
+    LOG("Bluedroid functions not available, assuming running on simulator. Not starting DBus thread.");
+  }
+#endif
+#endif
+  return NS_OK;
+}
+
 NS_IMPL_ISUPPORTS2(SystemWorkerManager, nsIObserver, nsIInterfaceRequestor)
 
 NS_IMETHODIMP
 SystemWorkerManager::Observe(nsISupports *aSubject, const char *aTopic,
                              const PRUnichar *aData)
 {
   if (!strcmp(aTopic, WORKERS_SHUTDOWN_TOPIC)) {
     Shutdown();
--- a/dom/system/gonk/SystemWorkerManager.h
+++ b/dom/system/gonk/SystemWorkerManager.h
@@ -73,17 +73,18 @@ public:
   GetInterfaceRequestor();
 
 private:
   SystemWorkerManager();
   ~SystemWorkerManager();
 
   nsresult InitRIL(JSContext *cx);
   nsresult InitWifi(JSContext *cx);
-
+  nsresult InitBluetooth(JSContext *cx);
+  
   nsCOMPtr<nsIWorkerHolder> mRILWorker;
   nsCOMPtr<nsIWorkerHolder> mWifiWorker;
 
   bool mShutdown;
 };
 
 }
 }
--- a/ipc/Makefile.in
+++ b/ipc/Makefile.in
@@ -42,11 +42,15 @@ VPATH = @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 DIRS += chromium glue ipdl testshell
 
 ifdef MOZ_B2G_RIL #{
 DIRS += ril
 endif #}
 
+ifdef MOZ_B2G_BT #{
+DIRS += dbus
+endif #}
+
 TOOL_DIRS = app
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/ipc/dbus/DBusThread.cpp
@@ -0,0 +1,587 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * NOTE: Due to being based on the dbus compatibility layer for
+ * android's bluetooth implementation, this file is licensed under the
+ * apache license instead of MPL.
+ *
+ */
+
+#include "DBusThread.h"
+#include "RawDBusConnection.h"
+#include "DBusUtils.h"
+
+#include <dbus/dbus.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <poll.h>
+
+#include <list>
+
+#include "base/eintr_wrapper.h"
+#include "base/message_loop.h"
+#include "nsTArray.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/Util.h"
+#include "mozilla/FileUtils.h"
+#include "nsAutoPtr.h"
+#include "nsIThread.h"
+#include "nsXULAppAPI.h"
+
+#undef LOG
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkBluetooth", args);
+#else
+#define BTDEBUG true
+#define LOG(args...) if(BTDEBUG) printf(args);
+#endif
+
+#define DEFAULT_INITIAL_POLLFD_COUNT 8
+
+// Functions for converting between unix events in the poll struct,
+// and their dbus definitions
+
+// TODO Add Wakeup to this list once we've moved to ics
+
+enum {
+  DBUS_EVENT_LOOP_EXIT = 1,
+  DBUS_EVENT_LOOP_ADD = 2,
+  DBUS_EVENT_LOOP_REMOVE = 3,
+} DBusEventTypes;
+
+// Signals that the DBus thread should listen for. Needs to include
+// all signals any DBus observer object may need.
+
+static const char* DBUS_SIGNALS[] =
+{
+  "type='signal',interface='org.freedesktop.DBus'",
+  "type='signal',interface='org.bluez.Adapter'",
+  "type='signal',interface='org.bluez.Device'",
+  "type='signal',interface='org.bluez.Input'",
+  "type='signal',interface='org.bluez.Network'",
+  "type='signal',interface='org.bluez.NetworkServer'",
+  "type='signal',interface='org.bluez.HealthDevice'",
+  "type='signal',interface='org.bluez.AudioSink'"
+};
+
+static unsigned int UnixEventsToDBusFlags(short events)
+{
+  return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
+    (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
+    (events & DBUS_WATCH_ERROR ? POLLERR : 0) |
+    (events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
+}
+
+static short DBusFlagsToUnixEvents(unsigned int flags)
+{
+  return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
+    (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
+    (flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
+    (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
+}
+
+namespace mozilla {
+namespace ipc {
+
+struct PollFdComparator {
+  bool Equals(const pollfd& a, const pollfd& b) const {
+    return ((a.fd == b.fd) &&
+            (a.events == b.events));
+  }
+  bool LessThan(const pollfd& a, const pollfd&b) const {
+    return false;
+  }
+};
+
+// DBus Thread Class prototype
+
+struct DBusThread : public RawDBusConnection
+{
+  DBusThread();
+  ~DBusThread();
+
+  bool StartEventLoop();
+  void StopEventLoop();
+  bool IsEventLoopRunning();
+  static void* EventLoop(void* aPtr);
+
+  // Thread members
+  pthread_t mThread;
+  Mutex mMutex;
+  bool mIsRunning;
+
+  // Information about the sockets we're polling. Socket counts
+  // increase/decrease depending on how many add/remove watch signals
+  // we're received via the control sockets.
+  nsTArray<pollfd> mPollData;
+  nsTArray<DBusWatch*> mWatchData;
+
+  // Sockets for receiving dbus control information (watch
+  // add/removes, loop shutdown, etc...)
+  ScopedClose mControlFdR;
+  ScopedClose mControlFdW;
+
+protected:
+  bool SetUpEventLoop();
+  bool TearDownData();
+  bool TearDownEventLoop();
+};
+
+static nsAutoPtr<DBusThread> sDBusThread;
+
+// DBus utility functions
+// Free statics, as they're used as function pointers in dbus setup
+
+static dbus_bool_t
+AddWatch(DBusWatch *aWatch, void *aData)
+{
+  DBusThread *dbt = (DBusThread *)aData;
+
+  if (dbus_watch_get_enabled(aWatch)) {
+    // note that we can't just send the watch and inspect it later
+    // because we may get a removeWatch call before this data is reacted
+    // to by our eventloop and remove this watch..  reading the add first
+    // and then inspecting the recently deceased watch would be bad.
+    char control = DBUS_EVENT_LOOP_ADD;
+    if(write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
+      LOG("Cannot write DBus add watch control data to socket!\n");
+      return false;
+    }
+
+    // TODO change this to dbus_watch_get_unix_fd once we move to ics
+    int fd = dbus_watch_get_fd(aWatch);
+    if(write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
+      LOG("Cannot write DBus add watch descriptor data to socket!\n");
+      return false;
+    }
+
+    unsigned int flags = dbus_watch_get_flags(aWatch);
+    if(write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
+      LOG("Cannot write DBus add watch flag data to socket!\n");
+      return false;
+    }
+
+    if(write(dbt->mControlFdW.get(), &aWatch, sizeof(DBusWatch*)) < 0) {
+      LOG("Cannot write DBus add watch struct data to socket!\n");
+      return false;
+    }
+  }
+  return true;
+}
+
+static void
+RemoveWatch(DBusWatch *aWatch, void *aData)
+{
+  DBusThread *dbt = (DBusThread *)aData;
+
+  char control = DBUS_EVENT_LOOP_REMOVE;
+  if(write(dbt->mControlFdW.get(), &control, sizeof(char)) < 0) {
+    LOG("Cannot write DBus remove watch control data to socket!\n");
+    return;
+  }
+
+  // TODO change this to dbus_watch_get_unix_fd once we move to ics
+  int fd = dbus_watch_get_fd(aWatch);
+  if(write(dbt->mControlFdW.get(), &fd, sizeof(int)) < 0) {
+    LOG("Cannot write DBus remove watch descriptor data to socket!\n");
+    return;
+  }
+
+  unsigned int flags = dbus_watch_get_flags(aWatch);
+  if(write(dbt->mControlFdW.get(), &flags, sizeof(unsigned int)) < 0) {
+    LOG("Cannot write DBus remove watch flag data to socket!\n");
+    return;
+  }
+}
+
+static void
+ToggleWatch(DBusWatch *aWatch, void *aData)
+{
+  if (dbus_watch_get_enabled(aWatch)) {
+    AddWatch(aWatch, aData);
+  } else {
+    RemoveWatch(aWatch, aData);
+  }
+}
+
+static void
+HandleWatchAdd(DBusThread* aDbt)
+{
+  DBusWatch *watch;
+  int newFD;
+  unsigned int flags;
+  if(read(aDbt->mControlFdR.get(), &newFD, sizeof(int)) < 0) {
+    LOG("Cannot read DBus watch add descriptor data from socket!\n");
+    return;
+  }
+  if(read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
+    LOG("Cannot read DBus watch add flag data from socket!\n");
+    return;
+  }
+  if(read(aDbt->mControlFdR.get(), &watch, sizeof(DBusWatch *)) < 0) {
+    LOG("Cannot read DBus watch add watch data from socket!\n");
+    return;
+  }
+  short events = DBusFlagsToUnixEvents(flags);
+
+  pollfd p;
+  p.fd = newFD;
+  p.revents = 0;
+  p.events = events;
+  if(aDbt->mPollData.Contains(p, PollFdComparator())) return;
+  aDbt->mPollData.AppendElement(p);
+  aDbt->mWatchData.AppendElement(watch);
+}
+
+static void HandleWatchRemove(DBusThread* aDbt) {
+  int removeFD;
+  unsigned int flags;
+
+  if(read(aDbt->mControlFdR.get(), &removeFD, sizeof(int)) < 0) {
+    LOG("Cannot read DBus watch remove descriptor data from socket!\n");
+    return;
+  }
+  if(read(aDbt->mControlFdR.get(), &flags, sizeof(unsigned int)) < 0) {
+    LOG("Cannot read DBus watch remove flag data from socket!\n");
+    return;
+  }
+  short events = DBusFlagsToUnixEvents(flags);
+  pollfd p;
+  p.fd = removeFD;
+  p.events = events;
+  int index = aDbt->mPollData.IndexOf(p, 0, PollFdComparator());
+  aDbt->mPollData.RemoveElementAt(index);
+
+  // DBusWatch pointers are maintained by DBus, so we won't leak by
+  // removing.
+  aDbt->mWatchData.RemoveElementAt(index);
+}
+
+// Called by dbus during WaitForAndDispatchEventNative()
+static DBusHandlerResult
+EventFilter(DBusConnection *aConn, DBusMessage *aMsg,
+            void *aData)
+{
+  DBusError err;
+
+  dbus_error_init(&err);
+
+  if (dbus_message_get_type(aMsg) != DBUS_MESSAGE_TYPE_SIGNAL) {
+    LOG("%s: not interested (not a signal).\n", __FUNCTION__);
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  LOG("%s: Received signal %s:%s from %s\n", __FUNCTION__,
+      dbus_message_get_interface(aMsg), dbus_message_get_member(aMsg),
+      dbus_message_get_path(aMsg));
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+// DBus Thread Implementation
+
+DBusThread::DBusThread() : mMutex("DBusGonk.mMutex")
+                         , mIsRunning(false)
+{
+}
+
+DBusThread::~DBusThread()
+{
+
+}
+
+bool
+DBusThread::SetUpEventLoop()
+{
+  // If we already have a connection, exit
+  if(mConnection) {
+    return false;
+  }
+
+  dbus_threads_init_default();
+  DBusError err;
+  dbus_error_init(&err);
+
+  // If we can't establish a connection to dbus, nothing else will work
+  if(!Create()) {
+    return false;
+  }
+
+  // Add a filter for all incoming messages_base
+  if (!dbus_connection_add_filter(mConnection, EventFilter, this, NULL)){
+    return false;
+  }
+
+  // Set which messages will be processed by this dbus connection.
+  // Since we are maintaining a single thread for all the DBus bluez
+  // signals we want, register all of them in this thread at startup.
+  // The event handler will sort the destinations out as needed.
+  for(uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
+    dbus_bus_add_match(mConnection,
+                       DBUS_SIGNALS[i],
+                       &err);
+    if (dbus_error_is_set(&err)) {
+      LOG_AND_FREE_DBUS_ERROR(&err);
+      return false;
+    }
+  }
+  return true;
+}
+
+bool
+DBusThread::TearDownData()
+{
+  LOG("Removing DBus Bluetooth Sockets\n");
+  if (mControlFdW.get()) {
+    mControlFdW.dispose();
+  }
+  if (mControlFdR.get()) {
+    mControlFdR.dispose();
+  }
+  mPollData.Clear();
+
+  // DBusWatch pointers are maintained by DBus, so we won't leak by
+  // clearing.
+  mWatchData.Clear();
+  return true;
+}
+
+bool
+DBusThread::TearDownEventLoop()
+{
+  MOZ_ASSERT(mConnection);
+
+  DBusError err;
+  dbus_error_init(&err);
+
+  for(uint32_t i = 0; i < ArrayLength(DBUS_SIGNALS); ++i) {
+    dbus_bus_remove_match(mConnection,
+                          DBUS_SIGNALS[i],
+                          &err);
+    if (dbus_error_is_set(&err)) {
+      LOG_AND_FREE_DBUS_ERROR(&err);
+    }
+  }
+
+  dbus_connection_remove_filter(mConnection, EventFilter, this);
+  return true;
+}
+
+void*
+DBusThread::EventLoop(void *aPtr)
+{
+  DBusThread* dbt = static_cast<DBusThread*>(aPtr);
+  MOZ_ASSERT(dbt);
+
+  dbus_connection_set_watch_functions(dbt->mConnection, AddWatch,
+                                      RemoveWatch, ToggleWatch, aPtr, NULL);
+
+  dbt->mIsRunning = true;
+  LOG("DBus Bluetooth Event Loop Starting\n");
+  while (1) {
+    poll(dbt->mPollData.Elements(), dbt->mPollData.Length(), -1);
+
+    for (uint32_t i = 0; i < dbt->mPollData.Length(); i++) {
+      if (!dbt->mPollData[i].revents) {
+        continue;
+      }
+
+      if (dbt->mPollData[i].fd == dbt->mControlFdR.get()) {
+        char data;
+        while (recv(dbt->mControlFdR.get(), &data, sizeof(char), MSG_DONTWAIT)
+               != -1) {
+          switch (data) {
+          case DBUS_EVENT_LOOP_EXIT:
+          {
+            LOG("DBus Bluetooth Event Loop Exiting\n");
+            dbus_connection_set_watch_functions(dbt->mConnection,
+                                                NULL, NULL, NULL, NULL, NULL);
+            dbt->TearDownEventLoop();
+            return NULL;
+          }
+          case DBUS_EVENT_LOOP_ADD:
+          {
+            HandleWatchAdd(dbt);
+            break;
+          }
+          case DBUS_EVENT_LOOP_REMOVE:
+          {
+            HandleWatchRemove(dbt);
+            break;
+          }
+          }
+        }
+      } else {
+        short events = dbt->mPollData[i].revents;
+        unsigned int flags = UnixEventsToDBusFlags(events);
+        dbus_watch_handle(dbt->mWatchData[i], flags);
+        dbt->mPollData[i].revents = 0;
+        // Break at this point since we don't know if the operation
+        // was destructive
+        break;
+      }
+    }
+    while (dbus_connection_dispatch(dbt->mConnection) ==
+           DBUS_DISPATCH_DATA_REMAINS)
+    {}
+  }
+}
+
+bool
+DBusThread::StartEventLoop()
+{
+  MutexAutoLock lock(mMutex);
+  mIsRunning = false;
+
+  // socketpair opens two sockets for the process to communicate on.
+  // This is how android's implementation of the dbus event loop
+  // communicates with itself in relation to IPC signals. These
+  // sockets are contained sequentially in the same struct in the
+  // android code, but we break them out into class members here.
+  // Therefore we read into a local array and then copy.
+
+  int sockets[2];
+  if (socketpair(AF_LOCAL, SOCK_STREAM, 0, (int*)(&sockets)) < 0) {
+    TearDownData();
+    return false;
+  }
+  mControlFdR.rwget() = sockets[0];
+  mControlFdW.rwget() = sockets[1];
+  pollfd p;
+  p.fd = mControlFdR.get();
+  p.events = POLLIN;
+  mPollData.AppendElement(p);
+
+  // Due to the fact that mPollData and mWatchData have to match, we
+  // push a null to the front of mWatchData since it has the control
+  // fd in the first slot of mPollData.
+
+  mWatchData.AppendElement((DBusWatch*)NULL);
+  if (!SetUpEventLoop()) {
+    TearDownData();
+    return false;
+  }
+  LOG("DBus Bluetooth Thread Starting\n");
+  pthread_create(&(mThread), NULL, DBusThread::EventLoop, this);
+  return true;
+}
+
+void
+DBusThread::StopEventLoop()
+{
+  MutexAutoLock lock(mMutex);
+  if (mIsRunning) {
+    char data = DBUS_EVENT_LOOP_EXIT;
+    ssize_t wret = write(mControlFdW.get(), &data, sizeof(char));
+    if(wret < 0) {
+      LOG("Cannot write exit bit to DBus Bluetooth Thread!\n");
+    }
+    void *ret;
+    LOG("DBus Bluetooth Thread Joining\n");
+    pthread_join(mThread, &ret);
+    LOG("DBus Bluetooth Thread Joined\n");
+    TearDownData();
+  }
+  mIsRunning = false;
+}
+
+bool
+DBusThread::IsEventLoopRunning()
+{
+  MutexAutoLock lock(mMutex);
+  return mIsRunning;
+}
+
+// Startup/Shutdown utility functions
+
+static void
+ConnectDBus(Monitor* aMonitor, bool* aSuccess)
+{
+  MOZ_ASSERT(!sDBusThread);
+
+  sDBusThread = new DBusThread();
+  *aSuccess = true;
+  if(!sDBusThread->StartEventLoop())
+  {
+    *aSuccess = false;
+  }
+  {
+    MonitorAutoLock lock(*aMonitor);
+    lock.Notify();
+  }
+}
+
+static void
+DisconnectDBus(Monitor* aMonitor, bool* aSuccess)
+{
+  MOZ_ASSERT(sDBusThread);
+
+  *aSuccess = true;
+  sDBusThread->StopEventLoop();
+  sDBusThread = NULL;
+  {
+    MonitorAutoLock lock(*aMonitor);
+    lock.Notify();
+  }
+}
+
+bool
+StartDBus()
+{
+  Monitor monitor("StartDBus.monitor");
+  bool success;
+  {
+    MonitorAutoLock lock(monitor);
+
+    XRE_GetIOMessageLoop()->PostTask(
+      FROM_HERE,
+      NewRunnableFunction(ConnectDBus, &monitor, &success));
+    lock.Wait();
+  }
+  return success;
+}
+
+bool
+StopDBus()
+{
+  Monitor monitor("StopDBus.monitor");
+  bool success;
+  {
+    MonitorAutoLock lock(monitor);
+
+    XRE_GetIOMessageLoop()->PostTask(
+      FROM_HERE,
+      NewRunnableFunction(DisconnectDBus, &monitor, &success));
+    lock.Wait();
+  }
+  return success;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/dbus/DBusThread.h
@@ -0,0 +1,25 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ipc_dbus_gonk_dbusthread_h__
+#define mozilla_ipc_dbus_gonk_dbusthread_h__
+
+namespace mozilla {
+namespace ipc {
+
+
+// Starts the DBus thread, which handles returning signals to objects
+// that call asynchronous functions. This should be called from the
+// main thread at startup.
+bool StartDBus();
+
+// Stop the DBus thread, assuming it's currently running. Should be
+// called from main thread.
+bool StopDBus();
+}
+}
+#endif
+
new file mode 100644
--- /dev/null
+++ b/ipc/dbus/DBusUtils.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdio.h>
+#include "dbus/dbus.h"
+
+#undef LOG
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args);
+#else
+#define LOG(args...)  printf(args);
+#endif
+
+namespace mozilla {
+namespace ipc {
+
+void
+log_and_free_dbus_error(DBusError* err, const char* function, DBusMessage* msg)
+{
+  if(msg) {
+    LOG("%s: D-Bus error in %s: %s (%s)", function,
+        dbus_message_get_member((msg)), (err)->name, (err)->message);
+  }	else {
+    LOG("%s: D-Bus error: %s (%s)", __FUNCTION__,
+        (err)->name, (err)->message);
+  }
+  dbus_error_free((err));
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/dbus/DBusUtils.h
@@ -0,0 +1,37 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef mozilla_ipc_dbus_dbusutils_h__
+#define mozilla_ipc_dbus_dbusutils_h__
+
+// LOGE and free a D-Bus error
+// Using #define so that __FUNCTION__ resolves usefully
+#define LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg) log_and_free_dbus_error(err, __FUNCTION__, msg);
+#define LOG_AND_FREE_DBUS_ERROR(err) log_and_free_dbus_error(err, __FUNCTION__);
+
+struct DBusMessage;
+struct DBusError;
+
+namespace mozilla {
+namespace ipc {
+void log_and_free_dbus_error(DBusError* err, const char* function, DBusMessage* msg = NULL);
+}
+}
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/ipc/dbus/Makefile.in
@@ -0,0 +1,44 @@
+# 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/.
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipc
+LIBRARY_NAME = mozdbus_s
+FORCE_STATIC_LIB = 1
+LIBXUL_LIBRARY = 1
+EXPORT_LIBRARY = 1
+
+ifdef MOZ_ENABLE_DBUS
+	LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
+endif
+
+EXPORTS_NAMESPACES = mozilla/ipc
+
+EXPORTS_mozilla/ipc = \
+  RawDBusConnection.h \
+  DBusThread.h \
+  DBusUtils.h \
+  $(NULL)
+
+CPPSRCS += \
+  RawDBusConnection.cpp \
+  DBusThread.cpp \
+  DBusUtils.cpp \
+  $(NULL)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+
+include $(topsrcdir)/config/rules.mk
+
+ifdef MOZ_ENABLE_DBUS
+	CFLAGS          += $(MOZ_DBUS_GLIB_CFLAGS)
+	CXXFLAGS        += $(MOZ_DBUS_GLIB_CFLAGS)
+endif
new file mode 100644
--- /dev/null
+++ b/ipc/dbus/RawDBusConnection.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RawDBusConnection.h"
+#include <dbus/dbus.h>
+
+using namespace mozilla::ipc;
+
+RawDBusConnection::RawDBusConnection() {
+}
+
+RawDBusConnection::~RawDBusConnection() {
+}
+
+bool RawDBusConnection::Create() {
+  DBusError err;
+  dbus_error_init(&err);
+  mConnection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+  if (dbus_error_is_set(&err)) {
+    dbus_error_free(&err);
+    return false;
+  }
+  dbus_connection_set_exit_on_disconnect(mConnection, FALSE);
+  return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/ipc/dbus/RawDBusConnection.h
@@ -0,0 +1,41 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ipc_dbus_gonk_rawdbusconnection_h__
+#define mozilla_ipc_dbus_gonk_rawdbusconnection_h__
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string>
+#include <stdlib.h>
+#include "mozilla/Scoped.h"
+#include "dbus/dbus.h"
+
+struct DBusConnection;
+
+namespace mozilla {
+namespace ipc {
+
+class RawDBusConnection
+{
+  struct ScopedDBusConnectionPtrTraits : ScopedFreePtrTraits<DBusConnection>
+  {
+    static void release(DBusConnection* ptr) { if(ptr) dbus_connection_unref(ptr); }
+  };
+
+public:
+  RawDBusConnection();
+  ~RawDBusConnection();
+  bool Create();
+protected:
+  Scoped<ScopedDBusConnectionPtrTraits> mConnection;
+};
+
+}
+}
+
+#endif
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -108,16 +108,20 @@ STATIC_LIBS += \
   hal_s \
   dombindings_s \
   $(NULL)
 
 ifdef MOZ_B2G_RIL #{
 STATIC_LIBS += mozril_s
 endif #}
 
+ifdef MOZ_B2G_BT #{
+STATIC_LIBS += mozdbus_s
+endif #}
+
 ifdef MOZ_IPDL_TESTS
 STATIC_LIBS += ipdlunittest_s
 endif
 
 ifeq (Linux,$(OS_ARCH))
 ifneq (Android,$(OS_TARGET))
 OS_LIBS += -lrt
 endif
@@ -393,16 +397,17 @@ OS_LIBS += \
   -lhardware_legacy \
   -lhardware \
   -lutils \
   -lcutils \
   -lsysutils \
   -lcamera_client \
   -lbinder \
   -lsensorservice \
+  -ldbus \
   $(NULL)
 endif
 
 EXTRA_DEPS += \
   $(topsrcdir)/intl/unicharutil/util/objs.mk \
   $(topsrcdir)/rdf/util/src/objs.mk \
   $(NULL)