Bug 1161945 - Fix empty characteristics and descriptors after searching services. f=elin, r=jocelyn
authorBruce Sun <brsun@mozilla.com>
Fri, 12 Jun 2015 10:44:57 +0800
changeset 248501 727d31bebaa9fee3a93175aa1cfbf0584e2e0b27
parent 248500 df92603690376825ad98c2c3157618409fda9ddd
child 248502 a79fc7f1c37d6fd90bafa8a45ad7954676a67d89
push id28897
push userryanvm@gmail.com
push dateFri, 12 Jun 2015 18:49:36 +0000
treeherdermozilla-central@0c3bca1b4935 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjocelyn
bugs1161945
milestone41.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 1161945 - Fix empty characteristics and descriptors after searching services. f=elin, r=jocelyn
dom/bluetooth/bluedroid/BluetoothGattManager.cpp
dom/bluetooth/bluetooth2/BluetoothGatt.cpp
dom/bluetooth/bluetooth2/BluetoothGatt.h
dom/bluetooth/bluetooth2/BluetoothGattCharacteristic.cpp
dom/bluetooth/bluetooth2/BluetoothGattCharacteristic.h
dom/bluetooth/bluetooth2/BluetoothGattService.cpp
dom/bluetooth/bluetooth2/BluetoothGattService.h
--- a/dom/bluetooth/bluedroid/BluetoothGattManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothGattManager.cpp
@@ -1637,23 +1637,25 @@ BluetoothGattManager::GetCharacteristicN
     // Get next characteristic of this service
     sBluetoothGattClientInterface->GetCharacteristic(
       aConnId,
       aServiceId,
       false,
       aCharId,
       new DiscoverResultHandler(client));
   } else { // all characteristics of this service are discovered
-    // Notify BluetoothGattService to create characteristics then proceed
-    nsString path;
-    GeneratePathFromGattId(aServiceId.mId, path);
+    // Notify BluetoothGatt to make BluetoothGattService create characteristics
+    // then proceed
+    nsTArray<BluetoothNamedValue> values;
+    BT_APPEND_NAMED_VALUE(values, "serviceId", aServiceId);
+    BT_APPEND_NAMED_VALUE(values, "characteristics", client->mCharacteristics);
 
     bs->DistributeSignal(NS_LITERAL_STRING("CharacteristicsDiscovered"),
-                         path,
-                         BluetoothValue(client->mCharacteristics));
+                         client->mAppUuid,
+                         BluetoothValue(values));
 
     ProceedDiscoverProcess(client, aServiceId);
   }
 }
 
 void
 BluetoothGattManager::GetDescriptorNotification(
   int aConnId, BluetoothGattStatus aStatus,
@@ -1681,23 +1683,26 @@ BluetoothGattManager::GetDescriptorNotif
     sBluetoothGattClientInterface->GetDescriptor(
       aConnId,
       aServiceId,
       aCharId,
       false,
       aDescriptorId,
       new DiscoverResultHandler(client));
   } else { // all descriptors of this characteristic are discovered
-    // Notify BluetoothGattCharacteristic to create descriptors then proceed
-    nsString path;
-    GeneratePathFromGattId(aCharId, path);
+    // Notify BluetoothGatt to make BluetoothGattCharacteristic create
+    // descriptors then proceed
+    nsTArray<BluetoothNamedValue> values;
+    BT_APPEND_NAMED_VALUE(values, "serviceId", aServiceId);
+    BT_APPEND_NAMED_VALUE(values, "characteristicId", aCharId);
+    BT_APPEND_NAMED_VALUE(values, "descriptors", client->mDescriptors);
 
     bs->DistributeSignal(NS_LITERAL_STRING("DescriptorsDiscovered"),
-                         path,
-                         BluetoothValue(client->mDescriptors));
+                         client->mAppUuid,
+                         BluetoothValue(values));
     client->mDescriptors.Clear();
 
     ProceedDiscoverProcess(client, aServiceId);
   }
 }
 
 void
 BluetoothGattManager::GetIncludedServiceNotification(
@@ -1724,23 +1729,26 @@ BluetoothGattManager::GetIncludedService
     // Get next included service of this service
     sBluetoothGattClientInterface->GetIncludedService(
       aConnId,
       aServiceId,
       false,
       aIncludedServId,
       new DiscoverResultHandler(client));
   } else { // all included services of this service are discovered
-    // Notify BluetoothGattService to create included services
-    nsString path;
-    GeneratePathFromGattId(aServiceId.mId, path);
+    // Notify BluetoothGatt to make BluetoothGattService create included
+    // services
+    nsTArray<BluetoothNamedValue> values;
+    BT_APPEND_NAMED_VALUE(values, "serviceId", aServiceId);
+    BT_APPEND_NAMED_VALUE(values, "includedServices",
+                          client->mIncludedServices);
 
     bs->DistributeSignal(NS_LITERAL_STRING("IncludedServicesDiscovered"),
-                         path,
-                         BluetoothValue(client->mIncludedServices));
+                         client->mAppUuid,
+                         BluetoothValue(values));
     client->mIncludedServices.Clear();
 
     // Start to discover characteristics of this service
     sBluetoothGattClientInterface->GetCharacteristic(
       aConnId,
       aServiceId,
       true, // first characteristic
       BluetoothGattId(),
--- a/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
@@ -277,16 +277,87 @@ BluetoothGatt::HandleServicesDiscovered(
     mServices.AppendElement(new BluetoothGattService(
       GetParentObject(), mAppUuid, serviceIds[i]));
   }
 
   BluetoothGattBinding::ClearCachedServicesValue(this);
 }
 
 void
