Bug 1181480 - Add and implement GATT server connection related Web APIs. r=btian, r=mrbkap

This commit is contained in:
Jocelyn Liu 2015-08-21 17:11:14 +08:00
parent 022d30fc0f
commit b721582960
18 changed files with 897 additions and 49 deletions

View File

@ -1847,7 +1847,7 @@ public:
return rv;
}
/* Read connected */
rv = UnpackPDU(pdu, aArg3);
rv = UnpackPDU(pdu, UnpackConversion<int32_t, bool>(aArg3));
if (NS_FAILED(rv)) {
return rv;
}

View File

@ -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<BluetoothGattManager> sBluetoothGattManager;
static BluetoothGattInterface* sBluetoothGattInterface;
@ -37,6 +40,7 @@ namespace {
bool BluetoothGattManager::mInShutdown = false;
static StaticAutoPtr<nsTArray<nsRefPtr<BluetoothGattClient> > > sClients;
static StaticAutoPtr<nsTArray<nsRefPtr<BluetoothGattServer> > > 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<BluetoothReplyRunnable> mConnectPeripheralRunnable;
nsRefPtr<BluetoothReplyRunnable> mDisconnectPeripheralRunnable;
nsRefPtr<BluetoothReplyRunnable> mUnregisterServerRunnable;
// Map connection id from device address
nsDataHashtable<nsStringHashKey, int> mConnectionMap;
private:
~BluetoothGattServer()
{ }
};
NS_IMPL_ISUPPORTS0(BluetoothGattServer)
class UuidComparator
{
public:
@ -210,9 +240,15 @@ public:
{
return aClient->mAppUuid.Equals(aAppUuid);
}
bool Equals(const nsRefPtr<BluetoothGattServer>& aServer,
const nsAString& aAppUuid) const
{
return aServer->mAppUuid.Equals(aAppUuid);
}
};
class ClientIfComparator
class InterfaceIdComparator
{
public:
bool Equals(const nsRefPtr<BluetoothGattClient>& aClient,
@ -220,6 +256,12 @@ public:
{
return aClient->mClientIf == aClientIf;
}
bool Equals(const nsRefPtr<BluetoothGattServer>& aServer,
int aServerIf) const
{
return aServer->mServerIf == aServerIf;
}
};
class ConnIdComparator
@ -305,6 +347,10 @@ BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
sClients = new nsTArray<nsRefPtr<BluetoothGattClient> >;
}
if (!sServers) {
sServers = new nsTArray<nsRefPtr<BluetoothGattServer> >;
}
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<nsString>& 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<BluetoothGattServer> 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<BluetoothGattServer> 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<BluetoothGattServer> 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<BluetoothGattServer> 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<BluetoothGattServer> 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<BluetoothGattServer> 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<BluetoothGattServer> 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<BluetoothGattClient> 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<BluetoothGattClient> 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<BluetoothGattClient> 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<BluetoothGattServer> 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<BluetoothGattServer> 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<BluetoothNamedValue> 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

View File

@ -90,6 +90,19 @@ public:
const nsTArray<uint8_t>& 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;
};

View File

@ -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)

View File

@ -290,6 +290,22 @@ public:
const nsTArray<uint8_t>& 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
//

View File

@ -23,7 +23,6 @@ NS_IMPL_RELEASE_INHERITED(BluetoothDiscoveryHandle, DOMEventTargetHelper)
BluetoothDiscoveryHandle::BluetoothDiscoveryHandle(nsPIDOMWindow* aWindow)
: DOMEventTargetHelper(aWindow)
, mLeScanUuid(EmptyString())
{
MOZ_ASSERT(aWindow);
}

View File

@ -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)

View File

@ -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<BluetoothNamedValue>& 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<BluetoothStatusChangedEvent> 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<JSObject*> 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;
}
if (mServerIf > 0) {
bs->UnregisterGattServerInternal(mServerIf, nullptr);
}
UnregisterBluetoothSignalHandler(mAppUuid, this);
}
already_AddRefed<Promise>
BluetoothGattServer::Connect(const nsAString& aAddress, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
if (!global) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<Promise> 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<Promise>
BluetoothGattServer::Disconnect(const nsAString& aAddress, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
if (!global) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<Promise> 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();
}

View File

@ -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<Promise> Connect(
const nsAString& aAddress, ErrorResult& aRv);
already_AddRefed<Promise> 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<JSObject*> aGivenProto) override;
virtual void DisconnectFromOwner() override;
BluetoothGattServer(nsPIDOMWindow* aOwner);
/* Invalidate the GATT server.
@ -61,6 +78,17 @@ private:
***************************************************************************/
nsCOMPtr<nsPIDOMWindow> 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;
};

View File

@ -490,6 +490,25 @@ public:
const nsTArray<uint8_t>& 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
{

View File

@ -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;
}

View File

@ -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

View File

@ -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()
{

View File

@ -298,6 +298,22 @@ public:
const nsTArray<uint8_t>& 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();

View File

@ -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

View File

@ -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,

View File

@ -305,6 +305,22 @@ public:
const nsTArray<uint8_t>& 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,

View File

@ -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<void> connect(DOMString address);
[NewObject]
Promise<void> disconnect(DOMString address);
};