From a81cf1b3e62c3260e4e640cdb25c7b468fa7e6b0 Mon Sep 17 00:00:00 2001 From: Jocelyn Liu Date: Fri, 21 Aug 2015 17:11:14 +0800 Subject: [PATCH] Bug 1181480 - Add and implement GATT server connection related Web APIs. r=btian, r=mrbkap --- .../BluetoothDaemonGattInterface.cpp | 2 +- .../bluedroid/BluetoothGattManager.cpp | 472 +++++++++++++++++- .../bluedroid/BluetoothGattManager.h | 27 + .../bluedroid/BluetoothServiceBluedroid.cpp | 45 ++ .../bluedroid/BluetoothServiceBluedroid.h | 16 + .../bluetooth2/BluetoothDiscoveryHandle.cpp | 1 - dom/bluetooth/bluetooth2/BluetoothGatt.cpp | 1 - .../bluetooth2/BluetoothGattServer.cpp | 149 +++++- .../bluetooth2/BluetoothGattServer.h | 38 +- dom/bluetooth/bluetooth2/BluetoothService.h | 19 + .../bluetooth2/ipc/BluetoothParent.cpp | 50 ++ .../bluetooth2/ipc/BluetoothParent.h | 9 + .../ipc/BluetoothServiceChildProcess.cpp | 29 ++ .../ipc/BluetoothServiceChildProcess.h | 16 + dom/bluetooth/bluetooth2/ipc/PBluetooth.ipdl | 20 + dom/bluetooth/bluez/BluetoothDBusService.cpp | 20 + dom/bluetooth/bluez/BluetoothDBusService.h | 16 + dom/webidl/BluetoothGattServer.webidl | 16 +- 18 files changed, 897 insertions(+), 49 deletions(-) diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp index 7a1d41003563..105f9f7f73e0 100644 --- a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp +++ b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp @@ -1847,7 +1847,7 @@ public: return rv; } /* Read connected */ - rv = UnpackPDU(pdu, aArg3); + rv = UnpackPDU(pdu, UnpackConversion(aArg3)); if (NS_FAILED(rv)) { return rv; } diff --git a/dom/bluetooth/bluedroid/BluetoothGattManager.cpp b/dom/bluetooth/bluedroid/BluetoothGattManager.cpp index cb87a60a4a24..187bfdaa73bd 100644 --- a/dom/bluetooth/bluedroid/BluetoothGattManager.cpp +++ b/dom/bluetooth/bluedroid/BluetoothGattManager.cpp @@ -14,14 +14,15 @@ #include "mozilla/dom/bluetooth/BluetoothCommon.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" +#include "nsDataHashtable.h" #include "nsIObserverService.h" #include "nsThreadUtils.h" -#define ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(runnable) \ +#define ENSURE_GATT_INTF_IS_READY_VOID(runnable) \ do { \ if (!sBluetoothGattInterface) { \ DispatchReplyError(runnable, \ - NS_LITERAL_STRING("BluetoothGattClientInterface is not ready")); \ + NS_LITERAL_STRING("BluetoothGattInterface is not ready")); \ return; \ } \ } while(0) @@ -29,6 +30,8 @@ using namespace mozilla; USING_BLUETOOTH_NAMESPACE +class BluetoothGattServer; + namespace { StaticRefPtr sBluetoothGattManager; static BluetoothGattInterface* sBluetoothGattInterface; @@ -37,6 +40,7 @@ namespace { bool BluetoothGattManager::mInShutdown = false; static StaticAutoPtr > > sClients; +static StaticAutoPtr > > sServers; struct BluetoothGattClientReadCharState { @@ -202,6 +206,32 @@ private: NS_IMPL_ISUPPORTS0(BluetoothGattClient) +class BluetoothGattServer final : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + BluetoothGattServer(const nsAString& aAppUuid) + : mAppUuid(aAppUuid) + , mServerIf(0) + { } + + nsString mAppUuid; + int mServerIf; + + nsRefPtr mConnectPeripheralRunnable; + nsRefPtr mDisconnectPeripheralRunnable; + nsRefPtr mUnregisterServerRunnable; + + // Map connection id from device address + nsDataHashtable mConnectionMap; +private: + ~BluetoothGattServer() + { } +}; + +NS_IMPL_ISUPPORTS0(BluetoothGattServer) + class UuidComparator { public: @@ -210,9 +240,15 @@ public: { return aClient->mAppUuid.Equals(aAppUuid); } + + bool Equals(const nsRefPtr& aServer, + const nsAString& aAppUuid) const + { + return aServer->mAppUuid.Equals(aAppUuid); + } }; -class ClientIfComparator +class InterfaceIdComparator { public: bool Equals(const nsRefPtr& aClient, @@ -220,6 +256,12 @@ public: { return aClient->mClientIf == aClientIf; } + + bool Equals(const nsRefPtr& aServer, + int aServerIf) const + { + return aServer->mServerIf == aServerIf; + } }; class ConnIdComparator @@ -305,6 +347,10 @@ BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes) sClients = new nsTArray >; } + if (!sServers) { + sServers = new nsTArray >; + } + BluetoothGattManager* gattManager = BluetoothGattManager::Get(); sBluetoothGattInterface->Init(gattManager, new InitGattResultHandler(aRes)); @@ -331,6 +377,7 @@ public: { sBluetoothGattInterface = nullptr; sClients = nullptr; + sServers = nullptr; if (mRes) { mRes->Deinit(); @@ -434,10 +481,8 @@ public: NS_ENSURE_TRUE_VOID(bs); // Notify BluetoothGatt to clear the clientIf - bs->DistributeSignal( - NS_LITERAL_STRING("ClientUnregistered"), - mClient->mAppUuid, - BluetoothValue(true)); + bs->DistributeSignal(NS_LITERAL_STRING("ClientUnregistered"), + mClient->mAppUuid); // Resolve the unregister request DispatchReplySuccess(mClient->mUnregisterClientRunnable); @@ -469,10 +514,10 @@ BluetoothGattManager::UnregisterClient(int aClientIf, MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aClientIf, 0 /* Start */, - ClientIfComparator()); + InterfaceIdComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { DispatchReplyError(aRunnable, STATUS_PARM_INVALID); return; @@ -569,7 +614,7 @@ BluetoothGattManager::StartLeScan(const nsTArray& aServiceUuids, MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); nsString appUuidStr; GenerateUuid(appUuidStr); @@ -603,7 +648,7 @@ BluetoothGattManager::StopLeScan(const nsAString& aScanUuid, MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aScanUuid, 0 /* Start */, UuidComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { @@ -662,7 +707,7 @@ BluetoothGattManager::Connect(const nsAString& aAppUuid, MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); if (index == sClients->NoIndex) { @@ -732,7 +777,7 @@ BluetoothGattManager::Disconnect(const nsAString& aAppUuid, MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { @@ -779,7 +824,7 @@ BluetoothGattManager::Discover(const nsAString& aAppUuid, MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { @@ -850,10 +895,10 @@ BluetoothGattManager::ReadRemoteRssi(int aClientIf, MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aClientIf, 0 /* Start */, - ClientIfComparator()); + InterfaceIdComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { DispatchReplyError(aRunnable, STATUS_PARM_INVALID); return; @@ -918,7 +963,7 @@ BluetoothGattManager::RegisterNotifications( MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { @@ -994,7 +1039,7 @@ BluetoothGattManager::DeregisterNotifications( MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { @@ -1057,7 +1102,7 @@ BluetoothGattManager::ReadCharacteristicValue( MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { @@ -1137,7 +1182,7 @@ BluetoothGattManager::WriteCharacteristicValue( MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { @@ -1219,7 +1264,7 @@ BluetoothGattManager::ReadDescriptorValue( MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { @@ -1300,7 +1345,7 @@ BluetoothGattManager::WriteDescriptorValue( MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); - ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); if (NS_WARN_IF(index == sClients->NoIndex)) { @@ -1342,6 +1387,278 @@ BluetoothGattManager::WriteDescriptorValue( new WriteDescriptorValueResultHandler(client)); } +class BluetoothGattManager::RegisterServerResultHandler final + : public BluetoothGattResultHandler +{ +public: + RegisterServerResultHandler(BluetoothGattServer* aServer) + : mServer(aServer) + { + MOZ_ASSERT(mServer); + } + + void OnError(BluetoothStatus aStatus) override + { + BT_WARNING("BluetoothGattServerInterface::RegisterServer failed: %d", + (int)aStatus); + + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + + // Reject the connect request + if (mServer->mConnectPeripheralRunnable) { + DispatchReplyError(mServer->mConnectPeripheralRunnable, + NS_LITERAL_STRING("Register GATT server failed")); + mServer->mConnectPeripheralRunnable = nullptr; + } + + sServers->RemoveElement(mServer); + } + +private: + nsRefPtr mServer; +}; + +class BluetoothGattManager::ConnectPeripheralResultHandler final + : public BluetoothGattResultHandler +{ +public: + ConnectPeripheralResultHandler(BluetoothGattServer* aServer, + const nsAString& aDeviceAddr) + : mServer(aServer) + , mDeviceAddr(aDeviceAddr) + { + MOZ_ASSERT(mServer); + MOZ_ASSERT(!mDeviceAddr.IsEmpty()); + } + + void OnError(BluetoothStatus aStatus) override + { + BT_WARNING("BluetoothGattServerInterface::ConnectPeripheral failed: %d", + (int)aStatus); + MOZ_ASSERT(mServer->mConnectPeripheralRunnable); + + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + + DispatchReplyError(mServer->mConnectPeripheralRunnable, + NS_LITERAL_STRING("ConnectPeripheral failed")); + mServer->mConnectPeripheralRunnable = nullptr; + mServer->mConnectionMap.Remove(mDeviceAddr); + } + +private: + nsRefPtr mServer; + nsString mDeviceAddr; +}; + +void +BluetoothGattManager::ConnectPeripheral( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRunnable); + + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); + + size_t index = sServers->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); + if (index == sServers->NoIndex) { + index = sServers->Length(); + sServers->AppendElement(new BluetoothGattServer(aAppUuid)); + } + nsRefPtr server = (*sServers)[index]; + + /** + * Early resolve or reject the request based on the current status before + * sending a request to bluetooth stack. + * + * case 1) Connecting/Disconnecting: If connect/disconnect peripheral + * runnable exists, reject the request since the local GATT server is + * busy connecting or disconnecting to a device. + * case 2) Connected: If there is an entry whose key is |aAddress| in the + * connection map, resolve the request. Since disconnected devices + * will not be in the map, all entries in the map are connected + * devices. + */ + if (server->mConnectPeripheralRunnable || + server->mDisconnectPeripheralRunnable) { + DispatchReplyError(aRunnable, STATUS_BUSY); + return; + } + + int connId = 0; + if (server->mConnectionMap.Get(aAddress, &connId)) { + MOZ_ASSERT(connId > 0); + DispatchReplySuccess(aRunnable); + return; + } + + server->mConnectionMap.Put(aAddress, 0); + server->mConnectPeripheralRunnable = aRunnable; + + if (server->mServerIf > 0) { + sBluetoothGattInterface->ConnectPeripheral( + server->mServerIf, + aAddress, + true, // direct connect + TRANSPORT_AUTO, + new ConnectPeripheralResultHandler(server, aAddress)); + } else { + BluetoothUuid uuid; + StringToUuid(NS_ConvertUTF16toUTF8(aAppUuid).get(), uuid); + + // connect will be proceeded after server registered + sBluetoothGattInterface->RegisterServer( + uuid, new RegisterServerResultHandler(server)); + } +} + +class BluetoothGattManager::DisconnectPeripheralResultHandler final + : public BluetoothGattResultHandler +{ +public: + DisconnectPeripheralResultHandler(BluetoothGattServer* aServer) + : mServer(aServer) + { + MOZ_ASSERT(mServer); + } + + void OnError(BluetoothStatus aStatus) override + { + BT_WARNING("BluetoothGattServerInterface::DisconnectPeripheral failed: %d", + (int)aStatus); + MOZ_ASSERT(mServer->mDisconnectPeripheralRunnable); + + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + + // Reject the disconnect request + DispatchReplyError(mServer->mDisconnectPeripheralRunnable, + NS_LITERAL_STRING("DisconnectPeripheral failed")); + mServer->mDisconnectPeripheralRunnable = nullptr; + } + +private: + nsRefPtr mServer; +}; + +void +BluetoothGattManager::DisconnectPeripheral( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRunnable); + + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); + + size_t index = sServers->IndexOf(aAppUuid, 0 /* Start */, UuidComparator()); + if (NS_WARN_IF(index == sServers->NoIndex)) { + DispatchReplyError(aRunnable, STATUS_PARM_INVALID); + return; + } + nsRefPtr server = (*sServers)[index]; + + if (NS_WARN_IF(server->mServerIf <= 0)) { + DispatchReplyError(aRunnable, + NS_LITERAL_STRING("Disconnect failed")); + return; + } + + // Reject the request if there is an ongoing connect/disconnect request. + if (server->mConnectPeripheralRunnable || + server->mDisconnectPeripheralRunnable) { + DispatchReplyError(aRunnable, STATUS_BUSY); + return; + } + + // Resolve the request if the device is not connected. + int connId = 0; + if (!server->mConnectionMap.Get(aAddress, &connId)) { + DispatchReplySuccess(aRunnable); + return; + } + + server->mDisconnectPeripheralRunnable = aRunnable; + + sBluetoothGattInterface->DisconnectPeripheral( + server->mServerIf, + aAddress, + connId, + new DisconnectPeripheralResultHandler(server)); +} + +class BluetoothGattManager::UnregisterServerResultHandler final + : public BluetoothGattResultHandler +{ +public: + UnregisterServerResultHandler(BluetoothGattServer* aServer) + : mServer(aServer) + { + MOZ_ASSERT(mServer); + } + + void UnregisterServer() override + { + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + + // Notify BluetoothGattServer to clear the serverIf + bs->DistributeSignal(NS_LITERAL_STRING("ServerUnregistered"), + mServer->mAppUuid); + + // Resolve the unregister request + if (mServer->mUnregisterServerRunnable) { + DispatchReplySuccess(mServer->mUnregisterServerRunnable); + mServer->mUnregisterServerRunnable = nullptr; + } + + sServers->RemoveElement(mServer); + } + + void OnError(BluetoothStatus aStatus) override + { + BT_WARNING("BluetoothGattServerInterface::UnregisterServer failed: %d", + (int)aStatus); + + // Reject the unregister request + if (mServer->mUnregisterServerRunnable) { + DispatchReplyError(mServer->mUnregisterServerRunnable, + NS_LITERAL_STRING("Unregister GATT Server failed")); + mServer->mUnregisterServerRunnable = nullptr; + } + } + +private: + nsRefPtr mServer; +}; + +void +BluetoothGattManager::UnregisterServer(int aServerIf, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + + ENSURE_GATT_INTF_IS_READY_VOID(aRunnable); + + size_t index = sServers->IndexOf(aServerIf, 0 /* Start */, + InterfaceIdComparator()); + if (NS_WARN_IF(index == sServers->NoIndex)) { + DispatchReplyError(aRunnable, STATUS_PARM_INVALID); + return; + } + + nsRefPtr server = (*sServers)[index]; + server->mUnregisterServerRunnable = aRunnable; + + sBluetoothGattInterface->UnregisterServer( + aServerIf, + new UnregisterServerResultHandler(server)); +} + // // Notification Handlers // @@ -1486,7 +1803,7 @@ BluetoothGattManager::ConnectNotification(int aConnId, NS_ENSURE_TRUE_VOID(bs); size_t index = sClients->IndexOf(aClientIf, 0 /* Start */, - ClientIfComparator()); + InterfaceIdComparator()); NS_ENSURE_TRUE_VOID(index != sClients->NoIndex); nsRefPtr client = sClients->ElementAt(index); @@ -1538,7 +1855,7 @@ BluetoothGattManager::DisconnectNotification(int aConnId, NS_ENSURE_TRUE_VOID(bs); size_t index = sClients->IndexOf(aClientIf, 0 /* Start */, - ClientIfComparator()); + InterfaceIdComparator()); NS_ENSURE_TRUE_VOID(index != sClients->NoIndex); nsRefPtr client = sClients->ElementAt(index); @@ -2064,7 +2381,7 @@ BluetoothGattManager::ReadRemoteRssiNotification(int aClientIf, NS_ENSURE_TRUE_VOID(bs); size_t index = sClients->IndexOf(aClientIf, 0 /* Start */, - ClientIfComparator()); + InterfaceIdComparator()); NS_ENSURE_TRUE_VOID(index != sClients->NoIndex); nsRefPtr client = sClients->ElementAt(index); @@ -2097,6 +2414,110 @@ BluetoothGattManager::ListenNotification(BluetoothGattStatus aStatus, int aServerIf) { } +void +BluetoothGattManager::RegisterServerNotification(BluetoothGattStatus aStatus, + int aServerIf, + const BluetoothUuid& aAppUuid) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsString uuid; + UuidToString(aAppUuid, uuid); + + size_t index = sServers->IndexOf(uuid, 0 /* Start */, UuidComparator()); + NS_ENSURE_TRUE_VOID(index != sServers->NoIndex); + + nsRefPtr server = (*sServers)[index]; + + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + + if (aStatus != GATT_STATUS_SUCCESS) { + BT_LOGD("RegisterServer failed: serverIf = %d, status = %d, appUuid = %s", + aServerIf, aStatus, NS_ConvertUTF16toUTF8(uuid).get()); + + if (server->mConnectPeripheralRunnable) { + // Reject the connect peripheral request + DispatchReplyError( + server->mConnectPeripheralRunnable, + NS_LITERAL_STRING( + "ConnectPeripheral failed due to registration failed")); + server->mConnectPeripheralRunnable = nullptr; + } + + sServers->RemoveElement(server); + } + + server->mServerIf = aServerIf; + + // Notify BluetoothGattServer to update the serverIf + bs->DistributeSignal( + NS_LITERAL_STRING("ServerRegistered"), + uuid, BluetoothValue(uint32_t(aServerIf))); + + if (server->mConnectPeripheralRunnable) { + // Only one entry exists in the map during first connect peripheral request + nsString deviceAddr(server->mConnectionMap.Iter().Key()); + + sBluetoothGattInterface->ConnectPeripheral( + aServerIf, deviceAddr, true /* direct connect */, TRANSPORT_AUTO, + new ConnectPeripheralResultHandler(server, deviceAddr)); + } +} + +void +BluetoothGattManager::ConnectionNotification(int aConnId, + int aServerIf, + bool aConnected, + const nsAString& aBdAddr) +{ + MOZ_ASSERT(NS_IsMainThread()); + + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + + size_t index = sServers->IndexOf(aServerIf, 0 /* Start */, + InterfaceIdComparator()); + NS_ENSURE_TRUE_VOID(index != sServers->NoIndex); + + nsRefPtr server = (*sServers)[index]; + + // Update the connection map based on the connection status + if (aConnected) { + server->mConnectionMap.Put(aBdAddr, aConnId); + } else { + server->mConnectionMap.Remove(aBdAddr); + } + + // Notify BluetoothGattServer that connection status changed + InfallibleTArray props; + BT_APPEND_NAMED_VALUE(props, "Connected", aConnected); + BT_APPEND_NAMED_VALUE(props, "Address", nsString(aBdAddr)); + bs->DistributeSignal( + NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID), + server->mAppUuid, + BluetoothValue(props)); + + // Resolve or reject connect/disconnect peripheral requests + if (server->mConnectPeripheralRunnable) { + if (aConnected) { + DispatchReplySuccess(server->mConnectPeripheralRunnable); + } else { + DispatchReplyError(server->mConnectPeripheralRunnable, + NS_LITERAL_STRING("ConnectPeripheral failed")); + } + server->mConnectPeripheralRunnable = nullptr; + } else if (server->mDisconnectPeripheralRunnable) { + if (!aConnected) { + DispatchReplySuccess(server->mDisconnectPeripheralRunnable); + } else { + DispatchReplyError(server->mDisconnectPeripheralRunnable, + NS_LITERAL_STRING("DisconnectPeripheral failed")); + } + server->mDisconnectPeripheralRunnable = nullptr; + } +} + BluetoothGattManager::BluetoothGattManager() { } @@ -2132,6 +2553,7 @@ BluetoothGattManager::HandleShutdown() mInShutdown = true; sBluetoothGattManager = nullptr; sClients = nullptr; + sServers = nullptr; } void diff --git a/dom/bluetooth/bluedroid/BluetoothGattManager.h b/dom/bluetooth/bluedroid/BluetoothGattManager.h index 455c36858fc2..0dc9bfe0cb71 100644 --- a/dom/bluetooth/bluedroid/BluetoothGattManager.h +++ b/dom/bluetooth/bluedroid/BluetoothGattManager.h @@ -90,6 +90,19 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable); + void ConnectPeripheral( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable); + + void DisconnectPeripheral( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable); + + void UnregisterServer(int aServerIf, + BluetoothReplyRunnable* aRunnable); + private: ~BluetoothGattManager(); @@ -112,6 +125,11 @@ private: class WriteDescriptorValueResultHandler; class ScanDeviceTypeResultHandler; + class RegisterServerResultHandler; + class ConnectPeripheralResultHandler; + class DisconnectPeripheralResultHandler; + class UnregisterServerResultHandler; + BluetoothGattManager(); void HandleShutdown(); @@ -200,6 +218,15 @@ private: void ProceedDiscoverProcess(BluetoothGattClient* aClient, const BluetoothGattServiceId& aServiceId); + void RegisterServerNotification(BluetoothGattStatus aStatus, + int aServerIf, + const BluetoothUuid& aAppUuid) override; + + void ConnectionNotification(int aConnId, + int aServerIf, + bool aConnected, + const nsAString& aBdAddr) override; + static bool mInShutdown; }; diff --git a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp index 43bd8ed4daf7..46bd50f2affd 100644 --- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp @@ -552,6 +552,51 @@ BluetoothServiceBluedroid::GattClientWriteDescriptorValueInternal( aDescriptorId, aValue, aRunnable); } +// GATT Server +void +BluetoothServiceBluedroid::GattServerConnectPeripheralInternal( + const nsAString& aAppUuid, const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + + ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable); + + BluetoothGattManager* gatt = BluetoothGattManager::Get(); + ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable); + + gatt->ConnectPeripheral(aAppUuid, aAddress, aRunnable); +} + +void +BluetoothServiceBluedroid::GattServerDisconnectPeripheralInternal( + const nsAString& aAppUuid, const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + + ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable); + + BluetoothGattManager* gatt = BluetoothGattManager::Get(); + ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable); + + gatt->DisconnectPeripheral(aAppUuid, aAddress, aRunnable); +} + +void +BluetoothServiceBluedroid::UnregisterGattServerInternal( + int aServerIf, BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + + ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable); + + BluetoothGattManager* gatt = BluetoothGattManager::Get(); + ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable); + + gatt->UnregisterServer(aServerIf, aRunnable); +} + nsresult BluetoothServiceBluedroid::GetAdaptersInternal( BluetoothReplyRunnable* aRunnable) diff --git a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h index 72fa4b64d19c..992cc4f8cbc5 100644 --- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h +++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h @@ -290,6 +290,22 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable) override; + virtual void + GattServerConnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) override; + + virtual void + GattServerDisconnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) override; + + virtual void + UnregisterGattServerInternal(int aServerIf, + BluetoothReplyRunnable* aRunnable) override; + // // Bluetooth notifications // diff --git a/dom/bluetooth/bluetooth2/BluetoothDiscoveryHandle.cpp b/dom/bluetooth/bluetooth2/BluetoothDiscoveryHandle.cpp index 46f91d392ce7..da2681eb93bd 100644 --- a/dom/bluetooth/bluetooth2/BluetoothDiscoveryHandle.cpp +++ b/dom/bluetooth/bluetooth2/BluetoothDiscoveryHandle.cpp @@ -23,7 +23,6 @@ NS_IMPL_RELEASE_INHERITED(BluetoothDiscoveryHandle, DOMEventTargetHelper) BluetoothDiscoveryHandle::BluetoothDiscoveryHandle(nsPIDOMWindow* aWindow) : DOMEventTargetHelper(aWindow) - , mLeScanUuid(EmptyString()) { MOZ_ASSERT(aWindow); } diff --git a/dom/bluetooth/bluetooth2/BluetoothGatt.cpp b/dom/bluetooth/bluetooth2/BluetoothGatt.cpp index ff86b8d578c0..3e26decd73be 100644 --- a/dom/bluetooth/bluetooth2/BluetoothGatt.cpp +++ b/dom/bluetooth/bluetooth2/BluetoothGatt.cpp @@ -51,7 +51,6 @@ NS_IMPL_RELEASE_INHERITED(BluetoothGatt, DOMEventTargetHelper) BluetoothGatt::BluetoothGatt(nsPIDOMWindow* aWindow, const nsAString& aDeviceAddr) : DOMEventTargetHelper(aWindow) - , mAppUuid(EmptyString()) , mClientIf(0) , mConnectionState(BluetoothConnectionState::Disconnected) , mDeviceAddr(aDeviceAddr) diff --git a/dom/bluetooth/bluetooth2/BluetoothGattServer.cpp b/dom/bluetooth/bluetooth2/BluetoothGattServer.cpp index e68fa6efb730..0940573b3f38 100644 --- a/dom/bluetooth/bluetooth2/BluetoothGattServer.cpp +++ b/dom/bluetooth/bluetooth2/BluetoothGattServer.cpp @@ -6,32 +6,91 @@ #include "BluetoothGattServer.h" +#include "BluetoothReplyRunnable.h" +#include "BluetoothService.h" +#include "BluetoothUtils.h" +#include "mozilla/dom/BluetoothStatusChangedEvent.h" +#include "mozilla/dom/Promise.h" + using namespace mozilla; using namespace mozilla::dom; USING_BLUETOOTH_NAMESPACE -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BluetoothGattServer, - mOwner) +NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothGattServer) -NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothGattServer) -NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothGattServer) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothGattServer) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothGattServer, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner) + + /** + * Unregister the bluetooth signal handler after unlinked. + * + * This is needed to avoid ending up with exposing a deleted object to JS or + * accessing deleted objects while receiving signals from parent process + * after unlinked. Please see Bug 1138267 for detail informations. + */ + UnregisterBluetoothSignalHandler(tmp->mAppUuid, tmp); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothGattServer, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothGattServer) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(BluetoothGattServer, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(BluetoothGattServer, DOMEventTargetHelper) BluetoothGattServer::BluetoothGattServer(nsPIDOMWindow* aOwner) : mOwner(aOwner) + , mServerIf(0) , mValid(true) -{ -} +{ } BluetoothGattServer::~BluetoothGattServer() { Invalidate(); } +void +BluetoothGattServer::Notify(const BluetoothSignal& aData) +{ + BT_LOGD("[GattServer] %s", NS_ConvertUTF16toUTF8(aData.name()).get()); + NS_ENSURE_TRUE_VOID(mSignalRegistered); + + BluetoothValue v = aData.value(); + if (aData.name().EqualsLiteral("ServerRegistered")) { + MOZ_ASSERT(v.type() == BluetoothValue::Tuint32_t); + mServerIf = v.get_uint32_t(); + } else if (aData.name().EqualsLiteral("ServerUnregistered")) { + mServerIf = 0; + } else if (aData.name().EqualsLiteral(GATT_CONNECTION_STATE_CHANGED_ID)) { + MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue); + const InfallibleTArray& arr = + v.get_ArrayOfBluetoothNamedValue(); + + MOZ_ASSERT(arr.Length() == 2 && + arr[0].value().type() == BluetoothValue::Tbool && + arr[1].value().type() == BluetoothValue::TnsString); + + BluetoothStatusChangedEventInit init; + init.mStatus = arr[0].value().get_bool(); + init.mAddress = arr[1].value().get_nsString(); + + nsRefPtr event = + BluetoothStatusChangedEvent::Constructor( + this, NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID), init); + + DispatchTrustedEvent(event); + } else { + BT_WARNING("Not handling GATT signal: %s", + NS_ConvertUTF16toUTF8(aData.name()).get()); + } +} + JSObject* BluetoothGattServer::WrapObject(JSContext* aContext, JS::Handle aGivenProto) @@ -39,12 +98,76 @@ BluetoothGattServer::WrapObject(JSContext* aContext, return BluetoothGattServerBinding::Wrap(aContext, this, aGivenProto); } +void +BluetoothGattServer::DisconnectFromOwner() +{ + DOMEventTargetHelper::DisconnectFromOwner(); + Invalidate(); +} + void BluetoothGattServer::Invalidate() { mValid = false; - /* TODO: add tear down stuff here */ + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); - return; -} \ No newline at end of file + if (mServerIf > 0) { + bs->UnregisterGattServerInternal(mServerIf, nullptr); + } + + UnregisterBluetoothSignalHandler(mAppUuid, this); +} + +already_AddRefed +BluetoothGattServer::Connect(const nsAString& aAddress, ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(GetParentObject()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr promise = Promise::Create(global, aRv); + NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + + BT_ENSURE_TRUE_REJECT(mValid, promise, NS_ERROR_NOT_AVAILABLE); + BluetoothService* bs = BluetoothService::Get(); + BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE); + + if (mAppUuid.IsEmpty()) { + GenerateUuid(mAppUuid); + BT_ENSURE_TRUE_REJECT(!mAppUuid.IsEmpty(), + promise, + NS_ERROR_DOM_OPERATION_ERR); + RegisterBluetoothSignalHandler(mAppUuid, this); + } + + bs->GattServerConnectPeripheralInternal( + mAppUuid, aAddress, new BluetoothVoidReplyRunnable(nullptr, promise)); + + return promise.forget(); +} + +already_AddRefed +BluetoothGattServer::Disconnect(const nsAString& aAddress, ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(GetParentObject()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr promise = Promise::Create(global, aRv); + NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + + BT_ENSURE_TRUE_REJECT(mValid, promise, NS_ERROR_NOT_AVAILABLE); + BluetoothService* bs = BluetoothService::Get(); + BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE); + + bs->GattServerDisconnectPeripheralInternal( + mAppUuid, aAddress, new BluetoothVoidReplyRunnable(nullptr, promise)); + + return promise.forget(); +} diff --git a/dom/bluetooth/bluetooth2/BluetoothGattServer.h b/dom/bluetooth/bluetooth2/BluetoothGattServer.h index 2865c9167cd8..b7ebe9742239 100644 --- a/dom/bluetooth/bluetooth2/BluetoothGattServer.h +++ b/dom/bluetooth/bluetooth2/BluetoothGattServer.h @@ -7,20 +7,29 @@ #ifndef mozilla_dom_bluetooth_BluetoothGattServer_h #define mozilla_dom_bluetooth_BluetoothGattServer_h +#include "mozilla/DOMEventTargetHelper.h" #include "mozilla/dom/BluetoothGattServerBinding.h" #include "mozilla/dom/bluetooth/BluetoothCommon.h" #include "nsCOMPtr.h" #include "nsPIDOMWindow.h" -#include "nsWrapperCache.h" + +namespace mozilla { +namespace dom { +class Promise; +} +} BEGIN_BLUETOOTH_NAMESPACE -class BluetoothGattServer final : public nsISupports - , public nsWrapperCache +class BluetoothSignal; + +class BluetoothGattServer final : public DOMEventTargetHelper + , public BluetoothSignalObserver { public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BluetoothGattServer) + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothGattServer, + DOMEventTargetHelper) /**************************************************************************** * Attribute Getters @@ -29,14 +38,21 @@ public: /**************************************************************************** * Event Handlers ***************************************************************************/ + IMPL_EVENT_HANDLER(connectionstatechanged); /**************************************************************************** * Methods (Web API Implementation) ***************************************************************************/ + already_AddRefed Connect( + const nsAString& aAddress, ErrorResult& aRv); + already_AddRefed Disconnect( + const nsAString& aAddress, ErrorResult& aRv); /**************************************************************************** * Others ***************************************************************************/ + void Notify(const BluetoothSignal& aData); // BluetoothSignalObserver + nsPIDOMWindow* GetParentObject() const { return mOwner; @@ -45,6 +61,7 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + virtual void DisconnectFromOwner() override; BluetoothGattServer(nsPIDOMWindow* aOwner); /* Invalidate the GATT server. @@ -61,6 +78,17 @@ private: ***************************************************************************/ nsCOMPtr mOwner; + /** + * Random generated UUID of this GATT client. + */ + nsString mAppUuid; + + /** + * Id of the GATT server interface given by bluetooth stack. + * 0 if the interface is not registered yet, nonzero otherwise. + */ + int mServerIf; + bool mValid; }; diff --git a/dom/bluetooth/bluetooth2/BluetoothService.h b/dom/bluetooth/bluetooth2/BluetoothService.h index 649bdf797cc2..8b2b18f74040 100644 --- a/dom/bluetooth/bluetooth2/BluetoothService.h +++ b/dom/bluetooth/bluetooth2/BluetoothService.h @@ -490,6 +490,25 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable) = 0; + virtual void + GattServerConnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) = 0; + + virtual void + GattServerDisconnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) = 0; + + /** + * Unregister a GATT server. (platform specific implementation) + */ + virtual void + UnregisterGattServerInternal(int aServerIf, + BluetoothReplyRunnable* aRunnable) = 0; + bool IsEnabled() const { diff --git a/dom/bluetooth/bluetooth2/ipc/BluetoothParent.cpp b/dom/bluetooth/bluetooth2/ipc/BluetoothParent.cpp index fe90a26cf9b4..6df78b28d8d4 100644 --- a/dom/bluetooth/bluetooth2/ipc/BluetoothParent.cpp +++ b/dom/bluetooth/bluetooth2/ipc/BluetoothParent.cpp @@ -292,6 +292,14 @@ BluetoothParent::RecvPBluetoothRequestConstructor( case Request::TGattClientWriteDescriptorValueRequest: return actor->DoRequest( aRequest.get_GattClientWriteDescriptorValueRequest()); + case Request::TGattServerConnectPeripheralRequest: + return actor->DoRequest( + aRequest.get_GattServerConnectPeripheralRequest()); + case Request::TGattServerDisconnectPeripheralRequest: + return actor->DoRequest( + aRequest.get_GattServerDisconnectPeripheralRequest()); + case Request::TUnregisterGattServerRequest: + return actor->DoRequest(aRequest.get_UnregisterGattServerRequest()); default: MOZ_CRASH("Unknown type!"); } @@ -973,3 +981,45 @@ BluetoothRequestParent::DoRequest( return true; } + +bool +BluetoothRequestParent::DoRequest( + const GattServerConnectPeripheralRequest& aRequest) +{ + MOZ_ASSERT(mService); + MOZ_ASSERT(mRequestType == + Request::TGattServerConnectPeripheralRequest); + + mService->GattServerConnectPeripheralInternal(aRequest.appUuid(), + aRequest.address(), + mReplyRunnable.get()); + + return true; +} + +bool +BluetoothRequestParent::DoRequest( + const GattServerDisconnectPeripheralRequest& aRequest) +{ + MOZ_ASSERT(mService); + MOZ_ASSERT(mRequestType == + Request::TGattServerDisconnectPeripheralRequest); + + mService->GattServerDisconnectPeripheralInternal(aRequest.appUuid(), + aRequest.address(), + mReplyRunnable.get()); + + return true; +} + +bool +BluetoothRequestParent::DoRequest(const UnregisterGattServerRequest& aRequest) +{ + MOZ_ASSERT(mService); + MOZ_ASSERT(mRequestType == Request::TUnregisterGattServerRequest); + + mService->UnregisterGattServerInternal(aRequest.serverIf(), + mReplyRunnable.get()); + + return true; +} diff --git a/dom/bluetooth/bluetooth2/ipc/BluetoothParent.h b/dom/bluetooth/bluetooth2/ipc/BluetoothParent.h index 4db1549ee4fe..bef542435ffc 100644 --- a/dom/bluetooth/bluetooth2/ipc/BluetoothParent.h +++ b/dom/bluetooth/bluetooth2/ipc/BluetoothParent.h @@ -270,6 +270,15 @@ protected: bool DoRequest(const GattClientWriteDescriptorValueRequest& aRequest); + + bool + DoRequest(const GattServerConnectPeripheralRequest& aRequest); + + bool + DoRequest(const GattServerDisconnectPeripheralRequest& aRequest); + + bool + DoRequest(const UnregisterGattServerRequest& aRequest); }; END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp index ac39b38073bf..82a8d89881b9 100644 --- a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp +++ b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp @@ -598,6 +598,35 @@ BluetoothServiceChildProcess::GattClientWriteDescriptorValueInternal( aValue)); } +void +BluetoothServiceChildProcess::GattServerConnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) +{ + SendRequest(aRunnable, + GattServerConnectPeripheralRequest(nsString(aAppUuid), + nsString(aAddress))); +} + +void +BluetoothServiceChildProcess::GattServerDisconnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) +{ + SendRequest(aRunnable, + GattServerDisconnectPeripheralRequest(nsString(aAppUuid), + nsString(aAddress))); +} + +void +BluetoothServiceChildProcess::UnregisterGattServerInternal( + int aServerIf, BluetoothReplyRunnable* aRunnable) +{ + SendRequest(aRunnable, UnregisterGattServerRequest(aServerIf)); +} + nsresult BluetoothServiceChildProcess::HandleStartup() { diff --git a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h index d860f02bde9a..c8ef22541887 100644 --- a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h +++ b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h @@ -298,6 +298,22 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable); + virtual void + GattServerConnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable); + + virtual void + GattServerDisconnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable); + + virtual void + UnregisterGattServerInternal(int aServerIf, + BluetoothReplyRunnable* aRunnable) override; + protected: BluetoothServiceChildProcess(); virtual ~BluetoothServiceChildProcess(); diff --git a/dom/bluetooth/bluetooth2/ipc/PBluetooth.ipdl b/dom/bluetooth/bluetooth2/ipc/PBluetooth.ipdl index 8663021b4715..193bd035efd9 100644 --- a/dom/bluetooth/bluetooth2/ipc/PBluetooth.ipdl +++ b/dom/bluetooth/bluetooth2/ipc/PBluetooth.ipdl @@ -292,6 +292,23 @@ struct GattClientWriteDescriptorValueRequest uint8_t[] value; }; +struct GattServerConnectPeripheralRequest +{ + nsString appUuid; + nsString address; +}; + +struct GattServerDisconnectPeripheralRequest +{ + nsString appUuid; + nsString address; +}; + +struct UnregisterGattServerRequest +{ + int serverIf; +}; + union Request { GetAdaptersRequest; @@ -342,6 +359,9 @@ union Request GattClientWriteCharacteristicValueRequest; GattClientReadDescriptorValueRequest; GattClientWriteDescriptorValueRequest; + GattServerConnectPeripheralRequest; + GattServerDisconnectPeripheralRequest; + UnregisterGattServerRequest; }; protocol PBluetooth diff --git a/dom/bluetooth/bluez/BluetoothDBusService.cpp b/dom/bluetooth/bluez/BluetoothDBusService.cpp index a90d7d999f5a..a489ef9a33b4 100644 --- a/dom/bluetooth/bluez/BluetoothDBusService.cpp +++ b/dom/bluetooth/bluez/BluetoothDBusService.cpp @@ -4379,6 +4379,26 @@ BluetoothDBusService::GattClientWriteDescriptorValueInternal( { } +void +BluetoothDBusService::GattServerConnectPeripheralInternal( + const nsAString& aAppUuid, const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) +{ +} + +void +BluetoothDBusService::GattServerDisconnectPeripheralInternal( + const nsAString& aAppUuid, const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) +{ +} + +void +BluetoothDBusService::UnregisterGattServerInternal( + int aServerIf, BluetoothReplyRunnable* aRunnable) +{ +} + void BluetoothDBusService::ReplyTovCardPulling( BlobParent* aBlobParent, diff --git a/dom/bluetooth/bluez/BluetoothDBusService.h b/dom/bluetooth/bluez/BluetoothDBusService.h index d564063b480b..ae6081b87fd5 100644 --- a/dom/bluetooth/bluez/BluetoothDBusService.h +++ b/dom/bluetooth/bluez/BluetoothDBusService.h @@ -305,6 +305,22 @@ public: const nsTArray& aValue, BluetoothReplyRunnable* aRunnable) override; + virtual void + GattServerConnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) override; + + virtual void + GattServerDisconnectPeripheralInternal( + const nsAString& aAppUuid, + const nsAString& aAddress, + BluetoothReplyRunnable* aRunnable) override; + + virtual void + UnregisterGattServerInternal(int aServerIf, + BluetoothReplyRunnable* aRunnable) override; + private: nsresult SendGetPropertyMessage(const nsAString& aPath, const char* aInterface, diff --git a/dom/webidl/BluetoothGattServer.webidl b/dom/webidl/BluetoothGattServer.webidl index aaa2e61fe769..68776c256400 100644 --- a/dom/webidl/BluetoothGattServer.webidl +++ b/dom/webidl/BluetoothGattServer.webidl @@ -5,9 +5,19 @@ */ [CheckAnyPermissions="bluetooth"] -interface BluetoothGattServer +interface BluetoothGattServer : EventTarget { - /* The implementation of BluetoothGattServer will come later. - * (see dependent bugs of bug 933358) + // Fired when a remote device has been connected/disconnected + attribute EventHandler onconnectionstatechanged; + + /** + * Connect/Disconnect to the remote BLE device with the target address. + * + * Promise will be rejected if the local GATT server is busy connecting or + * disconnecting to other devices. */ + [NewObject] + Promise connect(DOMString address); + [NewObject] + Promise disconnect(DOMString address); };