+BluetoothGatt::HandleIncludedServicesDiscovered(const BluetoothValue& aValue)
+{
+  MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
+
+  const InfallibleTArray<BluetoothNamedValue>& values =
+    aValue.get_ArrayOfBluetoothNamedValue();
+  MOZ_ASSERT(values.Length() == 2); // ServiceId, IncludedServices
+  MOZ_ASSERT(values[0].name().EqualsLiteral("serviceId"));
+  MOZ_ASSERT(values[0].value().type() ==
+             BluetoothValue::TBluetoothGattServiceId);
+  MOZ_ASSERT(values[1].name().EqualsLiteral("includedServices"));
+  MOZ_ASSERT(values[1].value().type() ==
+             BluetoothValue::TArrayOfBluetoothGattServiceId);
+
+  size_t index = mServices.IndexOf(
+    values[0].value().get_BluetoothGattServiceId());
+  NS_ENSURE_TRUE_VOID(index != mServices.NoIndex);
+
+  nsRefPtr<BluetoothGattService> service = mServices.ElementAt(index);
+  service->AssignIncludedServices(
+    values[1].value().get_ArrayOfBluetoothGattServiceId());
+}
+
+void
+BluetoothGatt::HandleCharacteristicsDiscovered(const BluetoothValue& aValue)
+{
+  MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
+
+  const InfallibleTArray<BluetoothNamedValue>& values =
+    aValue.get_ArrayOfBluetoothNamedValue();
+  MOZ_ASSERT(values.Length() == 2); // ServiceId, Characteristics
+  MOZ_ASSERT(values[0].name().EqualsLiteral("serviceId"));
+  MOZ_ASSERT(values[0].value().type() == BluetoothValue::TBluetoothGattServiceId);
+  MOZ_ASSERT(values[1].name().EqualsLiteral("characteristics"));
+  MOZ_ASSERT(values[1].value().type() ==
+             BluetoothValue::TArrayOfBluetoothGattCharAttribute);
+
+  size_t index = mServices.IndexOf(
+    values[0].value().get_BluetoothGattServiceId());
+  NS_ENSURE_TRUE_VOID(index != mServices.NoIndex);
+
+  nsRefPtr<BluetoothGattService> service = mServices.ElementAt(index);
+  service->AssignCharacteristics(
+    values[1].value().get_ArrayOfBluetoothGattCharAttribute());
+}
+
+void
+BluetoothGatt::HandleDescriptorsDiscovered(const BluetoothValue& aValue)
+{
+  MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
+
+  const InfallibleTArray<BluetoothNamedValue>& values =
+    aValue.get_ArrayOfBluetoothNamedValue();
+  MOZ_ASSERT(values.Length() == 3); // ServiceId, CharacteristicId, Descriptors
+  MOZ_ASSERT(values[0].name().EqualsLiteral("serviceId"));
+  MOZ_ASSERT(values[0].value().type() == BluetoothValue::TBluetoothGattServiceId);
+  MOZ_ASSERT(values[1].name().EqualsLiteral("characteristicId"));
+  MOZ_ASSERT(values[1].value().type() == BluetoothValue::TBluetoothGattId);
+  MOZ_ASSERT(values[2].name().EqualsLiteral("descriptors"));
+  MOZ_ASSERT(values[2].value().type() == BluetoothValue::TArrayOfBluetoothGattId);
+
+  size_t index = mServices.IndexOf(
+    values[0].value().get_BluetoothGattServiceId());
+  NS_ENSURE_TRUE_VOID(index != mServices.NoIndex);
+
+  nsRefPtr<BluetoothGattService> service = mServices.ElementAt(index);
+  service->AssignDescriptors(values[1].value().get_BluetoothGattId(),
+                             values[2].value().get_ArrayOfBluetoothGattId());
+}
+
+void
 BluetoothGatt::HandleCharacteristicChanged(const BluetoothValue& aValue)
 {
   MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
 
   const InfallibleTArray<BluetoothNamedValue>& ids =
     aValue.get_ArrayOfBluetoothNamedValue();
   MOZ_ASSERT(ids.Length() == 2); // ServiceId, CharId
   MOZ_ASSERT(ids[0].name().EqualsLiteral("serviceId"));
@@ -343,16 +414,22 @@ BluetoothGatt::Notify(const BluetoothSig
 
     bool isDiscoverSuccess = v.get_bool();
     if (!isDiscoverSuccess) { // Clean all discovered attributes if failed
       mServices.Clear();
       BluetoothGattBinding::ClearCachedServicesValue(this);
     }
 
     mDiscoveringServices = false;
+  } else if (aData.name().EqualsLiteral("IncludedServicesDiscovered")) {
+    HandleIncludedServicesDiscovered(v);
+  } else if (aData.name().EqualsLiteral("CharacteristicsDiscovered")) {
+    HandleCharacteristicsDiscovered(v);
+  } else if (aData.name().EqualsLiteral("DescriptorsDiscovered")) {
+    HandleDescriptorsDiscovered(v);
   } else if (aData.name().EqualsLiteral(GATT_CHARACTERISTIC_CHANGED_ID)) {
     HandleCharacteristicChanged(v);
   } else {
     BT_WARNING("Not handling GATT signal: %s",
                NS_ConvertUTF16toUTF8(aData.name()).get());
   }
 }
 
