Re-land the patch for bug 732639 after a b2g clobber.

This commit is contained in:
Ryan VanderMeulen 2012-05-07 17:50:25 -04:00
parent 20842f8db4
commit 3dff13f360
17 changed files with 971 additions and 54 deletions

View File

@ -291,7 +291,7 @@ if test -n "$gonkdir" ; then
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"

View File

@ -5,6 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BluetoothAdapter.h"
#include "BluetoothFirmware.h"
#include "nsDOMClassInfo.h"
#include "nsDOMEvent.h"
@ -12,7 +13,6 @@
#include "nsXPCOMCIDInternal.h"
#include "mozilla/LazyIdleThread.h"
#include "mozilla/Util.h"
#include <dlfcn.h>
static void
FireEnabled(bool aResult, nsIDOMDOMRequest* aDomRequest)
@ -34,56 +34,6 @@ FireEnabled(bool aResult, nsIDOMDOMRequest* aDomRequest)
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:

View File

@ -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;
}
}
}
}

View File

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

View File

@ -19,6 +19,7 @@ include $(topsrcdir)/dom/dom-config.mk
CPPSRCS = \
BluetoothAdapter.cpp \
BluetoothFirmware.cpp \
$(NULL)
XPIDLSRCS = \
@ -26,5 +27,17 @@ XPIDLSRCS = \
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

View File

@ -35,6 +35,7 @@ LOCAL_INCLUDES = \
-I$(topsrcdir)/dom/src/geolocation \
-I$(topsrcdir)/dom/telephony \
-I$(topsrcdir)/dom/wifi \
-I$(topsrcdir)/dom/bluetooth \
-I$(topsrcdir)/content/events/src \
$(NULL)

View File

@ -49,15 +49,29 @@
#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 {
@ -229,6 +243,11 @@ SystemWorkerManager::Init()
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) {
@ -250,7 +269,9 @@ SystemWorkerManager::Shutdown()
mShutdown = true;
StopRil();
#ifdef MOZ_B2G_BT
StopDBus();
#endif
mRILWorker = nsnull;
nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
if (wifi) {
@ -363,6 +384,30 @@ SystemWorkerManager::InitWifi(JSContext *cx)
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

View File

@ -78,7 +78,8 @@ private:
nsresult InitRIL(JSContext *cx);
nsresult InitWifi(JSContext *cx);
nsresult InitBluetooth(JSContext *cx);
nsCOMPtr<nsIWorkerHolder> mRILWorker;
nsCOMPtr<nsIWorkerHolder> mWifiWorker;

View File

@ -47,6 +47,10 @@ ifdef MOZ_B2G_RIL #{
DIRS += ril
endif #}
ifdef MOZ_B2G_BT #{
DIRS += dbus
endif #}
TOOL_DIRS = app
include $(topsrcdir)/config/rules.mk

587
ipc/dbus/DBusThread.cpp Normal file
View File

@ -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;
}
}
}

25
ipc/dbus/DBusThread.h Normal file
View File

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

47
ipc/dbus/DBusUtils.cpp Normal file
View File

@ -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));
}
}
}

37
ipc/dbus/DBusUtils.h Normal file
View File

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

44
ipc/dbus/Makefile.in Normal file
View File

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

View File

@ -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;
}

View File

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

View File

@ -113,6 +113,10 @@ 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
@ -398,6 +402,7 @@ OS_LIBS += \
-lcamera_client \
-lbinder \
-lsensorservice \
-ldbus \
$(NULL)
endif