diff --git a/dom/bluetooth2/bluedroid/BluetoothGattManager.cpp b/dom/bluetooth2/bluedroid/BluetoothGattManager.cpp new file mode 100644 index 000000000000..423b1b8513e6 --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothGattManager.cpp @@ -0,0 +1,321 @@ +/* -*- 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 "BluetoothGattManager.h" +#include "BluetoothCommon.h" +#include "BluetoothUtils.h" +#include "BluetoothInterface.h" + +#include "mozilla/Services.h" +#include "mozilla/StaticPtr.h" +#include "MainThreadUtils.h" +#include "nsIObserverService.h" +#include "nsThreadUtils.h" + +using namespace mozilla; +USING_BLUETOOTH_NAMESPACE + +namespace { + StaticRefPtr sBluetoothGattManager; + static BluetoothGattInterface* sBluetoothGattInterface; + static BluetoothGattClientInterface* sBluetoothGattClientInterface; +} // anonymous namespace + +bool BluetoothGattManager::mInShutdown = false; + +/* + * Static functions + */ + +BluetoothGattManager* +BluetoothGattManager::Get() +{ + MOZ_ASSERT(NS_IsMainThread()); + + // If sBluetoothGattManager already exists, exit early + if (sBluetoothGattManager) { + return sBluetoothGattManager; + } + + // If we're in shutdown, don't create a new instance + NS_ENSURE_FALSE(mInShutdown, nullptr); + + // Create a new instance, register, and return + BluetoothGattManager* manager = new BluetoothGattManager(); + sBluetoothGattManager = manager; + return sBluetoothGattManager; +} + +class InitGattResultHandler MOZ_FINAL : public BluetoothGattResultHandler +{ +public: + InitGattResultHandler(BluetoothProfileResultHandler* aRes) + : mRes(aRes) + { } + + void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE + { + BT_WARNING("BluetoothGattInterface::Init failed: %d", + (int)aStatus); + if (mRes) { + mRes->OnError(NS_ERROR_FAILURE); + } + } + + void Init() MOZ_OVERRIDE + { + if (mRes) { + mRes->Init(); + } + } + +private: + nsRefPtr mRes; +}; + +// static +void +BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes) +{ + BluetoothInterface* btInf = BluetoothInterface::GetInstance(); + if (!btInf) { + BT_LOGR("Error: Bluetooth interface not available"); + if (aRes) { + aRes->OnError(NS_ERROR_FAILURE); + } + return; + } + + sBluetoothGattInterface = btInf->GetBluetoothGattInterface(); + if (!sBluetoothGattInterface) { + BT_LOGR("Error: Bluetooth GATT interface not available"); + if (aRes) { + aRes->OnError(NS_ERROR_FAILURE); + } + return; + } + + sBluetoothGattClientInterface = + sBluetoothGattInterface->GetBluetoothGattClientInterface(); + NS_ENSURE_TRUE_VOID(sBluetoothGattClientInterface); + + BluetoothGattManager* gattManager = BluetoothGattManager::Get(); + sBluetoothGattInterface->Init(gattManager, + new InitGattResultHandler(aRes)); +} + +class CleanupResultHandler MOZ_FINAL : public BluetoothGattResultHandler +{ +public: + CleanupResultHandler(BluetoothProfileResultHandler* aRes) + : mRes(aRes) + { } + + void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE + { + BT_WARNING("BluetoothGattInterface::Cleanup failed: %d", + (int)aStatus); + if (mRes) { + mRes->OnError(NS_ERROR_FAILURE); + } + } + + void Cleanup() MOZ_OVERRIDE + { + sBluetoothGattClientInterface = nullptr; + sBluetoothGattInterface = nullptr; + if (mRes) { + mRes->Deinit(); + } + } + +private: + nsRefPtr mRes; +}; + +class CleanupResultHandlerRunnable MOZ_FINAL : public nsRunnable +{ +public: + CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes) + : mRes(aRes) + { + MOZ_ASSERT(mRes); + } + + NS_IMETHOD Run() MOZ_OVERRIDE + { + mRes->Deinit(); + return NS_OK; + } + +private: + nsRefPtr mRes; +}; + +// static +void +BluetoothGattManager::DeinitGattInterface(BluetoothProfileResultHandler* aRes) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (sBluetoothGattInterface) { + sBluetoothGattInterface->Cleanup(new CleanupResultHandler(aRes)); + } else if (aRes) { + // We dispatch a runnable here to make the profile resource handler + // behave as if GATT was initialized. + nsRefPtr r = new CleanupResultHandlerRunnable(aRes); + if (NS_FAILED(NS_DispatchToMainThread(r))) { + BT_LOGR("Failed to dispatch cleanup-result-handler runnable"); + } + } +} + +// +// Notification Handlers +// +void +BluetoothGattManager::RegisterClientNotification(int aStatus, + int aClientIf, + const BluetoothUuid& aAppUuid) +{ } + +void +BluetoothGattManager::ScanResultNotification( + const nsAString& aBdAddr, int aRssi, + const BluetoothGattAdvData& aAdvData) +{ } + +void +BluetoothGattManager::ConnectNotification(int aConnId, + int aStatus, + int aClientIf, + const nsAString& aBdAddr) +{ } + +void +BluetoothGattManager::DisconnectNotification(int aConnId, + int aStatus, + int aClientIf, + const nsAString& aBdAddr) +{ } + +void +BluetoothGattManager::SearchCompleteNotification(int aConnId, int aStatus) +{ } + +void +BluetoothGattManager::SearchResultNotification( + int aConnId, const BluetoothGattServiceId& aServiceId) +{ } + +void +BluetoothGattManager::GetCharacteristicNotification( + int aConnId, int aStatus, + const BluetoothGattServiceId& aServiceId, + const BluetoothGattId& aCharId, + int aCharProperty) +{ } + +void +BluetoothGattManager::GetDescriptorNotification( + int aConnId, int aStatus, + const BluetoothGattServiceId& aServiceId, + const BluetoothGattId& aCharId, + const BluetoothGattId& aDescriptorId) +{ } + +void +BluetoothGattManager::GetIncludedServiceNotification( + int aConnId, int aStatus, + const BluetoothGattServiceId& aServiceId, + const BluetoothGattServiceId& aIncludedServId) +{ } + +void +BluetoothGattManager::RegisterNotificationNotification( + int aConnId, int aIsRegister, int aStatus, + const BluetoothGattServiceId& aServiceId, + const BluetoothGattId& aCharId) +{ } + +void +BluetoothGattManager::NotifyNotification( + int aConnId, const BluetoothGattNotifyParam& aNotifyParam) +{ } + +void +BluetoothGattManager::ReadCharacteristicNotification( + int aConnId, int aStatus, const BluetoothGattReadParam& aReadParam) +{ } + +void +BluetoothGattManager::WriteCharacteristicNotification( + int aConnId, int aStatus, const BluetoothGattWriteParam& aWriteParam) +{ } + +void +BluetoothGattManager::ReadDescriptorNotification( + int aConnId, int aStatus, const BluetoothGattReadParam& aReadParam) +{ } + +void +BluetoothGattManager::WriteDescriptorNotification( + int aConnId, int aStatus, const BluetoothGattWriteParam& aWriteParam) +{ } + +void +BluetoothGattManager::ExecuteWriteNotification(int aConnId, int aStatus) +{ } + +void +BluetoothGattManager::ReadRemoteRssiNotification(int aClientIf, + const nsAString& aBdAddr, + int aRssi, + int aStatus) +{ } + +void +BluetoothGattManager::ListenNotification(int aStatus, + int aServerIf) +{ } + +BluetoothGattManager::BluetoothGattManager() +{ } + +BluetoothGattManager::~BluetoothGattManager() +{ + nsCOMPtr obs = services::GetObserverService(); + NS_ENSURE_TRUE_VOID(obs); + if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) { + BT_WARNING("Failed to remove shutdown observer!"); + } +} + +NS_IMETHODIMP +BluetoothGattManager::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) +{ + MOZ_ASSERT(sBluetoothGattManager); + + if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { + HandleShutdown(); + return NS_OK; + } + + MOZ_ASSERT(false, "BluetoothGattManager got unexpected topic!"); + return NS_ERROR_UNEXPECTED; +} + +void +BluetoothGattManager::HandleShutdown() +{ + MOZ_ASSERT(NS_IsMainThread()); + mInShutdown = true; + sBluetoothGattManager = nullptr; +} + +NS_IMPL_ISUPPORTS(BluetoothGattManager, nsIObserver) diff --git a/dom/bluetooth2/bluedroid/BluetoothGattManager.h b/dom/bluetooth2/bluedroid/BluetoothGattManager.h new file mode 100644 index 000000000000..fef3f6bcba0e --- /dev/null +++ b/dom/bluetooth2/bluedroid/BluetoothGattManager.h @@ -0,0 +1,115 @@ +/* -*- 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_bluetoothgattmanager_h__ +#define mozilla_dom_bluetooth_bluetoothgattmanager_h__ + +#include "BluetoothCommon.h" +#include "BluetoothInterface.h" +#include "BluetoothProfileManagerBase.h" + +BEGIN_BLUETOOTH_NAMESPACE +class BluetoothGattManager MOZ_FINAL : public nsIObserver + , public BluetoothGattNotificationHandler +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + static BluetoothGattManager* Get(); + static void InitGattInterface(BluetoothProfileResultHandler* aRes); + static void DeinitGattInterface(BluetoothProfileResultHandler* aRes); + virtual ~BluetoothGattManager(); + +private: + BluetoothGattManager(); + + void HandleShutdown(); + + void RegisterClientNotification(int aStatus, + int aClientIf, + const BluetoothUuid& aAppUuid) MOZ_OVERRIDE; + + void ScanResultNotification( + const nsAString& aBdAddr, int aRssi, + const BluetoothGattAdvData& aAdvData) MOZ_OVERRIDE; + + void ConnectNotification(int aConnId, + int aStatus, + int aClientIf, + const nsAString& aBdAddr) MOZ_OVERRIDE; + + void DisconnectNotification(int aConnId, + int aStatus, + int aClientIf, + const nsAString& aBdAddr) MOZ_OVERRIDE; + + void SearchCompleteNotification(int aConnId, int aStatus) MOZ_OVERRIDE; + + void SearchResultNotification(int aConnId, + const BluetoothGattServiceId& aServiceId) + MOZ_OVERRIDE; + + void GetCharacteristicNotification( + int aConnId, int aStatus, + const BluetoothGattServiceId& aServiceId, + const BluetoothGattId& aCharId, + int aCharProperty) MOZ_OVERRIDE; + + void GetDescriptorNotification( + int aConnId, int aStatus, + const BluetoothGattServiceId& aServiceId, + const BluetoothGattId& aCharId, + const BluetoothGattId& aDescriptorId) MOZ_OVERRIDE; + + void GetIncludedServiceNotification( + int aConnId, int aStatus, + const BluetoothGattServiceId& aServiceId, + const BluetoothGattServiceId& aIncludedServId) MOZ_OVERRIDE; + + void RegisterNotificationNotification( + int aConnId, int aIsRegister, int aStatus, + const BluetoothGattServiceId& aServiceId, + const BluetoothGattId& aCharId) MOZ_OVERRIDE; + + void NotifyNotification(int aConnId, + const BluetoothGattNotifyParam& aNotifyParam) + MOZ_OVERRIDE; + + void ReadCharacteristicNotification(int aConnId, + int aStatus, + const BluetoothGattReadParam& aReadParam) + MOZ_OVERRIDE; + + void WriteCharacteristicNotification( + int aConnId, int aStatus, + const BluetoothGattWriteParam& aWriteParam) MOZ_OVERRIDE; + + void ReadDescriptorNotification(int aConnId, + int aStatus, + const BluetoothGattReadParam& aReadParam) + MOZ_OVERRIDE; + + void WriteDescriptorNotification(int aConnId, + int aStatus, + const BluetoothGattWriteParam& aWriteParam) + MOZ_OVERRIDE; + + void ExecuteWriteNotification(int aConnId, int aStatus) MOZ_OVERRIDE; + + void ReadRemoteRssiNotification(int aClientIf, + const nsAString& aBdAddr, + int aRssi, + int aStatus) MOZ_OVERRIDE; + + void ListenNotification(int aStatus, int aServerIf) MOZ_OVERRIDE; + + static bool mInShutdown; +}; + +END_BLUETOOTH_NAMESPACE + +#endif diff --git a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp index 1475ad419112..27d795751380 100644 --- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp @@ -19,6 +19,7 @@ #include "BluetoothServiceBluedroid.h" #include "BluetoothA2dpManager.h" +#include "BluetoothGattManager.h" #include "BluetoothHfpManager.h" #include "BluetoothOppManager.h" #include "BluetoothProfileController.h" @@ -167,7 +168,8 @@ public: { static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = { BluetoothHfpManager::DeinitHfpInterface, - BluetoothA2dpManager::DeinitA2dpInterface + BluetoothA2dpManager::DeinitA2dpInterface, + BluetoothGattManager::DeinitGattInterface }; MOZ_ASSERT(NS_IsMainThread()); @@ -304,7 +306,8 @@ public: { static void (* const sInitManager[])(BluetoothProfileResultHandler*) = { BluetoothHfpManager::InitHfpInterface, - BluetoothA2dpManager::InitA2dpInterface + BluetoothA2dpManager::InitA2dpInterface, + BluetoothGattManager::InitGattInterface }; MOZ_ASSERT(NS_IsMainThread()); diff --git a/dom/bluetooth2/moz.build b/dom/bluetooth2/moz.build index b90b392240f2..5c0a3e842f80 100644 --- a/dom/bluetooth2/moz.build +++ b/dom/bluetooth2/moz.build @@ -52,6 +52,7 @@ if CONFIG['MOZ_B2G_BT']: 'bluedroid/BluetoothA2dpManager.cpp', 'bluedroid/BluetoothAvrcpHALInterface.cpp', 'bluedroid/BluetoothGattHALInterface.cpp', + 'bluedroid/BluetoothGattManager.cpp', 'bluedroid/BluetoothHALHelpers.cpp', 'bluedroid/BluetoothHALInterface.cpp', 'bluedroid/BluetoothHandsfreeHALInterface.cpp',