From 2b6d77373a6ee3c3b7c0a233343cedf62c7788a0 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 14 Nov 2014 10:04:33 +0100 Subject: [PATCH] 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. --- .../bluedroid/BluetoothDaemonHelpers.cpp | 65 ++ .../bluedroid/BluetoothDaemonHelpers.h | 376 ++++++++ .../bluedroid/BluetoothDaemonInterface.cpp | 813 ++++++++++++++++++ .../bluedroid/BluetoothDaemonInterface.h | 130 +++ .../BluetoothDaemonSetupInterface.cpp | 32 + .../bluedroid/BluetoothDaemonSetupInterface.h | 29 + dom/bluetooth2/moz.build | 3 + 7 files changed, 1448 insertions(+) create mode 100644 dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp create mode 100644 dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h create mode 100644 dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp create mode 100644 dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h create mode 100644 dom/bluetooth2/bluedroid/BluetoothDaemonSetupInterface.cpp create mode 100644 dom/bluetooth2/bluedroid/BluetoothDaemonSetupInterface.h diff --git a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp new file mode 100644 index 000000000000..2c9aedd21ca0 --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp @@ -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(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(aOut)); +} + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h new file mode 100644 index 000000000000..93f0c013b0eb --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h @@ -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 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 +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 +inline nsresult +PackPDU(const PackArray& 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 +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 +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 +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 +struct UnpackConversion { + UnpackConversion(Tout& aOut) + : mOut(aOut) + { } + + Tout& mOut; +}; + +template +inline nsresult +UnpackPDU(BluetoothDaemonPDU& aPDU, const UnpackConversion& 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 + nsresult operator () (T1& aArg1) const + { + nsresult rv = UnpackPDU(GetPDU(), aArg1); + if (NS_FAILED(rv)) { + return rv; + } + WarnAboutTrailingData(); + return NS_OK; + } + + template + 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 + 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 + 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 + 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 diff --git a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp new file mode 100644 index 000000000000..8a2eb9c5c47b --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp @@ -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 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 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 pdu( + new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CONFIGURATION, 0)); + + nsresult rv = PackPDU( + aLen, PackArray(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 res = + already_AddRefed( + static_cast(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(aRes)); + } + +private: + + // Responses + // + + typedef + BluetoothResultRunnable0 + ResultRunnable; + + typedef + BluetoothResultRunnable1 + 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 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 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 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 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 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(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 diff --git a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h new file mode 100644 index 000000000000..389fa3404b4e --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h @@ -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 mCmdChannel; + nsAutoPtr mNtfChannel; + nsAutoPtr mProtocol; + + nsTArray > mResultHandlerQ; +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth2/bluedroid/BluetoothDaemonSetupInterface.cpp b/dom/bluetooth2/bluedroid/BluetoothDaemonSetupInterface.cpp new file mode 100644 index 000000000000..3b2e4261caf1 --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothDaemonSetupInterface.cpp @@ -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 diff --git a/dom/bluetooth2/bluedroid/BluetoothDaemonSetupInterface.h b/dom/bluetooth2/bluedroid/BluetoothDaemonSetupInterface.h new file mode 100644 index 000000000000..60a659485a32 --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothDaemonSetupInterface.h @@ -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 diff --git a/dom/bluetooth2/moz.build b/dom/bluetooth2/moz.build index dd516a3c1577..10ba25e4d6a3 100644 --- a/dom/bluetooth2/moz.build +++ b/dom/bluetooth2/moz.build @@ -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',