Bug 1091575: Add core interfaces and Setup module for Bluetooth daemon (under bluetooth2/), r=btian

This patch adds the core interfaces and the Setup module for
the Bluetooth Daemon. The Setup module implements commands
for enabling and disabling Bluetooth profiles in the daemon.
This commit is contained in:
Thomas Zimmermann 2014-11-14 10:04:33 +01:00
parent 485cca797b
commit d5b5010884
7 changed files with 1448 additions and 0 deletions

View File

@ -0,0 +1,65 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BluetoothDaemonHelpers.h"
BEGIN_BLUETOOTH_NAMESPACE
//
// Conversion
//
nsresult
Convert(uint8_t aIn, BluetoothStatus& aOut)
{
static const BluetoothStatus sStatus[] = {
CONVERT(0x00, STATUS_SUCCESS),
CONVERT(0x01, STATUS_FAIL),
CONVERT(0x02, STATUS_NOT_READY),
CONVERT(0x03, STATUS_NOMEM),
CONVERT(0x04, STATUS_BUSY),
CONVERT(0x05, STATUS_DONE),
CONVERT(0x06, STATUS_UNSUPPORTED),
CONVERT(0x07, STATUS_PARM_INVALID),
CONVERT(0x08, STATUS_UNHANDLED),
CONVERT(0x09, STATUS_AUTH_FAILURE),
CONVERT(0x0a, STATUS_RMT_DEV_DOWN)
};
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sStatus))) {
return NS_ERROR_ILLEGAL_VALUE;
}
aOut = sStatus[aIn];
return NS_OK;
}
//
// Packing
//
nsresult
PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU)
{
return PackPDU(aIn.mType, aIn.mLength,
PackArray<uint8_t>(aIn.mValue.get(), aIn.mLength), aPDU);
}
nsresult
PackPDU(const BluetoothDaemonPDUHeader& aIn, BluetoothDaemonPDU& aPDU)
{
return PackPDU(aIn.mService, aIn.mOpcode, aIn.mLength, aPDU);
}
//
// Unpacking
//
nsresult
UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothStatus& aOut)
{
return UnpackPDU(aPDU, UnpackConversion<uint8_t, BluetoothStatus>(aOut));
}
END_BLUETOOTH_NAMESPACE

View File