--- a/dom/bluetooth/bluetooth2/BluetoothGatt.h
+++ b/dom/bluetooth/bluetooth2/BluetoothGatt.h
@@ -92,16 +92,60 @@ private:
    * value of mServices.
    *
    * @param aValue [in] BluetoothValue which contains an array of
    *                    BluetoothGattServiceId of all discovered services.
    */
   void HandleServicesDiscovered(const BluetoothValue& aValue);
 
   /**
+   * Add newly discovered GATT included services into mIncludedServices of
+   * BluetoothGattService and update the cache value of mIncludedServices.
+   *
+   * @param aValue [in] BluetoothValue which contains an array of
+   *                    BluetoothNamedValue. There are exact two elements in
+   *                    the array. The first element uses 'serviceId' as the
+   *                    name and uses BluetoothGattServiceId as the value. The
+   *                    second element uses 'includedServices' as the name and
+   *                    uses an array of BluetoothGattServiceId of all
+   *                    discovered included services as the value.
+   */
+  void HandleIncludedServicesDiscovered(const BluetoothValue& aValue);
+
+  /**
+   * Add newly discovered GATT characteristics into mCharacteristics of
+   * BluetoothGattService and update the cache value of mCharacteristics.
+   *
+   * @param aValue [in] BluetoothValue which contains an array of
+   *                    BluetoothNamedValue. There are exact two elements in
+   *                    the array. The first element uses 'serviceId' as the
+   *                    name and uses BluetoothGattServiceId as the value. The
+   *                    second element uses 'characteristics' as the name and
+   *                    uses an array of BluetoothGattCharAttribute of all
+   *                    discovered characteristics as the value.
+   */
+  void HandleCharacteristicsDiscovered(const BluetoothValue& aValue);
+
+  /**
+   * Add newly discovered GATT descriptors into mDescriptors of
+   * BluetoothGattCharacteristic and update the cache value of mDescriptors.
+   *
+   * @param aValue [in] BluetoothValue which contains an array of
+   *                    BluetoothNamedValue. There are exact three elements in
+   *                    the array. The first element uses 'serviceId' as the
+   *                    name and uses BluetoothGattServiceId as the value. The
+   *                    second element uses 'characteristicId' as the name and
+   *                    uses BluetoothGattId as the value. The third element
+   *                    uses 'descriptors' as the name and uses an array of
+   *                    BluetoothGattId of all discovered descriptors as the
+   *                    value.
+   */
+  void HandleDescriptorsDiscovered(const BluetoothValue& aValue);
+
+  /**
    * The value of a GATT characteristic has changed. In the mean time, the
    * cached value of this GATT characteristic has already been updated. An
    * 'characteristicchanged' event will be fired by this function.
    *
    * @param aValue [in] BluetoothValue which contains an array of
    *                    BluetoothNamedValue. There are exact two elements in
    *                    the array. The first element uses 'serviceId' as the
    *                    name and uses BluetoothGattServiceId as the value. The
--- a/dom/bluetooth/bluetooth2/BluetoothGattCharacteristic.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGattCharacteristic.cpp
@@ -137,28 +137,23 @@ BluetoothGattCharacteristic::StopNotific
                                           mService->GetServiceId(),
                                           mCharId,
                                           result);
 
   return promise.forget();
 }
 
 void
-BluetoothGattCharacteristic::HandleDescriptorsDiscovered(
-  const BluetoothValue& aValue)
+BluetoothGattCharacteristic::AssignDescriptors(
+  const nsTArray<BluetoothGattId>& aDescriptorIds)
 {
-  MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothGattId);
-
-  const InfallibleTArray<BluetoothGattId>& descriptorIds =
-    aValue.get_ArrayOfBluetoothGattId();
-
   mDescriptors.Clear();
-  for (uint32_t i = 0; i < descriptorIds.Length(); i++) {
+  for (uint32_t i = 0; i < aDescriptorIds.Length(); i++) {
     mDescriptors.AppendElement(new BluetoothGattDescriptor(
-      GetParentObject(), this, descriptorIds[i]));
+      GetParentObject(), this, aDescriptorIds[i]));
   }
 
   BluetoothGattCharacteristicBinding::ClearCachedDescriptorsValue(this);
 }
 
 void
 BluetoothGattCharacteristic::HandleCharacteristicValueUpdated(
   const BluetoothValue& aValue)
@@ -170,19 +165,17 @@ BluetoothGattCharacteristic::HandleChara
 
 void
 BluetoothGattCharacteristic::Notify(const BluetoothSignal& aData)
 {
   BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
   NS_ENSURE_TRUE_VOID(mSignalRegistered);
 
   BluetoothValue v = aData.value();
-  if (aData.name().EqualsLiteral("DescriptorsDiscovered")) {
-    HandleDescriptorsDiscovered(v);
-  } else if (aData.name().EqualsLiteral("CharacteristicValueUpdated")) {
+  if (aData.name().EqualsLiteral("CharacteristicValueUpdated")) {
     HandleCharacteristicValueUpdated(v);
   } else {
     BT_WARNING("Not handling GATT Characteristic signal: %s",
                NS_ConvertUTF16toUTF8(aData.name()).get());
   }
 }
 
 JSObject*
--- a/dom/bluetooth/bluetooth2/BluetoothGattCharacteristic.h
+++ b/dom/bluetooth/bluetooth2/BluetoothGattCharacteristic.h
@@ -27,16 +27,17 @@ BEGIN_BLUETOOTH_NAMESPACE
 class BluetoothGattService;
 class BluetoothSignal;
 class BluetoothValue;
 
 class BluetoothGattCharacteristic final : public nsISupports
                                         , public nsWrapperCache
                                         , public BluetoothSignalObserver
 {
+  friend class BluetoothGattService;
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BluetoothGattCharacteristic)
 
   /****************************************************************************
    * Attribute Getters
    ***************************************************************************/
   BluetoothGattService* Service() const
@@ -101,20 +102,20 @@ public:
 
 private:
   ~BluetoothGattCharacteristic();
 
   /**
    * Add newly discovered GATT descriptors into mDescriptors and update the
    * cache value of mDescriptors.
    *
-   * @param aValue [in] BluetoothValue which contains an array of
-   *                    BluetoothGattId of all discovered descriptors.
+   * @param aDescriptorIds [in] An array of BluetoothGattId for each descriptor
+   *                            that belongs to this characteristic.
    */
-  void HandleDescriptorsDiscovered(const BluetoothValue& aValue);
+  void AssignDescriptors(const nsTArray<BluetoothGattId>& aDescriptorIds);
 
   /**
    * Update the value of this characteristic.
    *
    * @param aValue [in] BluetoothValue which contains an uint8_t array.
    */
   void HandleCharacteristicValueUpdated(const BluetoothValue& aValue);
 
--- a/dom/bluetooth/bluetooth2/BluetoothGattService.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGattService.cpp
@@ -12,43 +12,20 @@
 #include "mozilla/dom/bluetooth/BluetoothGattService.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_BLUETOOTH_NAMESPACE
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothGattService)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BluetoothGattService)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncludedServices)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCharacteristics)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-
-  /**
-   * 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.
-   */
-  nsString path;
-  GeneratePathFromGattId(tmp->mServiceId.mId, path);
-  UnregisterBluetoothSignalHandler(path, tmp);
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BluetoothGattService)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncludedServices)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCharacteristics)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BluetoothGattService)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BluetoothGattService,
+                                      mOwner,
+                                      mIncludedServices,
+                                      mCharacteristics)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothGattService)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothGattService)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothGattService)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
@@ -58,82 +35,59 @@ BluetoothGattService::BluetoothGattServi
   : mOwner(aOwner)
   , mAppUuid(aAppUuid)
   , mServiceId(aServiceId)
 {
   MOZ_ASSERT(aOwner);
   MOZ_ASSERT(!mAppUuid.IsEmpty());
 
   UuidToString(mServiceId.mId.mUuid, mUuidStr);
-
-  // Generate bluetooth signal path of this service to applications
-  nsString path;
-  GeneratePathFromGattId(mServiceId.mId, path);
-  RegisterBluetoothSignalHandler(path, this);
 }
 
 BluetoothGattService::~BluetoothGattService()
 {
-  nsString path;
-  GeneratePathFromGattId(mServiceId.mId, path);
-  UnregisterBluetoothSignalHandler(path, this);
 }
 
 void
-BluetoothGattService::HandleIncludedServicesDiscovered(
-  const BluetoothValue& aValue)
+BluetoothGattService::AssignIncludedServices(
+  const nsTArray<BluetoothGattServiceId>& aServiceIds)
 {
-  MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothGattServiceId);
-
-  const InfallibleTArray<BluetoothGattServiceId>& includedServIds =
-    aValue.get_ArrayOfBluetoothGattServiceId();
-
   mIncludedServices.Clear();
-  for (uint32_t i = 0; i < includedServIds.Length(); i++) {
+  for (uint32_t i = 0; i < aServiceIds.Length(); i++) {
     mIncludedServices.AppendElement(new BluetoothGattService(
-      GetParentObject(), mAppUuid, includedServIds[i]));
+      GetParentObject(), mAppUuid, aServiceIds[i]));
   }
 
   BluetoothGattServiceBinding::ClearCachedIncludedServicesValue(this);
 }
 
 void
-BluetoothGattService::HandleCharacteristicsDiscovered(
-  const BluetoothValue& aValue)
+BluetoothGattService::AssignCharacteristics(
+  const nsTArray<BluetoothGattCharAttribute>& aCharacteristics)
 {
-  MOZ_ASSERT(aValue.type() ==
-             BluetoothValue::TArrayOfBluetoothGattCharAttribute);
-
-  const InfallibleTArray<BluetoothGattCharAttribute>& characteristics =
-    aValue.get_ArrayOfBluetoothGattCharAttribute();
-
   mCharacteristics.Clear();
-  for (uint32_t i = 0; i < characteristics.Length(); i++) {
+  for (uint32_t i = 0; i < aCharacteristics.Length(); i++) {
     mCharacteristics.AppendElement(new BluetoothGattCharacteristic(
-      GetParentObject(), this, characteristics[i]));
+      GetParentObject(), this, aCharacteristics[i]));
   }
 
   BluetoothGattServiceBinding::ClearCachedCharacteristicsValue(this);
 }
 
 void
