From 1225ee6a20c3a1651e0fa59ebbfb3d1ef0f81afc Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 3 Nov 2014 13:03:49 +0100 Subject: [PATCH] Bug 1073548: Add core interfaces and Setup module for Bluetooth daemon, r=shawnjohnjr 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 | 1004 +++++++++++++++++ .../bluedroid/BluetoothDaemonInterface.cpp | 789 +++++++++++++ .../bluedroid/BluetoothDaemonInterface.h | 129 +++ .../BluetoothDaemonSetupInterface.cpp | 32 + .../bluedroid/BluetoothDaemonSetupInterface.h | 29 + dom/bluetooth/moz.build | 3 + 7 files changed, 2051 insertions(+) create mode 100644 dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp create mode 100644 dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h create mode 100644 dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp create mode 100644 dom/bluetooth/bluedroid/BluetoothDaemonInterface.h create mode 100644 dom/bluetooth/bluedroid/BluetoothDaemonSetupInterface.cpp create mode 100644 dom/bluetooth/bluedroid/BluetoothDaemonSetupInterface.h diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp new file mode 100644 index 000000000000..2c9aedd21ca0 --- /dev/null +++ b/dom/bluetooth/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/bluetooth/bluedroid/BluetoothDaemonHelpers.h b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h new file mode 100644 index 000000000000..1370e6b64c8e --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h @@ -0,0 +1,1004 @@ +/* -*- 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" + +#if MOZ_IS_GCC && MOZ_GCC_VERSION_AT_LEAST(4, 7, 0) +/* use designated array initializers if supported */ +#define CONVERT(in_, out_) \ + [in_] = out_ +#else +/* otherwise init array element by position */ +#define CONVERT(in_, out_) \ + out_ +#endif + +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 intergers or +// strings. Gecko often uses more complex data types, such as +// enumators or stuctures. 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); +} + +template +inline nsresult +UnpackPDU(BluetoothDaemonPDU& aPDU, T1& aArg1) +{ + return UnpackPDU(aPDU, aArg1); +} + +template +inline nsresult +UnpackPDU(BluetoothDaemonPDU& aPDU, T1& aArg1, T2& aArg2) +{ + nsresult rv = UnpackPDU(aPDU, aArg1); + if (NS_FAILED(rv)) { + return rv; + } + return UnpackPDU(aPDU, aArg2); +} + +template +inline nsresult +UnpackPDU(BluetoothDaemonPDU& aPDU, T1& aArg1, T2& aArg2, T3& aArg3) +{ + nsresult rv = UnpackPDU(aPDU, aArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aArg2); + if (NS_FAILED(rv)) { + return rv; + } + return UnpackPDU(aPDU, aArg3); +} + +template +inline nsresult +UnpackPDU(BluetoothDaemonPDU& aPDU, T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4) +{ + nsresult rv = UnpackPDU(aPDU, aArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aArg2); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aArg3); + if (NS_FAILED(rv)) { + return rv; + } + return UnpackPDU(aPDU, aArg4); +} + +template +inline nsresult +UnpackPDU(BluetoothDaemonPDU& aPDU, + T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4, T5& aArg5) +{ + nsresult rv = UnpackPDU(aPDU, aArg1); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aArg2); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aArg3); + if (NS_FAILED(rv)) { + return rv; + } + rv = UnpackPDU(aPDU, aArg4); + if (NS_FAILED(rv)) { + return rv; + } + return UnpackPDU(aPDU, aArg5); +} + +// +// Result handling +// + +template +class BluetoothDaemonInterfaceRunnable0 : public nsRunnable +{ +public: + typedef BluetoothDaemonInterfaceRunnable0 SelfType; + + static already_AddRefed Create( + Obj* aObj, Res (Obj::*aMethod)()) + { + nsRefPtr runnable(new SelfType(aObj, aMethod)); + + return runnable.forget(); + } + + static void + Dispatch(Obj* aObj, Res (Obj::*aMethod)()) + { + nsRefPtr runnable = Create(aObj, aMethod); + if (!runnable) { + BT_WARNING("BluetoothDaemonInterfaceRunnable0::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + ((*mObj).*mMethod)(); + return NS_OK; + } + +private: + BluetoothDaemonInterfaceRunnable0(Obj* aObj, Res (Obj::*aMethod)()) + : mObj(aObj) + , mMethod(aMethod) + { + MOZ_ASSERT(mObj); + MOZ_ASSERT(mMethod); + } + + nsRefPtr mObj; + void (Obj::*mMethod)(); +}; + +template +class BluetoothDaemonInterfaceRunnable1 : public nsRunnable +{ +public: + typedef BluetoothDaemonInterfaceRunnable1 SelfType; + + template + static already_AddRefed Create( + Obj* aObj, Res (Obj::*aMethod)(Arg1), BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable(new SelfType(aObj, aMethod)); + + if (NS_FAILED((runnable->UnpackAndSet(aPDU)))) { + return nullptr; + } + return runnable.forget(); + } + + static already_AddRefed Create( + Obj* aObj, Res (Obj::*aMethod)(Arg1), const Arg1& aArg1) + { + nsRefPtr runnable(new SelfType(aObj, aMethod, aArg1)); + return runnable.forget(); + } + + template + static void + Dispatch(Obj* aObj, Res (Obj::*aMethod)(Arg1), + BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable = Create(aObj, aMethod, aPDU); + if (!runnable) { + BT_WARNING("BluetoothDaemonInterfaceRunnable1::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + static void + Dispatch(Obj* aObj, Res (Obj::*aMethod)(Arg1), const Tin1& aArg1) + { + nsRefPtr runnable = Create(aObj, aMethod, aArg1); + if (!runnable) { + BT_WARNING("BluetoothDaemonInterfaceRunnable1::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + ((*mObj).*mMethod)(mArg1); + return NS_OK; + } + +private: + BluetoothDaemonInterfaceRunnable1(Obj* aObj, Res (Obj::*aMethod)(Arg1)) + : mObj(aObj) + , mMethod(aMethod) + { + MOZ_ASSERT(mObj); + MOZ_ASSERT(mMethod); + } + + BluetoothDaemonInterfaceRunnable1(Obj* aObj, Res (Obj::*aMethod)(Arg1), + const Tin1& aArg1) + : mObj(aObj) + , mMethod(aMethod) + , mArg1(aArg1) + { + MOZ_ASSERT(mObj); + MOZ_ASSERT(mMethod); + } + + template + nsresult + UnpackAndSet(BluetoothDaemonPDU& aPDU) + { + return UnpackPDU(aPDU, mArg1); + } + + nsRefPtr mObj; + Res (Obj::*mMethod)(Arg1); + Tin1 mArg1; +}; + +template +class BluetoothDaemonInterfaceRunnable3 : public nsRunnable +{ +public: + typedef BluetoothDaemonInterfaceRunnable3 SelfType; + + template + static already_AddRefed Create( + Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3), BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable(new SelfType(aObj, aMethod)); + + if (NS_FAILED((runnable->UnpackAndSet(aPDU)))) { + return nullptr; + } + return runnable.forget(); + } + + static already_AddRefed Create( + Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3), + const Tin1& aArg1, const Tin2& aArg2, const Tin3& aArg3) + { + nsRefPtr runnable(new SelfType(aObj, aMethod, + aArg1, aArg2, aArg3)); + return runnable.forget(); + } + + template + static void + Dispatch(Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3), + BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable = Create(aObj, aMethod, aPDU); + if (!runnable) { + BT_WARNING("BluetoothDaemonInterfaceRunnable3::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + static void + Dispatch(Obj* aObj, Res (Obj::*aMethod)(Arg1, Arg2, Arg3), + const Tin1& aArg1, const Tin2& aArg2, const Tin3& aArg3) + { + nsRefPtr runnable = Create(aObj, aMethod, aArg1, aArg2, aArg3); + if (!runnable) { + BT_WARNING("BluetoothDaemonInterfaceRunnable3::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + ((*mObj).*mMethod)(mArg1, mArg2, mArg3); + return NS_OK; + } + +private: + BluetoothDaemonInterfaceRunnable3(Obj* aObj, + Res (Obj::*aMethod)(Arg1, Arg2, Arg3)) + : mObj(aObj) + , mMethod(aMethod) + { + MOZ_ASSERT(mObj); + MOZ_ASSERT(mMethod); + } + + BluetoothDaemonInterfaceRunnable3(Obj* aObj, + Res (Obj::*aMethod)(Arg1, Arg2, Arg3), + const Tin1& aArg1, const Tin2& aArg2, + const Tin3& aArg3) + : mObj(aObj) + , mMethod(aMethod) + , mArg1(aArg1) + , mArg2(aArg2) + , mArg3(aArg3) + { + MOZ_ASSERT(mObj); + MOZ_ASSERT(mMethod); + } + + template + nsresult + UnpackAndSet(BluetoothDaemonPDU& aPDU) + { + return UnpackPDU(aPDU, + mArg1, mArg2, + mArg3); + } + + nsRefPtr mObj; + Res (Obj::*mMethod)(Arg1, Arg2, Arg3); + Tin1 mArg1; + Tin2 mArg2; + Tin3 mArg3; +}; + +// +// Notification handling +// + +template +class BluetoothDaemonNotificationRunnable0 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothDaemonNotificationRunnable0 SelfType; + + static already_AddRefed Create(Res (ObjectType::*aMethod)()) + { + nsRefPtr runnable(new SelfType(aMethod)); + + return runnable.forget(); + } + + static void + Dispatch(Res (ObjectType::*aMethod)()) + { + nsRefPtr runnable = Create(aMethod); + + if (!runnable) { + BT_WARNING("BluetoothDaemonNotificationRunnable0::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(); + } + return NS_OK; + } + +private: + BluetoothDaemonNotificationRunnable0(Res (ObjectType::*aMethod)()) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + Res (ObjectType::*mMethod)(); +}; + +template +class BluetoothDaemonNotificationRunnable1 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothDaemonNotificationRunnable1 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1), BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED((runnable->UnpackAndSet(aPDU)))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1), BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable = Create(aMethod, aPDU); + + if (!runnable) { + BT_WARNING("BluetoothDaemonNotificationRunnable1::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1); + } + return NS_OK; + } + +private: + BluetoothDaemonNotificationRunnable1(Res (ObjectType::*aMethod)(Arg1)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + UnpackAndSet(BluetoothDaemonPDU& aPDU) + { + return UnpackPDU(aPDU, mArg1); + } + + Res (ObjectType::*mMethod)(Arg1); + Tin1 mArg1; +}; + +template +class BluetoothDaemonNotificationRunnable2 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothDaemonNotificationRunnable2 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2), BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED((runnable->UnpackAndSet(aPDU)))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2), + BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable = Create(aMethod, aPDU); + + if (!runnable) { + BT_WARNING("BluetoothDaemonNotificationRunnable2::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1, mArg2); + } + return NS_OK; + } + +private: + BluetoothDaemonNotificationRunnable2( + Res (ObjectType::*aMethod)(Arg1, Arg2)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + UnpackAndSet(BluetoothDaemonPDU& aPDU) + { + return UnpackPDU(aPDU, mArg1, mArg2); + } + + Res (ObjectType::*mMethod)(Arg1, Arg2); + Tin1 mArg1; + Tin2 mArg2; +}; + +template +class BluetoothDaemonNotificationRunnable3 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothDaemonNotificationRunnable3 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), + BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED((runnable->UnpackAndSet(aPDU)))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3), + BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable = Create(aMethod, aPDU); + if (!runnable) { + BT_WARNING("BluetoothDaemonNotificationRunnable3::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1, mArg2, mArg3); + } + return NS_OK; + } + +private: + BluetoothDaemonNotificationRunnable3( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + UnpackAndSet(BluetoothDaemonPDU& aPDU) + { + return UnpackPDU(aPDU, + mArg1, mArg2, + mArg3); + } + + Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3); + Tin1 mArg1; + Tin2 mArg2; + Tin3 mArg3; +}; + +template +class BluetoothDaemonNotificationRunnable4 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothDaemonNotificationRunnable4 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), + BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED((runnable->UnpackAndSet(aPDU)))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4), + BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable = Create(aMethod, aPDU); + if (!runnable) { + BT_WARNING("BluetoothDaemonNotificationRunnable4::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1, mArg2, mArg3, mArg4); + } + return NS_OK; + } + +private: + BluetoothDaemonNotificationRunnable4( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + UnpackAndSet(BluetoothDaemonPDU& aPDU) + { + return UnpackPDU(aPDU, + mArg1, mArg2, + mArg3, mArg4); + } + + Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4); + Tin1 mArg1; + Tin2 mArg2; + Tin3 mArg3; + Tin4 mArg4; +}; + +template +class BluetoothDaemonNotificationRunnable5 : public nsRunnable +{ +public: + typedef typename ObjectWrapper::ObjectType ObjectType; + typedef BluetoothDaemonNotificationRunnable5 SelfType; + + template + static already_AddRefed Create( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), + BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable(new SelfType(aMethod)); + + if (NS_FAILED((runnable->UnpackAndSet(aPDU)))) { + return nullptr; + } + return runnable.forget(); + } + + template + static void + Dispatch(Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5), + BluetoothDaemonPDU& aPDU) + { + nsRefPtr runnable = Create(aMethod, aPDU); + if (!runnable) { + BT_WARNING("BluetoothDaemonNotificationRunnable5::Create failed"); + return; + } + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_FAILED(rv)) { + BT_WARNING("NS_DispatchToMainThread failed: %X", rv); + } + } + + NS_METHOD + Run() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + + ObjectType* obj = ObjectWrapper::GetInstance(); + + if (!obj) { + BT_WARNING("Notification handler not initialized"); + } else { + ((*obj).*mMethod)(mArg1, mArg2, mArg3, mArg4, mArg5); + } + return NS_OK; + } + +private: + BluetoothDaemonNotificationRunnable5( + Res (ObjectType::*aMethod)(Arg1, Arg2, Arg3, Arg4, Arg5)) + : mMethod(aMethod) + { + MOZ_ASSERT(mMethod); + } + + template + nsresult + UnpackAndSet(BluetoothDaemonPDU& aPDU) + { + return UnpackPDU(aPDU, + mArg1, + mArg2, + mArg3, + mArg4, + mArg5); + } + + Res (ObjectType::*mMethod)(Arg1, Arg2, Arg3, Arg4, Arg5); + Tin1 mArg1; + Tin2 mArg2; + Tin3 mArg3; + Tin4 mArg4; + Tin5 mArg5; +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp new file mode 100644 index 000000000000..439fda855787 --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp @@ -0,0 +1,789 @@ +/* -*- 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 "mozilla/unused.h" + +using namespace mozilla::ipc; + +BEGIN_BLUETOOTH_NAMESPACE + +template +struct interface_traits +{ }; + +// +// Protocol initialization and setup +// + +class BluetoothDaemonSetupModule +{ +public: + 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(0x00, 0x01, 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(0x00, 0x02, 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(0x00, 0x03, 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*) = { + [0] = &BluetoothDaemonSetupModule::ErrorRsp, + [1] = &BluetoothDaemonSetupModule::RegisterModuleRsp, + [2] = &BluetoothDaemonSetupModule::UnregisterModuleRsp, + [3] = &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 + BluetoothDaemonInterfaceRunnable0 + ResultRunnable; + + typedef + BluetoothDaemonInterfaceRunnable1 + ErrorRunnable; + + void + ErrorRsp(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, + BluetoothSetupResultHandler* aRes) + { + ErrorRunnable::Dispatch<0x00, 0x00>( + aRes, &BluetoothSetupResultHandler::OnError, aPDU); + } + + void + RegisterModuleRsp(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, + BluetoothSetupResultHandler* aRes) + { + ResultRunnable::Dispatch( + aRes, &BluetoothSetupResultHandler::RegisterModule); + } + + void + UnregisterModuleRsp(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, + BluetoothSetupResultHandler* aRes) + { + ResultRunnable::Dispatch( + aRes, &BluetoothSetupResultHandler::UnregisterModule); + } + + void + ConfigurationRsp(const BluetoothDaemonPDUHeader& aHeader, + BluetoothDaemonPDU& aPDU, + BluetoothSetupResultHandler* aRes) + { + ResultRunnable::Dispatch( + aRes, &BluetoothSetupResultHandler::Configuration); + } +}; + +// +// 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()); + + NS_WARNING(__func__); + // TODO: close channels + + if (mRes) { + mRes->OnError(aStatus); + } + } + + void RegisterModule() MOZ_OVERRIDE + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mInterface->mProtocol); + + NS_WARNING(__func__); + 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(CMD_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(); + 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) +{ + BluetoothDaemonInterfaceRunnable1< + BluetoothResultHandler, void, BluetoothStatus, BluetoothStatus>::Dispatch( + aRes, &BluetoothResultHandler::OnError, aStatus); +} + +BluetoothSocketInterface* +BluetoothDaemonInterface::GetBluetoothSocketInterface() +{ + return nullptr; +} + +BluetoothHandsfreeInterface* +BluetoothDaemonInterface::GetBluetoothHandsfreeInterface() +{ + return nullptr; +} + +BluetoothA2dpInterface* +BluetoothDaemonInterface::GetBluetoothA2dpInterface() +{ + return nullptr; +} + +BluetoothAvrcpInterface* +BluetoothDaemonInterface::GetBluetoothAvrcpInterface() +{ + return nullptr; +} + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h new file mode 100644 index 000000000000..fa2e9e9906c7 --- /dev/null +++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h @@ -0,0 +1,129 @@ +/* -*- 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; + +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/bluetooth/bluedroid/BluetoothDaemonSetupInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonSetupInterface.cpp new file mode 100644 index 000000000000..3b2e4261caf1 --- /dev/null +++ b/dom/bluetooth/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/bluetooth/bluedroid/BluetoothDaemonSetupInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonSetupInterface.h new file mode 100644 index 000000000000..60a659485a32 --- /dev/null +++ b/dom/bluetooth/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/bluetooth/moz.build b/dom/bluetooth/moz.build index a9a30c8f9858..97ba9aa21fa5 100644 --- a/dom/bluetooth/moz.build +++ b/dom/bluetooth/moz.build @@ -48,6 +48,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/BluetoothHALHelpers.cpp', 'bluedroid/BluetoothHALInterface.cpp', 'bluedroid/BluetoothHandsfreeHALInterface.cpp',