diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp index e45aa434a51..8cac5ed4756 100644 --- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp +++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp @@ -1369,9 +1369,10 @@ private: (this->*(HandleNtf[index]))(aHeader, aPDU); } - }; +const int BluetoothDaemonCoreModule::MAX_NUM_CLIENTS = 1; + // // Protocol handling // @@ -1421,8 +1422,6 @@ private: // // - |HandleSvc|, // -const int BluetoothDaemonCoreModule::MAX_NUM_CLIENTS = 1; - // which is called by |BluetoothDaemonProtcol| to hand over received // PDUs into a module. // @@ -1624,65 +1623,6 @@ BluetoothDaemonProtocol::FetchUserData(const BluetoothDaemonPDUHeader& aHeader) return userData; } -// -// Channels -// - -class BluetoothDaemonChannel final : public BluetoothDaemonConnection -{ -public: - BluetoothDaemonChannel(BluetoothDaemonInterface* aInterface, - BluetoothDaemonInterface::Channel aChannel, - BluetoothDaemonPDUConsumer* aConsumer); - - // SocketBase - // - - void OnConnectSuccess() override; - void OnConnectError() override; - void OnDisconnect() override; - -private: - BluetoothDaemonInterface* mInterface; - BluetoothDaemonInterface::Channel mChannel; -}; - -BluetoothDaemonChannel::BluetoothDaemonChannel( - BluetoothDaemonInterface* aInterface, - BluetoothDaemonInterface::Channel aChannel, - BluetoothDaemonPDUConsumer* aConsumer) - : BluetoothDaemonConnection(aConsumer) - , mInterface(aInterface) - , mChannel(aChannel) -{ } - -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); -} - -void -BluetoothDaemonChannel::OnDisconnect() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mInterface); - - mInterface->OnDisconnect(mChannel); -} - // // Interface // @@ -1811,149 +1751,6 @@ private: bool mRegisteredSocketModule; }; -void -BluetoothDaemonInterface::OnConnectSuccess(enum Channel aChannel) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mResultHandlerQ.IsEmpty()); - - switch (aChannel) { - case LISTEN_SOCKET: { - // Init, step 2: Start Bluetooth daemon */ - nsCString value("bluetoothd:-a "); - value.Append(mListenSocketName); - if (NS_WARN_IF(property_set("ctl.start", value.get()) < 0)) { - OnConnectError(CMD_CHANNEL); - } - - /* - * If Bluetooth daemon is not running, retry to start it later. - * - * This condition happens when when we restart Bluetooth daemon - * immediately after it crashed, as the daemon state remains 'stopping' - * instead of 'stopped'. Due to the limitation of property service, - * hereby add delay. See Bug 1143925 Comment 41. - */ - if (!IsDaemonRunning()) { - MessageLoop::current()->PostDelayedTask(FROM_HERE, - new StartDaemonTask(this, value), sRetryInterval); - } - } - break; - case CMD_CHANNEL: - // Init, step 3: Listen for notification channel... - if (!mNtfChannel) { - mNtfChannel = new BluetoothDaemonChannel(this, NTF_CHANNEL, mProtocol); - } else if ( - NS_WARN_IF(mNtfChannel->GetConnectionStatus() == SOCKET_CONNECTED)) { - /* Notification channel should not be open; let's close it. */ - mNtfChannel->Close(); - } - if (NS_FAILED(mListenSocket->Listen(mNtfChannel))) { - OnConnectError(NTF_CHANNEL); - } - break; - case NTF_CHANNEL: { - nsRefPtr res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - - // Init, step 4: Register Core module - nsresult rv = mProtocol->RegisterModuleCmd( - 0x01, 0x00, BluetoothDaemonCoreModule::MAX_NUM_CLIENTS, - 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->Close(); - case CMD_CHANNEL: - // Stop daemon and close listen socket - unused << NS_WARN_IF(property_set("ctl.stop", "bluetoothd")); - mListenSocket->Close(); - case LISTEN_SOCKET: - if (!mResultHandlerQ.IsEmpty()) { - // Signal error to caller - nsRefPtr res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - - if (res) { - DispatchError(res, STATUS_FAIL); - } - } - break; - } -} - -/* - * Three cases for restarting: - * a) during startup - * b) during regular service - * c) during shutdown - * For (a)/(c) cases, mResultHandlerQ contains an element, but case (b) - * mResultHandlerQ shall be empty. The following procedure to recover from crashed - * consists of several steps for case (b). - * 1) Close listen socket. - * 2) Wait for all sockets disconnected and inform BluetoothServiceBluedroid to - * perform the regular stop bluetooth procedure. - * 3) When stop bluetooth procedures complete, fire - * AdapterStateChangedNotification to cleanup all necessary data members and - * deinit ProfileManagers. - * 4) After all resources cleanup, call |StartBluetooth| - */ -void -BluetoothDaemonInterface::OnDisconnect(enum Channel aChannel) -{ - MOZ_ASSERT(NS_IsMainThread()); - - switch (aChannel) { - case CMD_CHANNEL: - // We don't have to do anything here. Step 4 is triggered - // by the daemon. - break; - case NTF_CHANNEL: - // Cleanup, step 4 (Recovery, step 1): Close listen socket - mListenSocket->Close(); - break; - case LISTEN_SOCKET: - if (!mResultHandlerQ.IsEmpty()) { - nsRefPtr res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - // Cleanup, step 5: Signal success to caller - if (res) { - res->Cleanup(); - } - } - break; - } - - /* For recovery make sure all sockets disconnected, in order to avoid - * the remaining disconnects interfere with the restart procedure. - */ - if (sNotificationHandler && mResultHandlerQ.IsEmpty()) { - if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED && - mCmdChannel->GetConnectionStatus() == SOCKET_DISCONNECTED && - mNtfChannel->GetConnectionStatus() == SOCKET_DISCONNECTED) { - // Assume daemon crashed during regular service; notify - // BluetoothServiceBluedroid to prepare restart-daemon procedure - sNotificationHandler->BackendErrorNotification(true); - sNotificationHandler = nullptr; - } - } -} - nsresult BluetoothDaemonInterface::CreateRandomAddressString( const nsACString& aPrefix, unsigned long aPostfixLength, @@ -2052,7 +1849,7 @@ BluetoothDaemonInterface::Init( // Init, step 1: Listen for command channel... */ if (!mCmdChannel) { - mCmdChannel = new BluetoothDaemonChannel(this, CMD_CHANNEL, mProtocol); + mCmdChannel = new BluetoothDaemonConnection(mProtocol, this, CMD_CHANNEL); } else if ( NS_WARN_IF(mCmdChannel->GetConnectionStatus() == SOCKET_CONNECTED)) { // Command channel should not be open; let's close it. @@ -2504,25 +2301,149 @@ BluetoothDaemonInterface::GetBluetoothGattInterface() return nullptr; } -// Methods for |ListenSocketConsumer| -// +// |BluetoothDaemonConnectionConsumer|, |ListenSocketConsumer| void BluetoothDaemonInterface::OnConnectSuccess(int aIndex) { - OnConnectSuccess(static_cast(aIndex)); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mResultHandlerQ.IsEmpty()); + + switch (aIndex) { + case LISTEN_SOCKET: { + // Init, step 2: Start Bluetooth daemon */ + nsCString value("bluetoothd:-a "); + value.Append(mListenSocketName); + if (NS_WARN_IF(property_set("ctl.start", value.get()) < 0)) { + OnConnectError(CMD_CHANNEL); + } + + /* + * If Bluetooth daemon is not running, retry to start it later. + * + * This condition happens when when we restart Bluetooth daemon + * immediately after it crashed, as the daemon state remains 'stopping' + * instead of 'stopped'. Due to the limitation of property service, + * hereby add delay. See Bug 1143925 Comment 41. + */ + if (!IsDaemonRunning()) { + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new StartDaemonTask(this, value), sRetryInterval); + } + } + break; + case CMD_CHANNEL: + // Init, step 3: Listen for notification channel... + if (!mNtfChannel) { + mNtfChannel = new BluetoothDaemonConnection(mProtocol, this, NTF_CHANNEL); + } else if ( + NS_WARN_IF(mNtfChannel->GetConnectionStatus() == SOCKET_CONNECTED)) { + /* Notification channel should not be open; let's close it. */ + mNtfChannel->Close(); + } + if (NS_FAILED(mListenSocket->Listen(mNtfChannel))) { + OnConnectError(NTF_CHANNEL); + } + break; + case NTF_CHANNEL: { + nsRefPtr res = mResultHandlerQ.ElementAt(0); + mResultHandlerQ.RemoveElementAt(0); + + // Init, step 4: Register Core module + nsresult rv = mProtocol->RegisterModuleCmd( + 0x01, 0x00, BluetoothDaemonCoreModule::MAX_NUM_CLIENTS, + new InitResultHandler(this, res)); + if (NS_FAILED(rv) && res) { + DispatchError(res, STATUS_FAIL); + } + } + break; + } } void BluetoothDaemonInterface::OnConnectError(int aIndex) { - OnConnectError(static_cast(aIndex)); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mResultHandlerQ.IsEmpty()); + + switch (aIndex) { + case NTF_CHANNEL: + // Close command channel + mCmdChannel->Close(); + case CMD_CHANNEL: + // Stop daemon and close listen socket + unused << NS_WARN_IF(property_set("ctl.stop", "bluetoothd")); + mListenSocket->Close(); + case LISTEN_SOCKET: + if (!mResultHandlerQ.IsEmpty()) { + // Signal error to caller + nsRefPtr res = mResultHandlerQ.ElementAt(0); + mResultHandlerQ.RemoveElementAt(0); + + if (res) { + DispatchError(res, STATUS_FAIL); + } + } + break; + } } +/* + * Three cases for restarting: + * a) during startup + * b) during regular service + * c) during shutdown + * For (a)/(c) cases, mResultHandlerQ contains an element, but case (b) + * mResultHandlerQ shall be empty. The following procedure to recover from crashed + * consists of several steps for case (b). + * 1) Close listen socket. + * 2) Wait for all sockets disconnected and inform BluetoothServiceBluedroid to + * perform the regular stop bluetooth procedure. + * 3) When stop bluetooth procedures complete, fire + * AdapterStateChangedNotification to cleanup all necessary data members and + * deinit ProfileManagers. + * 4) After all resources cleanup, call |StartBluetooth| + */ void BluetoothDaemonInterface::OnDisconnect(int aIndex) { - OnDisconnect(static_cast(aIndex)); + MOZ_ASSERT(NS_IsMainThread()); + + switch (aIndex) { + case CMD_CHANNEL: + // We don't have to do anything here. Step 4 is triggered + // by the daemon. + break; + case NTF_CHANNEL: + // Cleanup, step 4 (Recovery, step 1): Close listen socket + mListenSocket->Close(); + break; + case LISTEN_SOCKET: + if (!mResultHandlerQ.IsEmpty()) { + nsRefPtr res = mResultHandlerQ.ElementAt(0); + mResultHandlerQ.RemoveElementAt(0); + // Cleanup, step 5: Signal success to caller + if (res) { + res->Cleanup(); + } + } + break; + } + + /* For recovery make sure all sockets disconnected, in order to avoid + * the remaining disconnects interfere with the restart procedure. + */ + if (sNotificationHandler && mResultHandlerQ.IsEmpty()) { + if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED && + mCmdChannel->GetConnectionStatus() == SOCKET_DISCONNECTED && + mNtfChannel->GetConnectionStatus() == SOCKET_DISCONNECTED) { + // Assume daemon crashed during regular service; notify + // BluetoothServiceBluedroid to prepare restart-daemon procedure + sNotificationHandler->BackendErrorNotification(true); + sNotificationHandler = nullptr; + } + } } END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h index a168deac763..81431660cbd 100644 --- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h +++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h @@ -8,11 +8,13 @@ #define mozilla_dom_bluetooth_bluedroid_bluetoothdaemoninterface_h__ #include "BluetoothInterface.h" +#include "mozilla/ipc/BluetoothDaemonConnectionConsumer.h" #include "mozilla/ipc/ListenSocketConsumer.h" namespace mozilla { namespace ipc { +class BluetoothDaemonConnection; class ListenSocket; } @@ -20,7 +22,6 @@ class ListenSocket; BEGIN_BLUETOOTH_NAMESPACE -class BluetoothDaemonChannel; class BluetoothDaemonA2dpInterface; class BluetoothDaemonAvrcpInterface; class BluetoothDaemonHandsfreeInterface; @@ -29,6 +30,7 @@ class BluetoothDaemonSocketInterface; class BluetoothDaemonInterface final : public BluetoothInterface + , public mozilla::ipc::BluetoothDaemonConnectionConsumer , public mozilla::ipc::ListenSocketConsumer { public: @@ -36,8 +38,6 @@ public: class InitResultHandler; class StartDaemonTask; - friend class BluetoothDaemonListenSocket; - friend class BluetoothDaemonChannel; friend class CleanupResultHandler; friend class InitResultHandler; friend class StartDaemonTask; @@ -138,15 +138,11 @@ protected: BluetoothDaemonInterface(); ~BluetoothDaemonInterface(); - void OnConnectSuccess(enum Channel aChannel); - void OnConnectError(enum Channel aChannel); - void OnDisconnect(enum Channel aChannel); - nsresult CreateRandomAddressString(const nsACString& aPrefix, unsigned long aPostfixLength, nsACString& aAddress); - // Methods for |ListenSocketConsumer| + // Methods for |BluetoothDaemonConnectionConsumer| and |ListenSocketConsumer| // void OnConnectSuccess(int aIndex) override; @@ -159,8 +155,8 @@ private: nsCString mListenSocketName; nsRefPtr mListenSocket; - nsRefPtr mCmdChannel; - nsRefPtr mNtfChannel; + nsRefPtr mCmdChannel; + nsRefPtr mNtfChannel; nsAutoPtr mProtocol; nsTArray > mResultHandlerQ; diff --git a/ipc/bluetooth/BluetoothDaemonConnection.cpp b/ipc/bluetooth/BluetoothDaemonConnection.cpp index d5cfac94444..c385bb2a490 100644 --- a/ipc/bluetooth/BluetoothDaemonConnection.cpp +++ b/ipc/bluetooth/BluetoothDaemonConnection.cpp @@ -10,6 +10,7 @@ #include #include #include +#include "mozilla/ipc/BluetoothDaemonConnectionConsumer.h" #include "mozilla/ipc/DataSocket.h" #include "mozilla/ipc/UnixSocketConnector.h" #include "mozilla/ipc/UnixSocketWatcher.h" @@ -433,8 +434,12 @@ BluetoothDaemonConnectionIO::ShutdownOnIOThread() // BluetoothDaemonConnection::BluetoothDaemonConnection( - BluetoothDaemonPDUConsumer* aConsumer) - : mConsumer(aConsumer) + BluetoothDaemonPDUConsumer* aPDUConsumer, + BluetoothDaemonConnectionConsumer* aConsumer, + int aIndex) + : mPDUConsumer(aPDUConsumer) + , mConsumer(aConsumer) + , mIndex(aIndex) , mIO(nullptr) { MOZ_ASSERT(mConsumer); @@ -461,7 +466,7 @@ BluetoothDaemonConnection::PrepareAccept(UnixSocketConnector* aConnector, mIO = new BluetoothDaemonConnectionIO( XRE_GetIOMessageLoop(), -1, UnixSocketWatcher::SOCKET_IS_CONNECTING, - this, mConsumer); + this, mPDUConsumer); aIO = mIO; return NS_OK; @@ -500,5 +505,29 @@ BluetoothDaemonConnection::Close() NotifyDisconnect(); } +void +BluetoothDaemonConnection::OnConnectSuccess() +{ + MOZ_ASSERT(NS_IsMainThread()); + + mConsumer->OnConnectSuccess(mIndex); +} + +void +BluetoothDaemonConnection::OnConnectError() +{ + MOZ_ASSERT(NS_IsMainThread()); + + mConsumer->OnConnectError(mIndex); +} + +void +BluetoothDaemonConnection::OnDisconnect() +{ + MOZ_ASSERT(NS_IsMainThread()); + + mConsumer->OnDisconnect(mIndex); +} + } } diff --git a/ipc/bluetooth/BluetoothDaemonConnection.h b/ipc/bluetooth/BluetoothDaemonConnection.h index 8f253bd62e6..afc935c3da5 100644 --- a/ipc/bluetooth/BluetoothDaemonConnection.h +++ b/ipc/bluetooth/BluetoothDaemonConnection.h @@ -15,6 +15,7 @@ namespace mozilla { namespace ipc { +class BluetoothDaemonConnectionConsumer; class BluetoothDaemonConnectionIO; class BluetoothDaemonPDUConsumer; @@ -113,7 +114,9 @@ protected: class BluetoothDaemonConnection : public ConnectionOrientedSocket { public: - BluetoothDaemonConnection(BluetoothDaemonPDUConsumer* aConsumer); + BluetoothDaemonConnection(BluetoothDaemonPDUConsumer* aPDUConsumer, + BluetoothDaemonConnectionConsumer* aConsumer, + int aIndex); virtual ~BluetoothDaemonConnection(); // Methods for |ConnectionOrientedSocket| @@ -131,9 +134,14 @@ public: // void Close() override; + void OnConnectSuccess() override; + void OnConnectError() override; + void OnDisconnect() override; private: - BluetoothDaemonPDUConsumer* mConsumer; + BluetoothDaemonPDUConsumer* mPDUConsumer; + BluetoothDaemonConnectionConsumer* mConsumer; + int mIndex; BluetoothDaemonConnectionIO* mIO; };