--- 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)