diff --git a/dom/bluetooth2/BluetoothCommon.h b/dom/bluetooth2/BluetoothCommon.h index 08293b5c606..6f7270b987b 100644 --- a/dom/bluetooth2/BluetoothCommon.h +++ b/dom/bluetooth2/BluetoothCommon.h @@ -194,6 +194,101 @@ enum BluetoothStatus { STATUS_RMT_DEV_DOWN }; +enum BluetoothBondState { + BOND_STATE_NONE, + BOND_STATE_BONDING, + BOND_STATE_BONDED +}; + +enum BluetoothDeviceType { + DEVICE_TYPE_BREDR, + DEVICE_TYPE_BLE, + DEVICE_TYPE_DUAL +}; + +enum BluetoothPropertyType { + PROPERTY_BDNAME, + PROPERTY_BDADDR, + PROPERTY_UUIDS, + PROPERTY_CLASS_OF_DEVICE, + PROPERTY_TYPE_OF_DEVICE, + PROPERTY_SERVICE_RECORD, + PROPERTY_ADAPTER_SCAN_MODE, + PROPERTY_ADAPTER_BONDED_DEVICES, + PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, + PROPERTY_REMOTE_FRIENDLY_NAME, + PROPERTY_REMOTE_RSSI, + PROPERTY_REMOTE_VERSION_INFO, + PROPERTY_REMOTE_DEVICE_TIMESTAMP +}; + +enum BluetoothScanMode { + SCAN_MODE_NONE, + SCAN_MODE_CONNECTABLE, + SCAN_MODE_CONNECTABLE_DISCOVERABLE +}; + +enum BluetoothSspVariant { + SSP_VARIANT_PASSKEY_CONFIRMATION, + SSP_VARIANT_PASSKEY_ENTRY, + SSP_VARIANT_CONSENT, + SSP_VARIANT_PASSKEY_NOTIFICATION +}; + +struct BluetoothUuid { + uint8_t mUuid[16]; +}; + +struct BluetoothServiceRecord { + BluetoothUuid mUuid; + uint16_t mChannel; + char mName[256]; +}; + +struct BluetoothRemoteInfo { + int mVerMajor; + int mVerMinor; + int mManufacturer; +}; + +struct BluetoothProperty { + /* Type */ + BluetoothPropertyType mType; + + /* Value + */ + + /* PROPERTY_BDNAME + PROPERTY_BDADDR + PROPERTY_REMOTE_FRIENDLY_NAME */ + nsString mString; + + /* PROPERTY_UUIDS */ + nsTArray mUuidArray; + + /* PROPERTY_ADAPTER_BONDED_DEVICES */ + nsTArray mStringArray; + + /* PROPERTY_CLASS_OF_DEVICE + PROPERTY_ADAPTER_DISCOVERY_TIMEOUT */ + uint32_t mUint32; + + /* PROPERTY_RSSI_VALUE */ + int32_t mInt32; + + /* PROPERTY_DEVICE_TYPE */ + BluetoothDeviceType mDeviceType; + + /* PROPERTY_SERVICE_RECORD */ + BluetoothServiceRecord mServiceRecord; + + /* PROPERTY_SCAN_MODE */ + BluetoothScanMode mScanMode; + + /* PROPERTY_REMOTE_VERSION_INFO */ + BluetoothRemoteInfo mRemoteInfo; +}; + enum BluetoothSocketType { RFCOMM = 1, SCO = 2, diff --git a/dom/bluetooth2/bluedroid/BluetoothInterface.cpp b/dom/bluetooth2/bluedroid/BluetoothInterface.cpp index 3c5ae885be7..8f6029c8da8 100644 --- a/dom/bluetooth2/bluedroid/BluetoothInterface.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothInterface.cpp @@ -23,6 +23,8 @@ out_ #endif +#define MAX_UUID_SIZE 16 + BEGIN_BLUETOOTH_NAMESPACE template @@ -92,6 +94,23 @@ Convert(bool aIn, bt_scan_mode_t& aOut) return NS_OK; } + +static nsresult +Convert(bt_scan_mode_t aIn, BluetoothScanMode& aOut) +{ + static const BluetoothScanMode sScanMode[] = { + CONVERT(BT_SCAN_MODE_NONE, SCAN_MODE_NONE), + CONVERT(BT_SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE), + CONVERT(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE, + SCAN_MODE_CONNECTABLE_DISCOVERABLE) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sScanMode)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sScanMode[aIn]; + return NS_OK; +} + struct ConvertNamedValue { ConvertNamedValue(const BluetoothNamedValue& aNamedValue) @@ -173,6 +192,24 @@ Convert(const nsAString& aIn, bt_ssp_variant_t& aOut) return NS_OK; } +static nsresult +Convert(const bt_ssp_variant_t& aIn, BluetoothSspVariant& aOut) +{ + static const BluetoothSspVariant sSspVariant[] = { + CONVERT(BT_SSP_VARIANT_PASSKEY_CONFIRMATION, + SSP_VARIANT_PASSKEY_CONFIRMATION), + CONVERT(BT_SSP_VARIANT_PASSKEY_ENTRY, SSP_VARIANT_PASSKEY_ENTRY), + CONVERT(BT_SSP_VARIANT_CONSENT, SSP_VARIANT_CONSENT), + CONVERT(BT_SSP_VARIANT_PASSKEY_NOTIFICATION, + SSP_VARIANT_PASSKEY_NOTIFICATION) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sSspVariant)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sSspVariant[aIn]; + return NS_OK; +} + static nsresult Convert(const bool& aIn, uint8_t& aOut) { @@ -193,6 +230,18 @@ Convert(const uint8_t aIn[16], bt_uuid_t& aOut) return NS_OK; } +static nsresult +Convert(const bt_uuid_t& aIn, BluetoothUuid& aOut) +{ + if (sizeof(aIn.uu) != sizeof(aOut.mUuid)) { + return NS_ERROR_ILLEGAL_VALUE; + } + + memcpy(aOut.mUuid, aIn.uu, sizeof(aOut.mUuid)); + + return NS_OK; +} + static nsresult Convert(const nsAString& aIn, bt_pin_code_t& aOut) { @@ -241,6 +290,166 @@ Convert(const bt_bdaddr_t& aIn, nsAString& aOut) return NS_OK; } +static nsresult +Convert(const bt_bdaddr_t* aIn, nsAString& aOut) +{ + if (!aIn) { + aOut.AssignLiteral(BLUETOOTH_ADDRESS_NONE); + return NS_OK; + } + return Convert(*aIn, aOut); +} + +static nsresult +Convert(bt_state_t aIn, bool& aOut) +{ + static const bool sState[] = { + CONVERT(BT_STATE_OFF, false), + CONVERT(BT_STATE_ON, true) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sState[aIn]; + return NS_OK; +} + +static nsresult +Convert(bt_property_type_t aIn, BluetoothPropertyType& aOut) +{ + static const BluetoothPropertyType sPropertyType[] = { + CONVERT(0, static_cast(0)), // invalid, required by gcc + CONVERT(BT_PROPERTY_BDNAME, PROPERTY_BDNAME), + CONVERT(BT_PROPERTY_BDADDR, PROPERTY_BDADDR), + CONVERT(BT_PROPERTY_UUIDS, PROPERTY_UUIDS), + CONVERT(BT_PROPERTY_CLASS_OF_DEVICE, PROPERTY_CLASS_OF_DEVICE), + CONVERT(BT_PROPERTY_TYPE_OF_DEVICE, PROPERTY_TYPE_OF_DEVICE), + CONVERT(BT_PROPERTY_SERVICE_RECORD, PROPERTY_SERVICE_RECORD), + CONVERT(BT_PROPERTY_ADAPTER_SCAN_MODE, PROPERTY_ADAPTER_SCAN_MODE), + CONVERT(BT_PROPERTY_ADAPTER_BONDED_DEVICES, + PROPERTY_ADAPTER_BONDED_DEVICES), + CONVERT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, + PROPERTY_ADAPTER_DISCOVERY_TIMEOUT), + CONVERT(BT_PROPERTY_REMOTE_FRIENDLY_NAME, PROPERTY_REMOTE_FRIENDLY_NAME), + CONVERT(BT_PROPERTY_REMOTE_RSSI, PROPERTY_REMOTE_RSSI), + CONVERT(BT_PROPERTY_REMOTE_VERSION_INFO,PROPERTY_REMOTE_VERSION_INFO) + }; + if (aIn == BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP) { + /* This case is handled separately to not populate + * |sPropertyType| with empty entries. */ + aOut = PROPERTY_REMOTE_DEVICE_TIMESTAMP; + return NS_OK; + } + if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sPropertyType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sPropertyType[aIn]; + return NS_OK; +} + +static nsresult +Convert(bt_discovery_state_t aIn, bool& aOut) +{ + static const bool sDiscoveryState[] = { + CONVERT(BT_DISCOVERY_STOPPED, false), + CONVERT(BT_DISCOVERY_STARTED, true) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sDiscoveryState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sDiscoveryState[aIn]; + return NS_OK; +} + +static nsresult +Convert(const bt_bdname_t& aIn, nsAString& aOut) +{ + aOut = NS_ConvertUTF8toUTF16(reinterpret_cast(aIn.name)); + + return NS_OK; +} + +static nsresult +Convert(const bt_bdname_t* aIn, nsAString& aOut) +{ + if (!aIn) { + aOut.Truncate(); + return NS_OK; + } + return Convert(*aIn, aOut); +} + +static nsresult +Convert(bt_bond_state_t aIn, BluetoothBondState& aOut) +{ + static const BluetoothBondState sBondState[] = { + CONVERT(BT_BOND_STATE_NONE, BOND_STATE_NONE), + CONVERT(BT_BOND_STATE_BONDING, BOND_STATE_BONDING), + CONVERT(BT_BOND_STATE_BONDED, BOND_STATE_BONDED) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sBondState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sBondState[aIn]; + return NS_OK; +} + +static nsresult +Convert(bt_acl_state_t aIn, bool& aOut) +{ + static const bool sAclState[] = { + CONVERT(BT_ACL_STATE_CONNECTED, true), + CONVERT(BT_ACL_STATE_DISCONNECTED, false) + }; + if (aIn >= MOZ_ARRAY_LENGTH(sAclState)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sAclState[aIn]; + return NS_OK; +} + +static nsresult +Convert(bt_device_type_t aIn, BluetoothDeviceType& aOut) +{ + static const BluetoothDeviceType sDeviceType[] = { + CONVERT(0, static_cast(0)), // invalid, required by gcc + CONVERT(BT_DEVICE_DEVTYPE_BREDR, DEVICE_TYPE_BREDR), + CONVERT(BT_DEVICE_DEVTYPE_BLE, DEVICE_TYPE_BLE), + CONVERT(BT_DEVICE_DEVTYPE_DUAL, DEVICE_TYPE_DUAL) + }; + if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sDeviceType)) { + return NS_ERROR_ILLEGAL_VALUE; + } + aOut = sDeviceType[aIn]; + return NS_OK; +} + +static nsresult +Convert(const bt_remote_version_t& aIn, BluetoothRemoteInfo& aOut) +{ + aOut.mVerMajor = aIn.version; + aOut.mVerMinor = aIn.sub_ver; + aOut.mManufacturer = aIn.manufacturer; + + return NS_OK; +} + +static nsresult +Convert(const bt_service_record_t& aIn, BluetoothServiceRecord& aOut) +{ + nsresult rv = Convert(aIn.uuid, aOut.mUuid); + if (NS_FAILED(rv)) { + return rv; + } + + aOut.mChannel = aIn.channel; + + MOZ_ASSERT(sizeof(aIn.name) == sizeof(aOut.mName)); + memcpy(aOut.mName, aIn.name, sizeof(aOut.mName)); + + return NS_OK; +} + static nsresult Convert(BluetoothSocketType aIn, btsock_type_t& aOut) { @@ -556,6 +765,101 @@ ConvertDefault(const Tin& aIn, const Tout& aDefault) return out; } +/* This implementation of |Convert| is a helper for copying the + * input value into the output value. It handles all cases that + * need no conversion. + */ +template +static nsresult +Convert(const T& aIn, T& aOut) +{ + aOut = aIn; + + return NS_OK; +} + +static nsresult +Convert(const bt_property_t& aIn, BluetoothProperty& aOut) +{ + /* type conversion */ + + nsresult rv = Convert(aIn.type, aOut.mType); + if (NS_FAILED(rv)) { + return rv; + } + + /* value conversion */ + + switch (aOut.mType) { + case PROPERTY_BDNAME: + /* fall through */ + case PROPERTY_REMOTE_FRIENDLY_NAME: + { + // We construct an nsCString here because bdname + // returned from Bluedroid is not 0-terminated. + aOut.mString = NS_ConvertUTF8toUTF16( + nsCString(static_cast(aIn.val), aIn.len)); + } + break; + case PROPERTY_BDADDR: + rv = Convert(*static_cast(aIn.val), aOut.mString); + break; + case PROPERTY_UUIDS: + { + size_t numUuids = aIn.len / MAX_UUID_SIZE; + ConvertArray array( + static_cast(aIn.val), numUuids); + aOut.mUuidArray.SetLength(numUuids); + rv = Convert(array, aOut.mUuidArray); + } + break; + case PROPERTY_CLASS_OF_DEVICE: + /* fall through */ + case PROPERTY_ADAPTER_DISCOVERY_TIMEOUT: + aOut.mUint32 = *static_cast(aIn.val); + break; + case PROPERTY_TYPE_OF_DEVICE: + rv = Convert(*static_cast(aIn.val), + aOut.mDeviceType); + break; + case PROPERTY_SERVICE_RECORD: + rv = Convert(*static_cast(aIn.val), + aOut.mServiceRecord); + break; + case PROPERTY_ADAPTER_SCAN_MODE: + rv = Convert(*static_cast(aIn.val), + aOut.mScanMode); + break; + case PROPERTY_ADAPTER_BONDED_DEVICES: + { + size_t numAddresses = aIn.len / BLUETOOTH_ADDRESS_BYTES; + ConvertArray array( + static_cast(aIn.val), numAddresses); + aOut.mStringArray.SetLength(numAddresses); + rv = Convert(array, aOut.mStringArray); + } + break; + case PROPERTY_REMOTE_RSSI: + aOut.mInt32 = *static_cast(aIn.val); + break; + case PROPERTY_REMOTE_VERSION_INFO: + rv = Convert(*static_cast(aIn.val), + aOut.mRemoteInfo); + break; + case PROPERTY_REMOTE_DEVICE_TIMESTAMP: + /* nothing to do */ + break; + default: + /* mismatch with type conversion */ + NS_NOTREACHED("Unhandled property type"); + break; + } + if (NS_FAILED(rv)) { + return rv; + } + return NS_OK; +} + // // Result handling // @@ -2430,6 +2734,232 @@ DispatchBluetoothResult(BluetoothResultHandler* aRes, return rv; } +// Notification handling +// + +BluetoothNotificationHandler::~BluetoothNotificationHandler() +{ } + +static BluetoothNotificationHandler* sNotificationHandler; + +struct BluetoothCallback +{ + class NotificationHandlerWrapper + { + public: + typedef BluetoothNotificationHandler ObjectType; + + static ObjectType* GetInstance() + { + MOZ_ASSERT(NS_IsMainThread()); + + return sNotificationHandler; + } + }; + + // Notifications + + typedef BluetoothNotificationRunnable1 + AdapterStateChangedNotification; + + typedef BluetoothNotificationRunnable3, + BluetoothStatus, int, + const BluetoothProperty*> + AdapterPropertiesNotification; + + typedef BluetoothNotificationRunnable4, + BluetoothStatus, const nsAString&, + int, const BluetoothProperty*> + RemoteDevicePropertiesNotification; + + typedef BluetoothNotificationRunnable2, + int, const BluetoothProperty*> + DeviceFoundNotification; + + typedef BluetoothNotificationRunnable1 + DiscoveryStateChangedNotification; + + typedef BluetoothNotificationRunnable3 + PinRequestNotification; + + typedef BluetoothNotificationRunnable5 + SspRequestNotification; + + typedef BluetoothNotificationRunnable3 + BondStateChangedNotification; + + typedef BluetoothNotificationRunnable3 + AclStateChangedNotification; + + typedef BluetoothNotificationRunnable3, + uint8_t, uint16_t, const uint8_t*> + DutModeRecvNotification; + + typedef BluetoothNotificationRunnable2 + LeTestModeNotification; + + // Bluedroid callbacks + + static const bt_property_t* + AlignedProperties(bt_property_t* aProperties, size_t aNumProperties, + nsAutoArrayPtr& aPropertiesArray) + { + // See Bug 989976: consider aProperties address is not aligned. If + // it is aligned, we return the pointer directly; otherwise we make + // an aligned copy. The argument |aPropertiesArray| keeps track of + // the memory buffer. + if (!(reinterpret_cast(aProperties) % sizeof(void*))) { + return aProperties; + } + + bt_property_t* properties = new bt_property_t[aNumProperties]; + memcpy(properties, aProperties, aNumProperties * sizeof(*properties)); + aPropertiesArray = properties; + + return properties; + } + + static void + AdapterStateChanged(bt_state_t aStatus) + { + AdapterStateChangedNotification::Dispatch( + &BluetoothNotificationHandler::AdapterStateChangedNotification, + aStatus); + } + + static void + AdapterProperties(bt_status_t aStatus, int aNumProperties, + bt_property_t* aProperties) + { + nsAutoArrayPtr propertiesArray; + + AdapterPropertiesNotification::Dispatch( + &BluetoothNotificationHandler::AdapterPropertiesNotification, + ConvertDefault(aStatus, STATUS_FAIL), aNumProperties, + ConvertArray( + AlignedProperties(aProperties, aNumProperties, propertiesArray), + aNumProperties)); + } + + static void + RemoteDeviceProperties(bt_status_t aStatus, bt_bdaddr_t* aBdAddress, + int aNumProperties, bt_property_t* aProperties) + { + nsAutoArrayPtr propertiesArray; + + RemoteDevicePropertiesNotification::Dispatch( + &BluetoothNotificationHandler::RemoteDevicePropertiesNotification, + ConvertDefault(aStatus, STATUS_FAIL), aBdAddress, aNumProperties, + ConvertArray( + AlignedProperties(aProperties, aNumProperties, propertiesArray), + aNumProperties)); + } + + static void + DeviceFound(int aNumProperties, bt_property_t* aProperties) + { + nsAutoArrayPtr propertiesArray; + + DeviceFoundNotification::Dispatch( + &BluetoothNotificationHandler::DeviceFoundNotification, + aNumProperties, + ConvertArray( + AlignedProperties(aProperties, aNumProperties, propertiesArray), + aNumProperties)); + } + + static void + DiscoveryStateChanged(bt_discovery_state_t aState) + { + DiscoveryStateChangedNotification::Dispatch( + &BluetoothNotificationHandler::DiscoveryStateChangedNotification, + aState); + } + + static void + PinRequest(bt_bdaddr_t* aRemoteBdAddress, + bt_bdname_t* aRemoteBdName, uint32_t aRemoteClass) + { + PinRequestNotification::Dispatch( + &BluetoothNotificationHandler::PinRequestNotification, + aRemoteBdAddress, aRemoteBdName, aRemoteClass); + } + + static void + SspRequest(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName, + uint32_t aRemoteClass, bt_ssp_variant_t aPairingVariant, + uint32_t aPasskey) + { + SspRequestNotification::Dispatch( + &BluetoothNotificationHandler::SspRequestNotification, + aRemoteBdAddress, aRemoteBdName, aRemoteClass, + aPairingVariant, aPasskey); + } + + static void + BondStateChanged(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, + bt_bond_state_t aState) + { + BondStateChangedNotification::Dispatch( + &BluetoothNotificationHandler::BondStateChangedNotification, + aStatus, aRemoteBdAddress, aState); + } + + static void + AclStateChanged(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, + bt_acl_state_t aState) + { + AclStateChangedNotification::Dispatch( + &BluetoothNotificationHandler::AclStateChangedNotification, + aStatus, aRemoteBdAddress, aState); + } + + static void + ThreadEvt(bt_cb_thread_evt evt) + { + // This callback maintains internal state and is not exported. + } + + static void + DutModeRecv(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen) + { + DutModeRecvNotification::Dispatch( + &BluetoothNotificationHandler::DutModeRecvNotification, + aOpcode, ConvertArray(aBuf, aLen), aLen); + } + + static void + LeTestMode(bt_status_t aStatus, uint16_t aNumPackets) + { + LeTestModeNotification::Dispatch( + &BluetoothNotificationHandler::LeTestModeNotification, + aStatus, aNumPackets); + } +}; + +// Interface +// + /* returns the container structure of a variable; _t is the container's * type, _v the name of the variable, and _m is _v's field within _t */ diff --git a/dom/bluetooth2/bluedroid/BluetoothInterface.h b/dom/bluetooth2/bluedroid/BluetoothInterface.h index 3720e33e73e..b95a1ceaf99 100644 --- a/dom/bluetooth2/bluedroid/BluetoothInterface.h +++ b/dom/bluetooth2/bluedroid/BluetoothInterface.h @@ -326,6 +326,50 @@ private: // Bluetooth Core Interface // +class BluetoothNotificationHandler +{ +public: + virtual ~BluetoothNotificationHandler(); + + virtual void AdapterStateChangedNotification(bool aState) { } + virtual void AdapterPropertiesNotification( + BluetoothStatus aStatus, int aNumProperties, + const BluetoothProperty* aProperties) { } + + virtual void RemoteDevicePropertiesNotification( + BluetoothStatus aStatus, const nsAString& aBdAddr, + int aNumProperties, const BluetoothProperty* aProperties) { } + + virtual void DeviceFoundNotification( + int aNumProperties, const BluetoothProperty* aProperties) { } + + virtual void DiscoveryStateChangedNotification(bool aState) { } + + virtual void PinRequestNotification(const nsAString& aRemoteBdAddr, + const nsAString& aBdName, uint32_t aCod) { } + virtual void SspRequestNotification(const nsAString& aRemoteBdAddr, + const nsAString& aBdName, + uint32_t aCod, + BluetoothSspVariant aPairingVariant, + uint32_t aPassKey) { } + + virtual void BondStateChangedNotification(BluetoothStatus aStatus, + const nsAString& aRemoteBdAddr, + BluetoothBondState aState) { } + virtual void AclStateChangedNotification(BluetoothStatus aStatus, + const nsAString& aRemoteBdAddr, + bool aState) { } + + virtual void DutModeRecvNotification(uint16_t aOpcode, + const uint8_t* aBuf, uint8_t aLen) { } + virtual void LeTestModeNotification(BluetoothStatus aStatus, + uint16_t aNumPackets) { } + +protected: + BluetoothNotificationHandler() + { } +}; + class BluetoothResultHandler { public: