Bug 1054242: Implement Bluetooth Core notifications (under bluetooth2/), r=btian
authorThomas Zimmermann <tdz@users.sourceforge.net>
Tue, 02 Sep 2014 12:38:45 +0200
changeset 226214 a9d8bf297d25c93e6ac7db3adad2a9b2d8b2d575
parent 226213 4a6fbb0366916d142c5b54bbc12b877644ba3340
child 226215 d057f561350c70317643ca101f1ce7987aff134f
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbtian
bugs1054242
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1054242: Implement Bluetooth Core notifications (under bluetooth2/), r=btian This patch adds the Gecko-side of the Core notifications. The current implementation of the notification methods has been copied from the repsective Bluedroid callback methods, with only minor changes to adapt them to Gecko data types.
dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.h
dom/bluetooth2/bluedroid/BluetoothUtils.cpp
dom/bluetooth2/bluedroid/BluetoothUtils.h
--- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
@@ -15,17 +15,16 @@
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 #include "BluetoothServiceBluedroid.h"
 
 #include "BluetoothA2dpManager.h"
 #include "BluetoothHfpManager.h"
-#include "BluetoothInterface.h"
 #include "BluetoothOppManager.h"
 #include "BluetoothProfileController.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuid.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/ipc/UnixSocket.h"
 #include "mozilla/StaticMutex.h"
@@ -337,17 +336,17 @@ public:
     }
 
     return NS_OK;
   }
 };
 
 /**
  * AdapterPropertiesCallback will be called after enable() but before
- * AdapterStateChangeCallback is called. At that moment, both
+ * AdapterStateChangedCallback is called. At that moment, both
  * BluetoothManager/BluetoothAdapter does not register observer yet.
  */
 static void
 AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
                           bt_property_t *aProperties)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
@@ -1774,8 +1773,372 @@ void
 BluetoothServiceBluedroid::IgnoreWaitingCall(BluetoothReplyRunnable* aRunnable)
 {
 }
 
 void
 BluetoothServiceBluedroid::ToggleCalls(BluetoothReplyRunnable* aRunnable)
 {
 }
+
+//
+// Bluetooth notifications
+//
+
+void
+BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  BT_LOGR("BT_STATE: %d", aState);
+
+  sAdapterEnabled = aState;
+
+  if (!sAdapterEnabled &&
+      NS_FAILED(NS_DispatchToMainThread(new CleanupTask()))) {
+    BT_WARNING("Failed to dispatch to main thread!");
+    return;
+  }
+
+  nsRefPtr<nsRunnable> runnable =
+    new BluetoothService::ToggleBtAck(sAdapterEnabled);
+  if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
+    BT_WARNING("Failed to dispatch to main thread!");
+    return;
+  }
+
+  if (sAdapterEnabled &&
+      NS_FAILED(NS_DispatchToMainThread(new SetupAfterEnabledTask()))) {
+    BT_WARNING("Failed to dispatch to main thread!");
+    return;
+  }
+
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(new AdapterStateChangedCallbackTask());
+}
+
+/**
+ * AdapterPropertiesNotification will be called after enable() but
+ * before AdapterStateChangeNotification is called. At that moment,
+ * BluetoothManager and BluetoothAdapter, do not register observer
+ * yet.
+ */
+void
+BluetoothServiceBluedroid::AdapterPropertiesNotification(
+  BluetoothStatus aStatus, int aNumProperties,
+  const BluetoothProperty* aProperties)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  InfallibleTArray<BluetoothNamedValue> propertiesArray;
+
+  for (int i = 0; i < aNumProperties; i++) {
+
+    const BluetoothProperty& p = aProperties[i];
+
+    if (p.mType == PROPERTY_BDADDR) {
+      sAdapterBdAddress = p.mString;
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Address", sAdapterBdAddress);
+
+    } else if (p.mType == PROPERTY_BDNAME) {
+      sAdapterBdName = p.mString;
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Name", sAdapterBdName);
+
+    } else if (p.mType == PROPERTY_ADAPTER_SCAN_MODE) {
+      sAdapterDiscoverable =
+        (p.mScanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Discoverable",
+                            sAdapterDiscoverable);
+
+    } else if (p.mType == PROPERTY_ADAPTER_BONDED_DEVICES) {
+      // We have to cache addresses of bonded devices. Unlike BlueZ,
+      // Bluedroid would not send another PROPERTY_ADAPTER_BONDED_DEVICES
+      // event after bond completed.
+      BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d",
+              p.mStringArray.Length());
+
+      nsTArray<nsString> pairedDeviceAddresses;
+      for (size_t index = 0; index < p.mStringArray.Length(); index++) {
+        pairedDeviceAddresses.AppendElement(p.mStringArray[index]);
+      }
+
+      BT_APPEND_NAMED_VALUE(propertiesArray, "PairedDevices", pairedDeviceAddresses);
+
+    } else {
+      BT_LOGD("Unhandled adapter property type: %d", p.mType);
+      continue;
+    }
+  }
+
+  NS_ENSURE_TRUE_VOID(propertiesArray.Length() > 0);
+
+  BluetoothValue value(propertiesArray);
+  BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
+                         NS_LITERAL_STRING(KEY_ADAPTER), value);
+  nsRefPtr<DistributeBluetoothSignalTask>
+    t = new DistributeBluetoothSignalTask(signal);
+  if (NS_FAILED(NS_DispatchToMainThread(t))) {
+    BT_WARNING("Failed to dispatch to main thread!");
+  }
+
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(new AdapterPropertiesCallbackTask());
+}
+
+/**
+ * RemoteDevicePropertiesNotification will be called
+ *
+ *   (1) automatically by Bluedroid when BT is turning on,
+ *   (2) as result of GetRemoteDeviceProperties, or
+ *   (3) as result of GetRemoteServices.
+ */
+void
+BluetoothServiceBluedroid::RemoteDevicePropertiesNotification(
+  BluetoothStatus aStatus, const nsAString& aBdAddr,
+  int aNumProperties, const BluetoothProperty* aProperties)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  InfallibleTArray<BluetoothNamedValue> propertiesArray;
+
+  BT_APPEND_NAMED_VALUE(propertiesArray, "Address", nsString(aBdAddr));
+
+  for (int i = 0; i < aNumProperties; ++i) {
+
+    const BluetoothProperty& p = aProperties[i];
+
+    if (p.mType == PROPERTY_BDNAME) {
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Name", p.mString);
+
+    } else if (p.mType == PROPERTY_CLASS_OF_DEVICE) {
+      uint32_t cod = p.mUint32;
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Cod", cod);
+
+    } else if (p.mType == PROPERTY_UUIDS) {
+      nsTArray<nsString> uuids;
+
+      // Construct a sorted uuid set
+      for (uint32_t index = 0; index < p.mUuidArray.Length(); ++index) {
+        nsAutoString uuid;
+        UuidToString(p.mUuidArray[index], uuid);
+
+        if (!uuids.Contains(uuid)) { // filter out duplicate uuids
+          uuids.InsertElementSorted(uuid);
+        }
+      }
+      BT_APPEND_NAMED_VALUE(propertiesArray, "UUIDs", uuids);
+
+    } else {
+      BT_LOGD("Other non-handled device properties. Type: %d", p.mType);
+    }
+  }
+
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(
+    new RemoteDevicePropertiesCallbackTask(propertiesArray, aBdAddr));
+}
+
+void
+BluetoothServiceBluedroid::DeviceFoundNotification(
+  int aNumProperties, const BluetoothProperty* aProperties)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  BluetoothValue propertyValue;
+  InfallibleTArray<BluetoothNamedValue> propertiesArray;
+
+  for (int i = 0; i < aNumProperties; i++) {
+
+    const BluetoothProperty& p = aProperties[i];
+
+    if (p.mType == PROPERTY_BDADDR) {
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Address", p.mString);
+
+    } else if (p.mType == PROPERTY_BDNAME) {
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Name", p.mString);
+
+    } else if (p.mType == PROPERTY_CLASS_OF_DEVICE) {
+      BT_APPEND_NAMED_VALUE(propertiesArray, "Cod", p.mUint32);
+
+    } else if (p.mType == PROPERTY_UUIDS) {
+      nsTArray<nsString> uuids;
+
+      // Construct a sorted uuid set
+      for (uint32_t index = 0; index < p.mUuidArray.Length(); ++index) {
+        nsAutoString uuid;
+        UuidToString(p.mUuidArray[index], uuid);
+
+        if (!uuids.Contains(uuid)) { // filter out duplicate uuids
+          uuids.InsertElementSorted(uuid);
+        }
+      }
+      BT_APPEND_NAMED_VALUE(propertiesArray, "UUIDs", uuids);
+
+    } else {
+      BT_LOGD("Not handled remote device property: %d", p.mType);
+    }
+  }
+
+  BluetoothValue value = propertiesArray;
+  BluetoothSignal signal(NS_LITERAL_STRING("DeviceFound"),
+                         NS_LITERAL_STRING(KEY_ADAPTER), value);
+  nsRefPtr<DistributeBluetoothSignalTask>
+    t = new DistributeBluetoothSignalTask(signal);
+  if (NS_FAILED(NS_DispatchToMainThread(t))) {
+    BT_WARNING("Failed to dispatch to main thread!");
+  }
+}
+
+void
+BluetoothServiceBluedroid::DiscoveryStateChangedNotification(bool aState)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  sAdapterDiscovering = aState;
+
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(new DiscoveryStateChangedCallbackTask());
+}
+
+void
+BluetoothServiceBluedroid::PinRequestNotification(const nsAString& aRemoteBdAddr,
+                                                  const nsAString& aBdName,
+                                                  uint32_t aCod)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  InfallibleTArray<BluetoothNamedValue> propertiesArray;
+
+  BT_APPEND_NAMED_VALUE(propertiesArray, "address", nsString(aRemoteBdAddr));
+  BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", EmptyString());
+  BT_APPEND_NAMED_VALUE(propertiesArray, "type",
+                        NS_LITERAL_STRING(PAIRING_REQ_TYPE_ENTERPINCODE));
+
+  BluetoothSignal signal(NS_LITERAL_STRING("PairingRequest"),
+                         NS_LITERAL_STRING(KEY_ADAPTER),
+                         BluetoothValue(propertiesArray));
+
+  nsRefPtr<DistributeBluetoothSignalTask> task =
+    new DistributeBluetoothSignalTask(signal);
+  if (NS_FAILED(NS_DispatchToMainThread(task))) {
+    BT_WARNING("Failed to dispatch to main thread!");
+  }
+}
+
+void
+BluetoothServiceBluedroid::SspRequestNotification(
+  const nsAString& aRemoteBdAddr, const nsAString& aBdName, uint32_t aCod,
+  BluetoothSspVariant aPairingVariant, uint32_t aPasskey)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  InfallibleTArray<BluetoothNamedValue> propertiesArray;
+  nsAutoString passkey;
+  nsAutoString pairingType;
+
+  /**
+   * Assign pairing request type and passkey based on the pairing variant.
+   *
+   * passkey value based on pairing request type:
+   * 1) aPasskey: PAIRING_REQ_TYPE_CONFIRMATION and
+   *              PAIRING_REQ_TYPE_DISPLAYPASSKEY
+   * 2) empty string: PAIRING_REQ_TYPE_CONSENT
+   */
+  switch (aPairingVariant) {
+    case SSP_VARIANT_PASSKEY_CONFIRMATION:
+      pairingType.AssignLiteral(PAIRING_REQ_TYPE_CONFIRMATION);
+      passkey.AppendInt(aPasskey);
+      break;
+    case SSP_VARIANT_PASSKEY_NOTIFICATION:
+      pairingType.AssignLiteral(PAIRING_REQ_TYPE_DISPLAYPASSKEY);
+      passkey.AppendInt(aPasskey);
+      break;
+    case SSP_VARIANT_CONSENT:
+      pairingType.AssignLiteral(PAIRING_REQ_TYPE_CONSENT);
+      break;
+    default:
+      BT_WARNING("Unhandled SSP Bonding Variant: %d", aPairingVariant);
+      return;
+  }
+
+  BT_APPEND_NAMED_VALUE(propertiesArray, "address", nsString(aRemoteBdAddr));
+  BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", passkey);
+  BT_APPEND_NAMED_VALUE(propertiesArray, "type", pairingType);
+
+  BluetoothSignal signal(NS_LITERAL_STRING("PairingRequest"),
+                         NS_LITERAL_STRING(KEY_ADAPTER),
+                         BluetoothValue(propertiesArray));
+
+  nsRefPtr<DistributeBluetoothSignalTask> task =
+    new DistributeBluetoothSignalTask(signal);
+  if (NS_FAILED(NS_DispatchToMainThread(task))) {
+    BT_WARNING("Failed to dispatch to main thread!");
+  }
+}
+
+void
+BluetoothServiceBluedroid::BondStateChangedNotification(
+  BluetoothStatus aStatus, const nsAString& aRemoteBdAddr,
+  BluetoothBondState aState)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (aState == BOND_STATE_BONDING) {
+    // No need to handle bonding state
+    return;
+  }
+
+  bool bonded = (aState == BOND_STATE_BONDED);
+
+  // Update attribute BluetoothDevice.paired
+  InfallibleTArray<BluetoothNamedValue> propertiesArray;
+  BT_APPEND_NAMED_VALUE(propertiesArray, "Paired", bonded);
+
+  BluetoothSignal deviceSignal(NS_LITERAL_STRING("PropertyChanged"),
+                               nsString(aRemoteBdAddr),
+                               BluetoothValue(propertiesArray));
+  NS_DispatchToMainThread(new DistributeBluetoothSignalTask(deviceSignal));
+
+  propertiesArray.Clear();
+
+  // Append signal properties and notify adapter.
+  BT_APPEND_NAMED_VALUE(propertiesArray, "Address", nsString(aRemoteBdAddr));
+  BT_APPEND_NAMED_VALUE(propertiesArray, "Paired", bonded);
+
+  nsString signalName = bonded ? NS_LITERAL_STRING(DEVICE_PAIRED_ID)
+                               : NS_LITERAL_STRING(DEVICE_UNPAIRED_ID);
+
+  BluetoothSignal adapterSignal(signalName,
+                                NS_LITERAL_STRING(KEY_ADAPTER),
+                                BluetoothValue(propertiesArray));
+  NS_DispatchToMainThread(new DistributeBluetoothSignalTask(adapterSignal));
+
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(new BondStateChangedCallbackTask(bonded));
+}
+
+void
+BluetoothServiceBluedroid::AclStateChangedNotification(
+  BluetoothStatus aStatus, const nsAString& aRemoteBdAddr, bool aState)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // FIXME: This will be implemented in the later patchset
+}
+
+void
+BluetoothServiceBluedroid::DutModeRecvNotification(uint16_t aOpcode,
+                                                   const uint8_t* aBuf,
+                                                   uint8_t aLen)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // FIXME: This will be implemented in the later patchset
+}
+
+void
+BluetoothServiceBluedroid::LeTestModeNotification(BluetoothStatus aStatus,
+                                                  uint16_t aNumPackets)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // FIXME: This will be implemented in the later patchset
+}
--- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.h
+++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.h
@@ -5,21 +5,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluetoothservicebluedroid_h__
 #define mozilla_dom_bluetooth_bluetoothservicebluedroid_h__
 
 #include <hardware/bluetooth.h>
 
 #include "BluetoothCommon.h"
+#include "BluetoothInterface.h"
 #include "BluetoothService.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothServiceBluedroid : public BluetoothService
+                                , public BluetoothNotificationHandler
 {
 public:
   static const bt_interface_t* GetBluetoothInterface();
 
   BluetoothServiceBluedroid();
   ~BluetoothServiceBluedroid();
 
   virtual nsresult StartInternal(BluetoothReplyRunnable* aRunnable);
@@ -150,14 +152,54 @@ public:
 
   virtual nsresult
   SendSinkMessage(const nsAString& aDeviceAddresses,
                   const nsAString& aMessage) MOZ_OVERRIDE;
 
   virtual nsresult
   SendInputMessage(const nsAString& aDeviceAddresses,
                    const nsAString& aMessage) MOZ_OVERRIDE;
+
+  //
+  // Bluetooth notifications
+  //
+
+  virtual void AdapterStateChangedNotification(bool aState) MOZ_OVERRIDE;
+  virtual void AdapterPropertiesNotification(
+    BluetoothStatus aStatus, int aNumProperties,
+    const BluetoothProperty* aProperties) MOZ_OVERRIDE;
+
+  virtual void RemoteDevicePropertiesNotification(
+    BluetoothStatus aStatus, const nsAString& aBdAddr,
+    int aNumProperties, const BluetoothProperty* aProperties) MOZ_OVERRIDE;
+
+  virtual void DeviceFoundNotification(
+    int aNumProperties, const BluetoothProperty* aProperties) MOZ_OVERRIDE;
+
+  virtual void DiscoveryStateChangedNotification(bool aState) MOZ_OVERRIDE;
+
+  virtual void PinRequestNotification(const nsAString& aRemoteBdAddr,
+                                      const nsAString& aBdName,
+                                      uint32_t aCod) MOZ_OVERRIDE;
+  virtual void SspRequestNotification(const nsAString& aRemoteBdAddr,
+                                      const nsAString& aBdName,
+                                      uint32_t aCod,
+                                      BluetoothSspVariant aPairingVariant,
+                                      uint32_t aPasskey) MOZ_OVERRIDE;
+
+  virtual void BondStateChangedNotification(
+    BluetoothStatus aStatus, const nsAString& aRemoteBdAddr,
+    BluetoothBondState aState) MOZ_OVERRIDE;
+  virtual void AclStateChangedNotification(BluetoothStatus aStatus,
+                                           const nsAString& aRemoteBdAddr,
+                                           bool aState) MOZ_OVERRIDE;
+
+  virtual void DutModeRecvNotification(uint16_t aOpcode,
+                                       const uint8_t* aBuf,
+                                       uint8_t aLen) MOZ_OVERRIDE;
+  virtual void LeTestModeNotification(BluetoothStatus aStatus,
+                                      uint16_t aNumPackets) MOZ_OVERRIDE;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
 
--- a/dom/bluetooth2/bluedroid/BluetoothUtils.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothUtils.cpp
@@ -67,16 +67,39 @@ UuidToString(bt_uuid_t* aUuid, nsAString
           ntohl(uuid0), ntohs(uuid1),
           ntohs(uuid2), ntohs(uuid3),
           ntohl(uuid4), ntohs(uuid5));
 
   aString.Truncate();
   aString.AssignLiteral(uuidStr);
 }
 
