Bug 732639: DBus Thread Implementation for B2G Bluetooth r=cjones
☠☠ backed out by 4469d30b6943 ☠ ☠
authorKyle Machulis <kyle@nonpolynomial.com>
Fri, 13 Apr 2012 22:40:09 -0700
changeset 91660 db5d4c1aece7290741f14f3f438f196be51ae710
parent 91659 d50bc535870c6765ef10e73120e8eed831f15303
child 91661 4469d30b694330c086b057ce3e28ab5ae598a4b8
push id680
push usertim.taubert@gmx.de
push dateMon, 16 Apr 2012 09:07:20 +0000
treeherderfx-team@fd06332733e5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs732639
milestone14.0a1
Bug 732639: DBus Thread Implementation for B2G Bluetooth r=cjones
dom/bluetooth/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/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -23,10 +23,22 @@ CPPSRCS = \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMNavigatorBluetooth.idl \
   nsIDOMBluetoothAdapter.idl \
   nsIDOMBluetoothDevice.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/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -44,16 +44,19 @@
 #include "nsIRadioInterfaceLayer.h"
 #include "nsIWifi.h"
 #include "nsIWorkerHolder.h"
 #include "nsIXPConnect.h"
 
 #include "jstypedarray.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ipc/Ril.h"
+#ifdef MOZ_B2G_BT
+#include "mozilla/ipc/DBusThread.h"
+#endif
 #include "nsContentUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsRadioInterfaceLayer.h"
 #include "WifiWorker.h"
 
 
 USING_WORKERS_NAMESPACE
@@ -226,16 +229,21 @@ SystemWorkerManager::Init()
   }
 
   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);
@@ -247,17 +255,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;
 
@@ -360,16 +370,29 @@ 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)
+{
+  // nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
+  // NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
+
+  // mWifiWorker = worker;
+#ifdef MOZ_B2G_BT
+  StartDBus();
+#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,531 @@
+/* -*- 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 "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, "Gonk", args);
+#else
+#define LOG(args...)  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;
+    write(dbt->mControlFdW.mFd, &control, sizeof(char));
+
+    // TODO change this to dbus_watch_get_unix_fd once we move to ics
+    int fd = dbus_watch_get_fd(aWatch);
+    write(dbt->mControlFdW.mFd, &fd, sizeof(int));
+
+    unsigned int flags = dbus_watch_get_flags(aWatch);
+    write(dbt->mControlFdW.mFd, &flags, sizeof(unsigned int));
+
+    write(dbt->mControlFdW.mFd, &aWatch, sizeof(DBusWatch*));
+  }
+  return true;
+}
+
+static void
+RemoveWatch(DBusWatch *aWatch, void *aData)
+{
+  DBusThread *dbt = (DBusThread *)aData;
+
+  char control = DBUS_EVENT_LOOP_REMOVE;
+  write(dbt->mControlFdW.mFd, &control, sizeof(char));
+
+  // TODO change this to dbus_watch_get_unix_fd once we move to ics
+  int fd = dbus_watch_get_fd(aWatch);
+  write(dbt->mControlFdW.mFd, &fd, sizeof(int));
+
+  unsigned int flags = dbus_watch_get_flags(aWatch);
+  write(dbt->mControlFdW.mFd, &flags, sizeof(unsigned int));
+}
+
+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;
+  read(aDbt->mControlFdR.mFd, &newFD, sizeof(int));
+  read(aDbt->mControlFdR.mFd, &flags, sizeof(unsigned int));
+  read(aDbt->mControlFdR.mFd, &watch, sizeof(DBusWatch *));
+  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;
+
+  read(aDbt->mControlFdR.mFd, &removeFD, sizeof(int));
+  read(aDbt->mControlFdR.mFd, &flags, sizeof(unsigned int));
+  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)
+                         , mControlFdR(-1)
+                         , mControlFdW(-1)
+{
+}
+
+DBusThread::~DBusThread()
+{
+
+}
+
+bool
+DBusThread::SetUpEventLoop()
+{
+  // If we already have a connection, exit
+  if(mConnection) {
+    return false;
+  }
+  // If we can't establish a connection to dbus, nothing else will work
+  if(!Create()) {
+    return false;
+  }
+
+  dbus_threads_init_default();
+  DBusError err;
+  dbus_error_init(&err);
+
+  // 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()
+{
+  if (mControlFdW.mFd) {
+    close(mControlFdW.mFd);
+    mControlFdW.mFd = 0;
+  }
+  if (mControlFdR.mFd) {
+    close(mControlFdR.mFd);
+    mControlFdR.mFd = 0;
+  }    
+  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;
+
+  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.mFd) {
+        char data;
+        while (recv(dbt->mControlFdR.mFd, &data, sizeof(char), MSG_DONTWAIT)
+               != -1) {
+          switch (data) {
+          case DBUS_EVENT_LOOP_EXIT:
+          {
+            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;
+  if (socketpair(AF_LOCAL, SOCK_STREAM, 0, &(mControlFdR.mFd))) {
+    TearDownData();
+    return false;
+  }
+  pollfd p;
+  p.fd = mControlFdR.mFd;
+  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() != true) {
+    TearDownData();
+    return false;
+  }
+  pthread_create(&(mThread), NULL, DBusThread::EventLoop, this);
+  return true;
+}
+
+void
+DBusThread::StopEventLoop()
+{
+  MutexAutoLock lock(mMutex);
+  if (mIsRunning) {
+    char data = DBUS_EVENT_LOOP_EXIT;
+    write(mControlFdW.mFd, &data, sizeof(char));
+    void *ret;
+    pthread_join(mThread, &ret);
+    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,30 @@
+/* -*- 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);
+  dbus_threads_init_default();
+  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) { dbus_connection_unref(ptr); }
+  };
+
+public:
+  RawDBusConnection();
+  ~RawDBusConnection();
+  bool Create();
+protected:
+  Scoped<ScopedDBusConnectionPtrTraits> mConnection;
+};
+
+}
+}
+
+#endif
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -110,16 +110,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 += \
   -lmedia \
   -lhardware_legacy \
   -lhardware \
   -lutils \
   -lcutils \
   -lcamera_client \
   -lbinder \
   -lsensorservice \
+  -ldbus \
   $(NULL)
 endif
 
 EXTRA_DEPS += \
   $(topsrcdir)/intl/unicharutil/util/objs.mk \
   $(topsrcdir)/rdf/util/src/objs.mk \
   $(NULL)