-BluetoothGattService::Notify(const BluetoothSignal& aData)
+BluetoothGattService::AssignDescriptors(
+  const BluetoothGattId& aCharacteristicId,
+  const nsTArray<BluetoothGattId>& aDescriptorIds)
 {
-  BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
-  NS_ENSURE_TRUE_VOID(mSignalRegistered);
+  size_t index = mCharacteristics.IndexOf(aCharacteristicId);
+  NS_ENSURE_TRUE_VOID(index != mCharacteristics.NoIndex);
 
-  BluetoothValue v = aData.value();
-  if (aData.name().EqualsLiteral("IncludedServicesDiscovered")) {
-    HandleIncludedServicesDiscovered(v);
-  } else if (aData.name().EqualsLiteral("CharacteristicsDiscovered")) {
-    HandleCharacteristicsDiscovered(v);
-  } else {
-    BT_WARNING("Not handling GATT Service signal: %s",
-               NS_ConvertUTF16toUTF8(aData.name()).get());
-  }
+  nsRefPtr<BluetoothGattCharacteristic> characteristic =
+    mCharacteristics.ElementAt(index);
+  characteristic->AssignDescriptors(aDescriptorIds);
 }
 
 JSObject*
 BluetoothGattService::WrapObject(JSContext* aContext,
                                  JS::Handle<JSObject*> aGivenProto)
 {
   return BluetoothGattServiceBinding::Wrap(aContext, this, aGivenProto);
 }
--- a/dom/bluetooth/bluetooth2/BluetoothGattService.h
+++ b/dom/bluetooth/bluetooth2/BluetoothGattService.h
@@ -12,23 +12,24 @@
 #include "mozilla/dom/bluetooth/BluetoothCommon.h"
 #include "mozilla/dom/bluetooth/BluetoothGattCharacteristic.h"
 #include "nsCOMPtr.h"
 #include "nsWrapperCache.h"
 #include "nsPIDOMWindow.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
+class BluetoothGatt;
 class BluetoothSignal;
 class BluetoothValue;
 
 class BluetoothGattService final : public nsISupports
                                  , public nsWrapperCache
-                                 , public BluetoothSignalObserver
 {
+  friend class BluetoothGatt;
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BluetoothGattService)
 
   /****************************************************************************
    * Attribute Getters
    ***************************************************************************/
   bool IsPrimary() const
@@ -66,18 +67,16 @@ public:
     return mAppUuid;
   }
 
   const BluetoothGattServiceId& GetServiceId() const
   {
     return mServiceId;
   }
 
-  void Notify(const BluetoothSignal& aData); // BluetoothSignalObserver
-
   nsPIDOMWindow* GetParentObject() const
   {
      return mOwner;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
@@ -87,30 +86,46 @@ public:
 
 private:
   ~BluetoothGattService();
 
   /**
    * Add newly discovered GATT included services into mIncludedServices and
    * update the cache value of mIncludedServices.
    *
-   * @param aValue [in] BluetoothValue which contains an array of
-   *                    BluetoothGattServiceId of all discovered included
-   *                    services.
+   * @param aServiceIds [in] An array of BluetoothGattServiceId for each
+   *                         included service that belongs to this service.
    */
-  void HandleIncludedServicesDiscovered(const BluetoothValue& aValue);
+  void AssignIncludedServices(
+    const nsTArray<BluetoothGattServiceId>& aServiceIds);
 
   /**
    * Add newly discovered GATT characteristics into mCharacteristics and
    * update the cache value of mCharacteristics.
    *
-   * @param aValue [in] BluetoothValue which contains an array of
-   *                    BluetoothGattId of all discovered characteristics.
+   * @param aCharacteristics [in] An array of BluetoothGattCharAttribute for
+   *                              each characteristic that belongs to this
+   *                              service.
    */
-  void HandleCharacteristicsDiscovered(const BluetoothValue& aValue);
+  void AssignCharacteristics(
+    const nsTArray<BluetoothGattCharAttribute>& aCharacteristics);
+
+  /**
+   * Add newly discovered GATT descriptors into mDescriptors of
+   * BluetoothGattCharacteristic and update the cache value of mDescriptors.
+   *
+   * @param aCharacteristicId [in] BluetoothGattId of a characteristic that
+   *                               belongs to this service.
+   * @param aDescriptorIds [in] An array of BluetoothGattId for each descriptor
+   *                            that belongs to the characteristic referred by
+   *                            aCharacteristicId.
+   */
+  void AssignDescriptors(
+    const BluetoothGattId& aCharacteristicId,
+    const nsTArray<BluetoothGattId>& aDescriptorIds);
 
   /****************************************************************************
    * Variables
    ***************************************************************************/
   nsCOMPtr<nsPIDOMWindow> mOwner;
 
   /**
    * UUID of the GATT client.