From 9b1bbedfbc8edf66ce2eaa079304eefd036ef85d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 22 Jul 2014 13:53:27 +0200 Subject: [PATCH] Bug 1038645: Asynchronous starting and stopping of profile managers (under bluetooth2/), r=btian Profile managers use the new class |BluetoothProfileResultHandler| to signal the result of initializing of cleaning up operations to |BluetoothServiceBluedroid|. |BluetoothServiceBluedroid| proceeds once all profile handlers have finished. Future patches will build upon this patch to create completely asynchronous profile managers. --- dom/bluetooth2/BluetoothProfileManagerBase.h | 12 +++ .../bluedroid/BluetoothA2dpManager.cpp | 35 +++++- .../bluedroid/BluetoothA2dpManager.h | 4 +- .../bluedroid/BluetoothServiceBluedroid.cpp | 102 ++++++++++++++++-- .../bluedroid/hfp/BluetoothHfpManager.cpp | 36 +++++-- .../bluedroid/hfp/BluetoothHfpManager.h | 4 +- 6 files changed, 172 insertions(+), 21 deletions(-) diff --git a/dom/bluetooth2/BluetoothProfileManagerBase.h b/dom/bluetooth2/BluetoothProfileManagerBase.h index d053beaa027..c63b7dfbe31 100644 --- a/dom/bluetooth2/BluetoothProfileManagerBase.h +++ b/dom/bluetooth2/BluetoothProfileManagerBase.h @@ -28,6 +28,18 @@ BEGIN_BLUETOOTH_NAMESPACE class BluetoothProfileController; +class BluetoothProfileResultHandler +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothProfileResultHandler); + + virtual ~BluetoothProfileResultHandler() { } + + virtual void OnError(nsresult aResult) { } + virtual void Init() { } + virtual void Deinit() { } +}; + class BluetoothProfileManagerBase : public nsIObserver { public: diff --git a/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp b/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp index 61660844a0a..1ccc890cc0d 100644 --- a/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp @@ -500,13 +500,25 @@ static btrc_callbacks_t sBtAvrcpCallbacks = { */ // static void -BluetoothA2dpManager::InitA2dpInterface() +BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes) { BluetoothInterface* btInf = BluetoothInterface::GetInstance(); - NS_ENSURE_TRUE_VOID(btInf); + if (!btInf) { + BT_LOGR("Error: Bluetooth interface not available"); + if (aRes) { + aRes->OnError(NS_ERROR_FAILURE); + } + return; + } sBtA2dpInterface = btInf->GetBluetoothA2dpInterface(); - NS_ENSURE_TRUE_VOID(sBtA2dpInterface); + if (!sBtA2dpInterface) { + BT_LOGR("Error: Bluetooth A2DP interface not available"); + if (aRes) { + aRes->OnError(NS_ERROR_FAILURE); + } + return; + } int ret = sBtA2dpInterface->Init(&sBtA2dpCallbacks); if (ret != BT_STATUS_SUCCESS) { @@ -515,13 +527,23 @@ BluetoothA2dpManager::InitA2dpInterface() #if ANDROID_VERSION > 17 sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface(); - NS_ENSURE_TRUE_VOID(sBtAvrcpInterface); + if (!sBtAvrcpInterface) { + BT_LOGR("Error: Bluetooth AVRCP interface not available"); + if (aRes) { + aRes->OnError(NS_ERROR_FAILURE); + } + return; + } ret = sBtAvrcpInterface->Init(&sBtAvrcpCallbacks); if (ret != BT_STATUS_SUCCESS) { BT_LOGR("Warning: failed to init avrcp module"); } #endif + + if (aRes) { + aRes->Init(); + } } BluetoothA2dpManager::~BluetoothA2dpManager() @@ -597,7 +619,7 @@ BluetoothA2dpManager::Get() // static void -BluetoothA2dpManager::DeinitA2dpInterface() +BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes) { MOZ_ASSERT(NS_IsMainThread()); @@ -611,6 +633,9 @@ BluetoothA2dpManager::DeinitA2dpInterface() sBtAvrcpInterface = nullptr; } #endif + if (aRes) { + aRes->Deinit(); + } } void diff --git a/dom/bluetooth2/bluedroid/BluetoothA2dpManager.h b/dom/bluetooth2/bluedroid/BluetoothA2dpManager.h index 7e6a34b5b36..9f7a01daeb2 100644 --- a/dom/bluetooth2/bluedroid/BluetoothA2dpManager.h +++ b/dom/bluetooth2/bluedroid/BluetoothA2dpManager.h @@ -30,8 +30,8 @@ public: }; static BluetoothA2dpManager* Get(); - static void InitA2dpInterface(); - static void DeinitA2dpInterface(); + static void InitA2dpInterface(BluetoothProfileResultHandler* aRes); + static void DeinitA2dpInterface(BluetoothProfileResultHandler* aRes); virtual ~BluetoothA2dpManager(); // A2DP-specific functions diff --git a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp index 9f08db60041..fbf0d684ad5 100644 --- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp @@ -152,12 +152,54 @@ public: } }; +/* |ProfileDeinitResultHandler| collects the results of all profile + * result handlers and calls |Proceed| after all results handlers + * have been run. + */ +class ProfileDeinitResultHandler MOZ_FINAL +: public BluetoothProfileResultHandler +{ +public: + ProfileDeinitResultHandler(unsigned char aNumProfiles) + : mNumProfiles(aNumProfiles) + { + MOZ_ASSERT(mNumProfiles); + } + + void Deinit() MOZ_OVERRIDE + { + if (!(--mNumProfiles)) { + Proceed(); + } + } + + void OnError(nsresult aResult) MOZ_OVERRIDE + { + if (!(--mNumProfiles)) { + Proceed(); + } + } + +private: + void Proceed() const + { + sBtInterface->Cleanup(nullptr); + } + + unsigned char mNumProfiles; +}; + class CleanupTask MOZ_FINAL : public nsRunnable { public: NS_IMETHOD Run() { + static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = { + BluetoothHfpManager::DeinitHfpInterface, + BluetoothA2dpManager::DeinitA2dpInterface + }; + MOZ_ASSERT(NS_IsMainThread()); // Return error if BluetoothService is unavailable @@ -185,9 +227,12 @@ public: bs->DistributeSignal(signal); // Cleanup bluetooth interfaces after BT state becomes BT_STATE_OFF. - BluetoothHfpManager::DeinitHfpInterface(); - BluetoothA2dpManager::DeinitA2dpInterface(); - sBtInterface->Cleanup(nullptr); + nsRefPtr res = + new ProfileDeinitResultHandler(MOZ_ARRAY_LENGTH(sDeinitManager)); + + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sDeinitManager); ++i) { + sDeinitManager[i](res); + } return NS_OK; } @@ -765,19 +810,64 @@ public: } }; +/* |ProfileInitResultHandler| collects the results of all profile + * result handlers and calls |Proceed| after all results handlers + * have been run. + */ +class ProfileInitResultHandler MOZ_FINAL +: public BluetoothProfileResultHandler +{ +public: + ProfileInitResultHandler(unsigned char aNumProfiles) + : mNumProfiles(aNumProfiles) + { + MOZ_ASSERT(mNumProfiles); + } + + void Init() MOZ_OVERRIDE + { + if (!(--mNumProfiles)) { + Proceed(); + } + } + + void OnError(nsresult aResult) MOZ_OVERRIDE + { + if (!(--mNumProfiles)) { + Proceed(); + } + } + +private: + void Proceed() const + { + sBtInterface->Enable(new EnableResultHandler()); + } + + unsigned char mNumProfiles; +}; + class InitResultHandler MOZ_FINAL : public BluetoothResultHandler { public: void Init() MOZ_OVERRIDE { + static void (* const sInitManager[])(BluetoothProfileResultHandler*) = { + BluetoothHfpManager::InitHfpInterface, + BluetoothA2dpManager::InitA2dpInterface + }; + MOZ_ASSERT(NS_IsMainThread()); // Register all the bluedroid callbacks before enable() get called // It is required to register a2dp callbacks before a2dp media task starts up. // If any interface cannot be initialized, turn on bluetooth core anyway. - BluetoothHfpManager::InitHfpInterface(); - BluetoothA2dpManager::InitA2dpInterface(); - sBtInterface->Enable(new EnableResultHandler()); + nsRefPtr res = + new ProfileInitResultHandler(MOZ_ARRAY_LENGTH(sInitManager)); + + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sInitManager); ++i) { + sInitManager[i](res); + } } void OnError(int aStatus) MOZ_OVERRIDE diff --git a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp index 1df4bd64705..855d09b0818 100644 --- a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp +++ b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp @@ -430,10 +430,16 @@ BluetoothHfpManager::Init() // static void -BluetoothHfpManager::InitHfpInterface() +BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes) { BluetoothInterface* btInf = BluetoothInterface::GetInstance(); - NS_ENSURE_TRUE_VOID(btInf); + if (!btInf) { + BT_LOGR("Error: Bluetooth interface not available"); + if (aRes) { + aRes->OnError(NS_ERROR_FAILURE); + } + return; + } if (sBluetoothHfpInterface) { sBluetoothHfpInterface->Cleanup(); @@ -442,11 +448,26 @@ BluetoothHfpManager::InitHfpInterface() BluetoothHandsfreeInterface *interface = btInf->GetBluetoothHandsfreeInterface(); - NS_ENSURE_TRUE_VOID(interface); + if (!interface) { + BT_LOGR("Error: Bluetooth Handsfree interface not available"); + if (aRes) { + aRes->OnError(NS_ERROR_FAILURE); + } + return; + } + + if (interface->Init(&sBluetoothHfpCallbacks) != BT_STATUS_SUCCESS) { + if (aRes) { + aRes->OnError(NS_ERROR_FAILURE); + } + return; + } - NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS == - interface->Init(&sBluetoothHfpCallbacks)); sBluetoothHfpInterface = interface; + + if (aRes) { + aRes->Init(); + } } BluetoothHfpManager::~BluetoothHfpManager() @@ -469,12 +490,15 @@ BluetoothHfpManager::~BluetoothHfpManager() // static void -BluetoothHfpManager::DeinitHfpInterface() +BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes) { if (sBluetoothHfpInterface) { sBluetoothHfpInterface->Cleanup(); sBluetoothHfpInterface = nullptr; } + if (aRes) { + aRes->Deinit(); + } } //static diff --git a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.h b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.h index 37ac6f16e0c..015b64c9ea5 100644 --- a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.h +++ b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.h @@ -82,8 +82,8 @@ public: static BluetoothHfpManager* Get(); virtual ~BluetoothHfpManager(); - static void InitHfpInterface(); - static void DeinitHfpInterface(); + static void InitHfpInterface(BluetoothProfileResultHandler* aRes); + static void DeinitHfpInterface(BluetoothProfileResultHandler* aRes); bool ConnectSco(); bool DisconnectSco();