+void
+UuidToString(const BluetoothUuid& aUuid, nsAString& aString)
+{
+  char uuidStr[37];
+  uint32_t uuid0, uuid4;
+  uint16_t uuid1, uuid2, uuid3, uuid5;
+
+  memcpy(&uuid0, &aUuid.mUuid[0], sizeof(uint32_t));
+  memcpy(&uuid1, &aUuid.mUuid[4], sizeof(uint16_t));
+  memcpy(&uuid2, &aUuid.mUuid[6], sizeof(uint16_t));
+  memcpy(&uuid3, &aUuid.mUuid[8], sizeof(uint16_t));
+  memcpy(&uuid4, &aUuid.mUuid[10], sizeof(uint32_t));
+  memcpy(&uuid5, &aUuid.mUuid[14], sizeof(uint16_t));
+
+  sprintf(uuidStr, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
+          ntohl(uuid0), ntohs(uuid1),
+          ntohs(uuid2), ntohs(uuid3),
+          ntohl(uuid4), ntohs(uuid5));
+
+  aString.Truncate();
+  aString.AssignLiteral(uuidStr);
+}
+
 bool
 SetJsObject(JSContext* aContext,
             const BluetoothValue& aValue,
             JS::Handle<JSObject*> aObj)
 {
   MOZ_ASSERT(aContext && aObj);
 
   if (aValue.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
--- a/dom/bluetooth2/bluedroid/BluetoothUtils.h
+++ b/dom/bluetooth2/bluedroid/BluetoothUtils.h
@@ -24,16 +24,19 @@ StringToBdAddressType(const nsAString& a
 
 void
 BdAddressTypeToString(bt_bdaddr_t* aBdAddressType,
                       nsAString& aRetBdAddress);
 
 void
 UuidToString(bt_uuid_t* aUuid, nsAString& aString);
 
+void
+UuidToString(const BluetoothUuid& aUuid, nsAString& aString);
+
 bool
 SetJsObject(JSContext* aContext,
             const BluetoothValue& aValue,
             JS::Handle<JSObject*> aObj);
 
 bool
 BroadcastSystemMessage(const nsAString& aType,
                        const BluetoothValue& aData);