@ -0,0 +1,376 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothdaemonhelpers_h__
#define mozilla_dom_bluetooth_bluedroid_bluetoothdaemonhelpers_h__
#include "BluetoothCommon.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/ipc/BluetoothDaemonConnection.h"
#include "nsThreadUtils.h"
using namespace mozilla::ipc;
BEGIN_BLUETOOTH_NAMESPACE
struct BluetoothConfigurationParameter {
uint8_t mType;
uint16_t mLength;
nsAutoArrayPtr<uint8_t> mValue;
};
struct BluetoothDaemonPDUHeader {
BluetoothDaemonPDUHeader()
: mService(0x00)
, mOpcode(0x00)
, mLength(0x00)
{ }
BluetoothDaemonPDUHeader(uint8_t aService, uint8_t aOpcode, uint8_t aLength)
: mService(aService)
, mOpcode(aOpcode)
, mLength(aLength)
{ }
uint8_t mService;
uint8_t mOpcode;
uint16_t mLength;
};
//
// Conversion
//
// PDUs can only store primitive data types, such as integers or
// strings. Gecko often uses more complex data types, such as
// enumerators or structures. Conversion functions convert between
// primitive data and internal Gecko's data types during a PDU's
// packing and unpacking.
//
nsresult
Convert(uint8_t aIn, BluetoothStatus& aOut);
//
// Packing
//
inline nsresult
PackPDU(uint8_t aIn, BluetoothDaemonPDU& aPDU)
{
return aPDU.Write(aIn);
}
inline nsresult
PackPDU(uint16_t aIn, BluetoothDaemonPDU& aPDU)
{
return aPDU.Write(aIn);
}
nsresult
PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU);
nsresult
PackPDU(const BluetoothDaemonPDUHeader& aIn, BluetoothDaemonPDU& aPDU);
/* |PackArray| is a helper for packing arrays. Pass an instance
* of this structure as the first argument to |PackPDU| to pack
* an array. The array's maximum default length is 255 elements.
*/
template <typename T>
struct PackArray
{
PackArray(const T* aData, size_t aLength)
: mData(aData)
, mLength(aLength)
{ }
const T* mData;
size_t mLength;
};
/* This implementation of |PackPDU| packs the length of an array
* and the elements of the array one-by-one.
*/
template<typename T>
inline nsresult
PackPDU(const PackArray<T>& aIn, BluetoothDaemonPDU& aPDU)
{
for (size_t i = 0; i < aIn.mLength; ++i) {
nsresult rv = PackPDU(aIn.mData[i], aPDU);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
template <typename T1, typename T2>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, BluetoothDaemonPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn2, aPDU);
}
template <typename T1, typename T2, typename T3>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
BluetoothDaemonPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn3, aPDU);
}
template <typename T1, typename T2, typename T3, typename T4>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3, const T4& aIn4,
BluetoothDaemonPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn4, aPDU);
}
//
// Unpacking
//
inline nsresult
UnpackPDU(BluetoothDaemonPDU& aPDU, uint8_t& aOut)
{
return aPDU.Read(aOut);
}
inline nsresult
UnpackPDU(BluetoothDaemonPDU& aPDU, uint16_t& aOut)
{
return aPDU.Read(aOut);
}
inline nsresult
UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothDaemonPDUHeader& aOut)
{
nsresult rv = UnpackPDU(aPDU, aOut.mService);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(aPDU, aOut.mOpcode);
if (NS_FAILED(rv)) {
return rv;
}
return UnpackPDU(aPDU, aOut.mLength);
}
nsresult
UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothStatus& aOut);
/* |UnpackConversion| is a helper for convering unpacked values. Pass
* an instance of this structure to |UnpackPDU| to read a value from
* the PDU in the input type and convert it to the output type.
*/
template<typename Tin, typename Tout>
struct UnpackConversion {
UnpackConversion(Tout& aOut)
: mOut(aOut)
{ }
Tout& mOut;
};
template<typename Tin, typename Tout>
inline nsresult
UnpackPDU(BluetoothDaemonPDU& aPDU, const UnpackConversion<Tin, Tout>& aOut)
{
Tin in;
nsresult rv = UnpackPDU(aPDU, in);
if (NS_FAILED(rv)) {
return rv;
}
return Convert(in, aOut.mOut);
}
//
// Init operators
//
// |PDUInitOP| provides functionality for init operators that unpack PDUs.
class PDUInitOp
{
protected:
PDUInitOp(BluetoothDaemonPDU& aPDU)
: mPDU(&aPDU)
{ }
BluetoothDaemonPDU& GetPDU() const
{
return *mPDU; // cannot be nullptr
}
void WarnAboutTrailingData() const
{
size_t size = mPDU->GetSize();
if (MOZ_LIKELY(!size)) {
return;
}
uint8_t service, opcode;
uint16_t payloadSize;
mPDU->GetHeader(service, opcode, payloadSize);
BT_LOGR("Unpacked PDU of type (%x,%x) still contains %zu Bytes of data.",
service, opcode, size);
}
private:
BluetoothDaemonPDU* mPDU; // Hold pointer to allow for constant instances
};
// |UnpackPDUInitOp| is a general-purpose init operator for all variants
// of |BluetoothResultRunnable| and |BluetoothNotificationRunnable|. The
// call operators of |UnpackPDUInitOp| unpack a PDU into the supplied
// arguments.
class UnpackPDUInitOp MOZ_FINAL : private PDUInitOp
{
public:
UnpackPDUInitOp(BluetoothDaemonPDU& aPDU)
: PDUInitOp(aPDU)
{ }
nsresult operator () () const
{
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1>
nsresult operator () (T1& aArg1) const
{
nsresult rv = UnpackPDU(GetPDU(), aArg1);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2>
nsresult operator () (T1& aArg1, T2& aArg2) const
{
BluetoothDaemonPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3) const
{
BluetoothDaemonPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3, typename T4>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4) const
{
BluetoothDaemonPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg4);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3, typename T4, typename T5>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
T5& aArg5) const
{
BluetoothDaemonPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg4);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg5);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
};
END_BLUETOOTH_NAMESPACE
#endif

View File

@ -0,0 +1,813 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BluetoothDaemonInterface.h"
#include "BluetoothDaemonHelpers.h"
#include "BluetoothDaemonSetupInterface.h"
#include "BluetoothInterfaceHelpers.h"
#include "mozilla/unused.h"
using namespace mozilla::ipc;
BEGIN_BLUETOOTH_NAMESPACE
//
// Protocol initialization and setup
//
class BluetoothDaemonSetupModule
{
public:
enum {
SERVICE_ID = 0x00
};
enum {
OPCODE_ERROR = 0x00,
OPCODE_REGISTER_MODULE = 0x01,
OPCODE_UNREGISTER_MODULE = 0x02,
OPCODE_CONFIGURATION = 0x03
};
virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
// Commands
//
nsresult RegisterModuleCmd(uint8_t aId, uint8_t aMode,
BluetoothSetupResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoPtr<BluetoothDaemonPDU> pdu(
new BluetoothDaemonPDU(SERVICE_ID, OPCODE_REGISTER_MODULE, 0));
nsresult rv = PackPDU(aId, aMode, *pdu);
if (NS_FAILED(rv)) {
return rv;
}
rv = Send(pdu, aRes);
if (NS_FAILED(rv)) {
return rv;
}
unused << pdu.forget();
return rv;
}
nsresult UnregisterModuleCmd(uint8_t aId,
BluetoothSetupResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoPtr<BluetoothDaemonPDU> pdu(
new BluetoothDaemonPDU(SERVICE_ID, OPCODE_UNREGISTER_MODULE, 0));
nsresult rv = PackPDU(aId, *pdu);
if (NS_FAILED(rv)) {
return rv;
}
rv = Send(pdu, aRes);
if (NS_FAILED(rv)) {
return rv;
}
unused << pdu.forget();
return rv;
}
nsresult ConfigurationCmd(const BluetoothConfigurationParameter* aParam,
uint8_t aLen, BluetoothSetupResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoPtr<BluetoothDaemonPDU> pdu(
new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CONFIGURATION, 0));
nsresult rv = PackPDU(
aLen, PackArray<BluetoothConfigurationParameter>(aParam, aLen), *pdu);
if (NS_FAILED(rv)) {
return rv;
}
rv = Send(pdu, aRes);
if (NS_FAILED(rv)) {
return rv;
}
unused << pdu.forget();
return rv;
}
protected:
// Called to handle PDUs with Service field equal to 0x00, which
// contains internal operations for setup and configuration.
void HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
BluetoothDaemonPDU& aPDU, void* aUserData)
{
static void (BluetoothDaemonSetupModule::* const HandleRsp[])(
const BluetoothDaemonPDUHeader&,
BluetoothDaemonPDU&,
BluetoothSetupResultHandler*) = {
INIT_ARRAY_AT(OPCODE_ERROR,
&BluetoothDaemonSetupModule::ErrorRsp),
INIT_ARRAY_AT(OPCODE_REGISTER_MODULE,
&BluetoothDaemonSetupModule::RegisterModuleRsp),
INIT_ARRAY_AT(OPCODE_UNREGISTER_MODULE,
&BluetoothDaemonSetupModule::UnregisterModuleRsp),
INIT_ARRAY_AT(OPCODE_CONFIGURATION,
&BluetoothDaemonSetupModule::ConfigurationRsp)
};
if (NS_WARN_IF(aHeader.mOpcode >= MOZ_ARRAY_LENGTH(HandleRsp)) ||
NS_WARN_IF(!HandleRsp[aHeader.mOpcode])) {
return;
}
nsRefPtr<BluetoothSetupResultHandler> res =
already_AddRefed<BluetoothSetupResultHandler>(
static_cast<BluetoothSetupResultHandler*>(aUserData));
if (!res) {
return; // Return early if no result handler has been set
}
(this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
}
nsresult Send(BluetoothDaemonPDU* aPDU, BluetoothSetupResultHandler* aRes)
{
aRes->AddRef(); // Keep reference for response
return Send(aPDU, static_cast<void*>(aRes));
}
private:
// Responses
//
typedef
BluetoothResultRunnable0<BluetoothSetupResultHandler, void>
ResultRunnable;
typedef
BluetoothResultRunnable1<BluetoothSetupResultHandler, void,
BluetoothStatus, BluetoothStatus>
ErrorRunnable;
void
ErrorRsp(const BluetoothDaemonPDUHeader& aHeader,
BluetoothDaemonPDU& aPDU,
BluetoothSetupResultHandler* aRes)
{
ErrorRunnable::Dispatch(
aRes, &BluetoothSetupResultHandler::OnError, UnpackPDUInitOp(aPDU));
}
void
RegisterModuleRsp(const BluetoothDaemonPDUHeader& aHeader,
BluetoothDaemonPDU& aPDU,
BluetoothSetupResultHandler* aRes)
{
ResultRunnable::Dispatch(
aRes, &BluetoothSetupResultHandler::RegisterModule,
UnpackPDUInitOp(aPDU));
}
void
UnregisterModuleRsp(const BluetoothDaemonPDUHeader& aHeader,
BluetoothDaemonPDU& aPDU,
BluetoothSetupResultHandler* aRes)
{
ResultRunnable::Dispatch(
aRes, &BluetoothSetupResultHandler::UnregisterModule,
UnpackPDUInitOp(aPDU));
}
void
ConfigurationRsp(const BluetoothDaemonPDUHeader& aHeader,
BluetoothDaemonPDU& aPDU,
BluetoothSetupResultHandler* aRes)
{
ResultRunnable::Dispatch(
aRes, &BluetoothSetupResultHandler::Configuration,
UnpackPDUInitOp(aPDU));
}
};
//
// Core module
//
static BluetoothNotificationHandler* sNotificationHandler;
//
// Protocol handling
//
class BluetoothDaemonProtocol MOZ_FINAL
: public BluetoothDaemonPDUConsumer
, public BluetoothDaemonSetupModule
{
public:
BluetoothDaemonProtocol(BluetoothDaemonConnection* aConnection);
// Outgoing PDUs
//
nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) MOZ_OVERRIDE;
void StoreUserData(const BluetoothDaemonPDU& aPDU) MOZ_OVERRIDE;
// Incoming PUDs
//
void Handle(BluetoothDaemonPDU& aPDU) MOZ_OVERRIDE;
void* FetchUserData(const BluetoothDaemonPDUHeader& aHeader);
private:
void HandleSetupSvc(const BluetoothDaemonPDUHeader& aHeader,
BluetoothDaemonPDU& aPDU, void* aUserData);
BluetoothDaemonConnection* mConnection;
nsTArray<void*> mUserDataQ;
};
BluetoothDaemonProtocol::BluetoothDaemonProtocol(
BluetoothDaemonConnection* aConnection)
: mConnection(aConnection)
{
MOZ_ASSERT(mConnection);
}
nsresult
BluetoothDaemonProtocol::Send(BluetoothDaemonPDU* aPDU, void* aUserData)
{
MOZ_ASSERT(aPDU);
aPDU->SetUserData(aUserData);
aPDU->UpdateHeader();
return mConnection->Send(aPDU); // Forward PDU to command channel
}
void
BluetoothDaemonProtocol::HandleSetupSvc(
const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
void* aUserData)
{
BluetoothDaemonSetupModule::HandleSvc(aHeader, aPDU, aUserData);
}
void
BluetoothDaemonProtocol::Handle(BluetoothDaemonPDU& aPDU)
{
static void (BluetoothDaemonProtocol::* const HandleSvc[])(
const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = {
[0] = &BluetoothDaemonProtocol::HandleSetupSvc
};
BluetoothDaemonPDUHeader header;
if (NS_FAILED(UnpackPDU(aPDU, header)) ||
NS_WARN_IF(!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc))) ||
NS_WARN_IF(!(HandleSvc[header.mService]))) {
return;
}
(this->*(HandleSvc[header.mService]))(header, aPDU, FetchUserData(header));
}
void
BluetoothDaemonProtocol::StoreUserData(const BluetoothDaemonPDU& aPDU)
{
MOZ_ASSERT(!NS_IsMainThread());
mUserDataQ.AppendElement(aPDU.GetUserData());
}
void*
BluetoothDaemonProtocol::FetchUserData(const BluetoothDaemonPDUHeader& aHeader)
{
MOZ_ASSERT(!NS_IsMainThread());
if (aHeader.mOpcode & 0x80) {
return nullptr; // Ignore notifications
}
void* userData = mUserDataQ.ElementAt(0);
mUserDataQ.RemoveElementAt(0);
return userData;
}
//
// Channels
//
class BluetoothDaemonChannel MOZ_FINAL : public BluetoothDaemonConnection
{
public:
BluetoothDaemonChannel(BluetoothDaemonInterface::Channel aChannel);
nsresult ConnectSocket(BluetoothDaemonInterface* aInterface,
BluetoothDaemonPDUConsumer* aConsumer);
// Connection state
//
void OnConnectSuccess() MOZ_OVERRIDE;
void OnConnectError() MOZ_OVERRIDE;
void OnDisconnect() MOZ_OVERRIDE;
private:
BluetoothDaemonInterface* mInterface;
BluetoothDaemonInterface::Channel mChannel;
};
BluetoothDaemonChannel::BluetoothDaemonChannel(
BluetoothDaemonInterface::Channel aChannel)
: mInterface(nullptr)
, mChannel(aChannel)
{ }
nsresult
BluetoothDaemonChannel::ConnectSocket(BluetoothDaemonInterface* aInterface,
BluetoothDaemonPDUConsumer* aConsumer)
{
MOZ_ASSERT(aInterface);
mInterface = aInterface;
return BluetoothDaemonConnection::ConnectSocket(aConsumer);
}
void
BluetoothDaemonChannel::OnConnectSuccess()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mInterface);
mInterface->OnConnectSuccess(mChannel);
}
void
BluetoothDaemonChannel::OnConnectError()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mInterface);
mInterface->OnConnectError(mChannel);
mInterface = nullptr;
}
void
BluetoothDaemonChannel::OnDisconnect()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mInterface);
mInterface->OnDisconnect(mChannel);
mInterface = nullptr;
}
//
// Interface
//
/* returns the container structure of a variable; _t is the container's
* type, _v the name of the variable, and _m is _v's field within _t
*/
#define container(_t, _v, _m) \
( (_t*)( ((const unsigned char*)(_v)) - offsetof(_t, _m) ) )
BluetoothDaemonInterface*
BluetoothDaemonInterface::GetInstance()
{
static BluetoothDaemonInterface* sBluetoothInterface;
if (sBluetoothInterface) {
return sBluetoothInterface;
}
// Only create channel objects here. The connection will be
// established by |BluetoothDaemonInterface::Init|.
BluetoothDaemonChannel* cmdChannel =
new BluetoothDaemonChannel(BluetoothDaemonInterface::CMD_CHANNEL);
BluetoothDaemonChannel* ntfChannel =
new BluetoothDaemonChannel(BluetoothDaemonInterface::NTF_CHANNEL);
// Create a new interface object with the channels and a
// protocol handler.
sBluetoothInterface =
new BluetoothDaemonInterface(cmdChannel,
ntfChannel,
new BluetoothDaemonProtocol(cmdChannel));
return sBluetoothInterface;
}
BluetoothDaemonInterface::BluetoothDaemonInterface(
BluetoothDaemonChannel* aCmdChannel,
BluetoothDaemonChannel* aNtfChannel,
BluetoothDaemonProtocol* aProtocol)
: mCmdChannel(aCmdChannel)
, mNtfChannel(aNtfChannel)
, mProtocol(aProtocol)
{
MOZ_ASSERT(mCmdChannel);
MOZ_ASSERT(mNtfChannel);
MOZ_ASSERT(mProtocol);
}
BluetoothDaemonInterface::~BluetoothDaemonInterface()
{ }
class BluetoothDaemonInterface::InitResultHandler MOZ_FINAL
: public BluetoothSetupResultHandler
{
public:
InitResultHandler(BluetoothDaemonInterface* aInterface,
BluetoothResultHandler* aRes)
: mInterface(aInterface)
, mRes(aRes)
, mRegisteredSocketModule(false)
{
MOZ_ASSERT(mInterface);
}
// We need to call methods from the |BluetoothResultHandler|. Since
// we're already on the main thread and returned from Init, we don't
// need to dispatch a new runnable.
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
// TODO: close channels
if (mRes) {
mRes->OnError(aStatus);
}
}
void RegisterModule() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mInterface->mProtocol);
if (!mRegisteredSocketModule) {
mRegisteredSocketModule = true;
// Init, step 4: Register Socket module
mInterface->mProtocol->RegisterModuleCmd(0x02, 0x00, this);
} else if (mRes) {
// Init, step 5: Signal success to caller
mRes->Init();
}
}
private:
BluetoothDaemonInterface* mInterface;
nsRefPtr<BluetoothResultHandler> mRes;
bool mRegisteredSocketModule;
};
void
BluetoothDaemonInterface::OnConnectSuccess(enum Channel aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
switch (aChannel) {
case CMD_CHANNEL:
// Init, step 2: Connect notification channel...
if (mNtfChannel->GetConnectionStatus() != SOCKET_CONNECTED) {
nsresult rv = mNtfChannel->ConnectSocket(this, mProtocol);
if (NS_FAILED(rv)) {
OnConnectError(NTF_CHANNEL);
}
} else {
// ...or go to step 3 if channel is already connected.
OnConnectSuccess(NTF_CHANNEL);
}
break;
case NTF_CHANNEL: {
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
mResultHandlerQ.RemoveElementAt(0);
// Init, step 3: Register Core module
nsresult rv = mProtocol->RegisterModuleCmd(
0x01, 0x00, new InitResultHandler(this, res));
if (NS_FAILED(rv) && res) {
DispatchError(res, STATUS_FAIL);
}
}
break;
}
}
void
BluetoothDaemonInterface::OnConnectError(enum Channel aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
switch (aChannel) {
case NTF_CHANNEL:
// Close command channel
mCmdChannel->CloseSocket();
/* fall through for cleanup and error signalling */
case CMD_CHANNEL: {
// Signal error to caller
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
mResultHandlerQ.RemoveElementAt(0);
if (res) {
DispatchError(res, STATUS_FAIL);
}
}
break;
}
}
void
BluetoothDaemonInterface::OnDisconnect(enum Channel aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
switch (aChannel) {
case NTF_CHANNEL:
// Cleanup, step 4: Close command channel
mCmdChannel->CloseSocket();
break;
case CMD_CHANNEL: {
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
mResultHandlerQ.RemoveElementAt(0);
// Cleanup, step 5: Signal success to caller
if (res) {
res->Cleanup();
}
}
break;
}
}
void
BluetoothDaemonInterface::Init(
BluetoothNotificationHandler* aNotificationHandler,
BluetoothResultHandler* aRes)
{
sNotificationHandler = aNotificationHandler;
mResultHandlerQ.AppendElement(aRes);
// Init, step 1: Connect command channel...
if (mCmdChannel->GetConnectionStatus() != SOCKET_CONNECTED) {
nsresult rv = mCmdChannel->ConnectSocket(this, mProtocol);
if (NS_FAILED(rv)) {
OnConnectError(CMD_CHANNEL);
}
} else {
// ...or go to step 2 if channel is already connected.
OnConnectSuccess(CMD_CHANNEL);
}
}
class BluetoothDaemonInterface::CleanupResultHandler MOZ_FINAL
: public BluetoothSetupResultHandler
{
public:
CleanupResultHandler(BluetoothDaemonInterface* aInterface)
: mInterface(aInterface)
, mUnregisteredCoreModule(false)
{
MOZ_ASSERT(mInterface);
}
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
{
Proceed();
}
void UnregisterModule() MOZ_OVERRIDE
{
Proceed();
}
private:
void Proceed()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mInterface->mProtocol);
if (!mUnregisteredCoreModule) {
mUnregisteredCoreModule = true;
// Cleanup, step 2: Unregister Core module
mInterface->mProtocol->UnregisterModuleCmd(0x01, this);
} else {
// Cleanup, step 3: Close notification channel
mInterface->mNtfChannel->CloseSocket();
}
}
BluetoothDaemonInterface* mInterface;
bool mUnregisteredCoreModule;
};
void
BluetoothDaemonInterface::Cleanup(BluetoothResultHandler* aRes)
{
sNotificationHandler = nullptr;
mResultHandlerQ.AppendElement(aRes);
// Cleanup, step 1: Unregister Socket module
mProtocol->UnregisterModuleCmd(0x02, new CleanupResultHandler(this));
}
void
BluetoothDaemonInterface::Enable(BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::Disable(BluetoothResultHandler* aRes)
{
}
/* Adapter Properties */
void
BluetoothDaemonInterface::GetAdapterProperties(BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::GetAdapterProperty(const nsAString& aName,
BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::SetAdapterProperty(
const BluetoothNamedValue& aProperty, BluetoothResultHandler* aRes)
{
}
/* Remote Device Properties */
void
BluetoothDaemonInterface::GetRemoteDeviceProperties(
const nsAString& aRemoteAddr, BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::GetRemoteDeviceProperty(
const nsAString& aRemoteAddr, const nsAString& aName,
BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::SetRemoteDeviceProperty(
const nsAString& aRemoteAddr, const BluetoothNamedValue& aProperty,
BluetoothResultHandler* aRes)
{
}
/* Remote Services */
void
BluetoothDaemonInterface::GetRemoteServiceRecord(const nsAString& aRemoteAddr,
const uint8_t aUuid[16],
BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::GetRemoteServices(const nsAString& aRemoteAddr,
BluetoothResultHandler* aRes)
{
}
/* Discovery */
void
BluetoothDaemonInterface::StartDiscovery(BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::CancelDiscovery(BluetoothResultHandler* aRes)
{
}
/* Bonds */
void
BluetoothDaemonInterface::CreateBond(const nsAString& aBdAddr,
BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::RemoveBond(const nsAString& aBdAddr,
BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::CancelBond(const nsAString& aBdAddr,
BluetoothResultHandler* aRes)
{
}
/* Authentication */
void
BluetoothDaemonInterface::PinReply(const nsAString& aBdAddr, bool aAccept,
const nsAString& aPinCode,
BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::SspReply(const nsAString& aBdAddr,
const nsAString& aVariant,
bool aAccept, uint32_t aPasskey,
BluetoothResultHandler* aRes)
{
}
/* DUT Mode */
void
BluetoothDaemonInterface::DutModeConfigure(bool aEnable,
BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::DutModeSend(uint16_t aOpcode, uint8_t* aBuf,
uint8_t aLen,
BluetoothResultHandler* aRes)
{
}
/* LE Mode */
void
BluetoothDaemonInterface::LeTestMode(uint16_t aOpcode, uint8_t* aBuf,
uint8_t aLen,
BluetoothResultHandler* aRes)
{
}
void
BluetoothDaemonInterface::DispatchError(BluetoothResultHandler* aRes,
BluetoothStatus aStatus)
{
BluetoothResultRunnable1<
BluetoothResultHandler, void, BluetoothStatus, BluetoothStatus>::Dispatch(
aRes, &BluetoothResultHandler::OnError,
ConstantInitOp1<BluetoothStatus>(aStatus));
}
BluetoothSocketInterface*
BluetoothDaemonInterface::GetBluetoothSocketInterface()
{
return nullptr;
}
BluetoothHandsfreeInterface*
BluetoothDaemonInterface::GetBluetoothHandsfreeInterface()
{
return nullptr;
}
BluetoothA2dpInterface*
BluetoothDaemonInterface::GetBluetoothA2dpInterface()
{
return nullptr;
}
BluetoothAvrcpInterface*
BluetoothDaemonInterface::GetBluetoothAvrcpInterface()
{
return nullptr;
}
BluetoothGattInterface*
BluetoothDaemonInterface::GetBluetoothGattInterface()
{
return nullptr;
}
END_BLUETOOTH_NAMESPACE

View File

@ -0,0 +1,130 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__
#define mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__
#include "BluetoothInterface.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothDaemonChannel;
class BluetoothDaemonProtocol;
class BluetoothDaemonInterface MOZ_FINAL : public BluetoothInterface
{
public:
class CleanupResultHandler;
class InitResultHandler;
friend class BluetoothDaemonChannel;
friend class CleanupResultHandler;
friend class InitResultHandler;
static BluetoothDaemonInterface* GetInstance();
void Init(BluetoothNotificationHandler* aNotificationHandler,
BluetoothResultHandler* aRes);
void Cleanup(BluetoothResultHandler* aRes);
void Enable(BluetoothResultHandler* aRes);
void Disable(BluetoothResultHandler* aRes);
/* Adapter Properties */
void GetAdapterProperties(BluetoothResultHandler* aRes);
void GetAdapterProperty(const nsAString& aName,
BluetoothResultHandler* aRes);
void SetAdapterProperty(const BluetoothNamedValue& aProperty,
BluetoothResultHandler* aRes);
/* Remote Device Properties */
void GetRemoteDeviceProperties(const nsAString& aRemoteAddr,
BluetoothResultHandler* aRes);
void GetRemoteDeviceProperty(const nsAString& aRemoteAddr,
const nsAString& aName,
BluetoothResultHandler* aRes);
void SetRemoteDeviceProperty(const nsAString& aRemoteAddr,
const BluetoothNamedValue& aProperty,
BluetoothResultHandler* aRes);
/* Remote Services */
void GetRemoteServiceRecord(const nsAString& aRemoteAddr,
const uint8_t aUuid[16],
BluetoothResultHandler* aRes);
void GetRemoteServices(const nsAString& aRemoteAddr,
BluetoothResultHandler* aRes);
/* Discovery */
void StartDiscovery(BluetoothResultHandler* aRes);
void CancelDiscovery(BluetoothResultHandler* aRes);
/* Bonds */
void CreateBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes);
void RemoveBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes);
void CancelBond(const nsAString& aBdAddr, BluetoothResultHandler* aRes);
/* Authentication */
void PinReply(const nsAString& aBdAddr, bool aAccept,
const nsAString& aPinCode,
BluetoothResultHandler* aRes);
void SspReply(const nsAString& aBdAddr, const nsAString& aVariant,
bool aAccept, uint32_t aPasskey,
BluetoothResultHandler* aRes);
/* DUT Mode */
void DutModeConfigure(bool aEnable, BluetoothResultHandler* aRes);
void DutModeSend(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
BluetoothResultHandler* aRes);
/* LE Mode */
void LeTestMode(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
BluetoothResultHandler* aRes);
/* Profile Interfaces */
BluetoothSocketInterface* GetBluetoothSocketInterface() MOZ_OVERRIDE;
BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() MOZ_OVERRIDE;
BluetoothA2dpInterface* GetBluetoothA2dpInterface() MOZ_OVERRIDE;
BluetoothAvrcpInterface* GetBluetoothAvrcpInterface() MOZ_OVERRIDE;
BluetoothGattInterface* GetBluetoothGattInterface() MOZ_OVERRIDE;
protected:
enum Channel {
CMD_CHANNEL,
NTF_CHANNEL
};
BluetoothDaemonInterface(BluetoothDaemonChannel* aCmdChannel,
BluetoothDaemonChannel* aNtfChannel,
BluetoothDaemonProtocol* aProtocol);
~BluetoothDaemonInterface();
void OnConnectSuccess(enum Channel aChannel);
void OnConnectError(enum Channel aChannel);
void OnDisconnect(enum Channel aChannel);
private:
void DispatchError(BluetoothResultHandler* aRes, BluetoothStatus aStatus);
nsAutoPtr<BluetoothDaemonChannel> mCmdChannel;
nsAutoPtr<BluetoothDaemonChannel> mNtfChannel;
nsAutoPtr<BluetoothDaemonProtocol> mProtocol;
nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
};
END_BLUETOOTH_NAMESPACE
#endif

View File

@ -0,0 +1,32 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BluetoothDaemonSetupInterface.h"
BEGIN_BLUETOOTH_NAMESPACE
BluetoothSetupResultHandler::~BluetoothSetupResultHandler()
{ }
void
BluetoothSetupResultHandler::OnError(BluetoothStatus aStatus)
{
BT_WARNING("Received error code %d", (int)aStatus);
}
void
BluetoothSetupResultHandler::RegisterModule()
{ }
void
BluetoothSetupResultHandler::UnregisterModule()
{ }
void
BluetoothSetupResultHandler::Configuration()
{ }
END_BLUETOOTH_NAMESPACE

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=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_bluetooth_bluedroid_bluetoothdaemonsetupinterface_h__
#define mozilla_dom_bluetooth_bluedroid_bluetoothdaemonsetupinterface_h__
#include "BluetoothCommon.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothSetupResultHandler
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothSetupResultHandler)
virtual ~BluetoothSetupResultHandler();
virtual void OnError(BluetoothStatus aStatus);
virtual void RegisterModule();
virtual void UnregisterModule();
virtual void Configuration();
};
END_BLUETOOTH_NAMESPACE
#endif

View File

@ -51,6 +51,9 @@ if CONFIG['MOZ_B2G_BT']:
'bluedroid/BluetoothA2dpHALInterface.cpp',
'bluedroid/BluetoothA2dpManager.cpp',
'bluedroid/BluetoothAvrcpHALInterface.cpp',
'bluedroid/BluetoothDaemonHelpers.cpp',
'bluedroid/BluetoothDaemonInterface.cpp',
'bluedroid/BluetoothDaemonSetupInterface.cpp',
'bluedroid/BluetoothGattHALInterface.cpp',
'bluedroid/BluetoothGattManager.cpp',
'bluedroid/BluetoothHALHelpers.cpp',