Bug 1222956: Use |BluetoothUuid| in |BluetoothDiscoveryHandle|, r=tzimmermann
authorBruce Sun <brsun@mozilla.com>
Mon, 22 Feb 2016 11:41:07 +0800
changeset 285025 807683706e4ed63cd348a3c748bcc028cb4c3d3e
parent 285017 241581e67d7535834591ae9ec031e5f0f37f6210
child 285026 7d2bc215980907d791c942ae3b8783a97b060d34
push id30022
push usercbook@mozilla.com
push dateTue, 23 Feb 2016 15:52:25 +0000
treeherdermozilla-central@25697d503815 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstzimmermann
bugs1222956
milestone47.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 1222956: Use |BluetoothUuid| in |BluetoothDiscoveryHandle|, r=tzimmermann
dom/bluetooth/common/BluetoothCommon.cpp
dom/bluetooth/common/BluetoothCommon.h
dom/bluetooth/common/BluetoothUtils.cpp
dom/bluetooth/common/BluetoothUtils.h
dom/bluetooth/common/webapi/BluetoothAdapter.cpp
dom/bluetooth/common/webapi/BluetoothAdapter.h
dom/bluetooth/common/webapi/BluetoothDevice.cpp
dom/bluetooth/common/webapi/BluetoothDevice.h
dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.cpp
dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.h
--- a/dom/bluetooth/common/BluetoothCommon.cpp
+++ b/dom/bluetooth/common/BluetoothCommon.cpp
@@ -20,9 +20,32 @@ const BluetoothAddress BluetoothAddress:
                                              0x00, 0x00, 0x00);
 
 const BluetoothAddress BluetoothAddress::ALL(0xff, 0xff, 0xff,
                                              0xff, 0xff, 0xff);
 
 const BluetoothAddress BluetoothAddress::LOCAL(0x00, 0x00, 0x00,
                                                0xff, 0xff, 0xff);
 
+//
+// |BluetoothUuid|
+//
+
+const BluetoothUuid BluetoothUuid::ZERO(0x00, 0x00, 0x00, 0x00,
+                                        0x00, 0x00, 0x00, 0x00,
+                                        0x00, 0x00, 0x00, 0x00,
+                                        0x00, 0x00, 0x00, 0x00);
+
+/*
+ * [Bluetooth Specification Version 4.2, Volume 3, Part B, Section 2.5.1]
+ *
+ * To reduce the burden of storing and transferring 128-bit UUID values, a
+ * range of UUID values has been pre-allocated for assignment to often-used,
+ * registered purposes. The first UUID in this pre-allocated range is known as
+ * the Bluetooth Base UUID and has the value 00000000-0000-1000-8000-
+ * 00805F9B34FB, from the Bluetooth Assigned Numbers document.
+ */
+const BluetoothUuid BluetoothUuid::BASE(0x00, 0x00, 0x00, 0x00,
+                                        0x00, 0x00, 0x10, 0x00,
+                                        0x80, 0x00, 0x00, 0x80,
+                                        0x5f, 0x9b, 0x34, 0xfb);
+
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/common/BluetoothCommon.h
+++ b/dom/bluetooth/common/BluetoothCommon.h
@@ -545,21 +545,23 @@ enum BluetoothServiceClass {
   HID              = 0x1124,
   PBAP_PCE         = 0x112e,
   PBAP_PSE         = 0x112f,
   MAP_MAS          = 0x1132,
   MAP_MNS          = 0x1133
 };
 
 struct BluetoothUuid {
+  static const BluetoothUuid ZERO;
+  static const BluetoothUuid BASE;
 
-  uint8_t mUuid[16];
+  uint8_t mUuid[16];  // store 128-bit UUID value in big-endian order
 
   BluetoothUuid()
-    : BluetoothUuid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+    : BluetoothUuid(ZERO)
   { }
 
   MOZ_IMPLICIT BluetoothUuid(const BluetoothUuid&) = default;
 
   BluetoothUuid(uint8_t aUuid0, uint8_t aUuid1,
                 uint8_t aUuid2, uint8_t aUuid3,
                 uint8_t aUuid4, uint8_t aUuid5,
                 uint8_t aUuid6, uint8_t aUuid7,
@@ -603,73 +605,69 @@ struct BluetoothUuid {
 
   BluetoothUuid& operator=(const BluetoothUuid& aRhs) = default;
 
   /**
    * |Clear| assigns an invalid value (i.e., zero) to the UUID.
    */
   void Clear()
   {
-    operator=(BluetoothUuid());
+    operator=(ZERO);
   }
 
   /**
    * |IsCleared| returns true if the UUID contains a value of
    * zero.
    */
   bool IsCleared() const
   {
-    return operator==(BluetoothUuid());
+    return operator==(ZERO);
   }
 
   bool operator==(const BluetoothUuid& aRhs) const
   {
     return std::equal(aRhs.mUuid,
                       aRhs.mUuid + MOZ_ARRAY_LENGTH(aRhs.mUuid), mUuid);
   }
 
   bool operator!=(const BluetoothUuid& aRhs) const
   {
     return !operator==(aRhs);
   }
 
+  /* This less-than operator is used for sorted insertion of nsTArray */
+  bool operator<(const BluetoothUuid& aUuid) const
+  {
+    return memcmp(mUuid, aUuid.mUuid, sizeof(aUuid.mUuid)) < 0;
+  };
+
   /*
    * Getter-setter methods for short UUIDS. The first 4 bytes in the
    * UUID are represented by the short notation UUID32, and bytes 3
    * and 4 (indices 2 and 3) are represented by UUID16. The rest of
-   * the UUID is filled with the SDP base UUID.
+   * the UUID is filled with the Bluetooth Base UUID.
    *
    * Below are helpers for accessing these values.
    */
 
   void SetUuid32(uint32_t aUuid32)
   {
+    operator=(BASE);
     BigEndian::writeUint32(&mUuid[0], aUuid32);
-    mUuid[4] = 0x00;
-    mUuid[5] = 0x00;
-    mUuid[6] = 0x10;
-    mUuid[7] = 0x00;
-    mUuid[8] = 0x80;
-    mUuid[9] = 0x00;
-    mUuid[10] = 0x00;
-    mUuid[11] = 0x80;
-    mUuid[12] = 0x5f;
-    mUuid[13] = 0x9b;
-    mUuid[14] = 0x34;
-    mUuid[15] = 0xfb;
   }
 
   uint32_t GetUuid32() const
   {
     return BigEndian::readUint32(&mUuid[0]);
   }
 
   void SetUuid16(uint16_t aUuid16)
   {
-    SetUuid32(aUuid16); // MSB is 0x0000
+    operator=(BASE);
+    BigEndian::writeUint16(&mUuid[2], aUuid16);
   }
 
   uint16_t GetUuid16() const
   {
     return BigEndian::readUint16(&mUuid[2]);
   }
 };
 
--- a/dom/bluetooth/common/BluetoothUtils.cpp
+++ b/dom/bluetooth/common/BluetoothUtils.cpp
@@ -273,16 +273,96 @@ StringToUuid(const nsAString& aString, B
   memcpy(&aUuid.mUuid[8], &uuid3, sizeof(uint16_t));
   memcpy(&aUuid.mUuid[10], &uuid4, sizeof(uint32_t));
   memcpy(&aUuid.mUuid[14], &uuid5, sizeof(uint16_t));
 
   return NS_OK;
 }
 
 nsresult
+BytesToUuid(const nsTArray<uint8_t>& aArray,
+            nsTArray<uint8_t>::index_type aOffset,
+            BluetoothUuidType aType,
+            BluetoothProfileEndian aEndian,
+            BluetoothUuid& aUuid)
+{
+  MOZ_ASSERT(aType == UUID_16_BIT ||
+             aType == UUID_32_BIT ||
+             aType == UUID_128_BIT);
+  MOZ_ASSERT(aEndian == ENDIAN_BIG || aEndian == ENDIAN_LITTLE);
+
+  size_t index = (aType == UUID_16_BIT) ? 2 : 0;
+  size_t length = 0;
+
+  if (aType == UUID_16_BIT) {
+    length =  sizeof(uint16_t);
+  } else if (aType == UUID_32_BIT) {
+    length = sizeof(uint32_t);
+  } else {
+    length = MOZ_ARRAY_LENGTH(aUuid.mUuid);
+  }
+
+  if (aArray.Length() < aOffset + length) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  aUuid = BluetoothUuid::BASE;
+
+  if (aEndian == ENDIAN_BIG) {
+    for (size_t i = 0; i < length; ++i) {
+      aUuid.mUuid[index + i] = aArray[aOffset + i];
+    }
+  } else {
+    for (size_t i = 0; i < length; ++i) {
+      aUuid.mUuid[index + i] = aArray[aOffset + length - i - 1];
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
+UuidToBytes(const BluetoothUuid& aUuid,
+            BluetoothUuidType aType,
+            BluetoothProfileEndian aEndian,
+            nsTArray<uint8_t>& aArray,
+            nsTArray<uint8_t>::index_type aOffset)
+{
+  MOZ_ASSERT(aType == UUID_16_BIT ||
+             aType == UUID_32_BIT ||
+             aType == UUID_128_BIT);
+  MOZ_ASSERT(aEndian == ENDIAN_BIG || aEndian == ENDIAN_LITTLE);
+
+  size_t index = (aType == UUID_16_BIT) ? 2 : 0;
+  size_t length = 0;
+
+  if (aType == UUID_16_BIT) {
+    length =  sizeof(uint16_t);
+  } else if (aType == UUID_32_BIT) {
+    length = sizeof(uint32_t);
+  } else {
+    length = MOZ_ARRAY_LENGTH(aUuid.mUuid);
+  }
+
+  aArray.SetCapacity(aOffset + length);
+
+  if (aEndian == ENDIAN_BIG) {
+    for (size_t i = 0; i < length; ++i) {
+      aArray[aOffset + i] = aUuid.mUuid[index + i];
+    }
+  } else {
+    for (size_t i = 0; i < length; ++i) {
+      aArray[aOffset + length - i - 1] = aUuid.mUuid[index + i];
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
 GenerateUuid(BluetoothUuid &aUuid)
 {
   nsresult rv;
   nsCOMPtr<nsIUUIDGenerator> uuidGenerator =
     do_GetService("@mozilla.org/uuid-generator;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsID uuid;
--- a/dom/bluetooth/common/BluetoothUtils.h
+++ b/dom/bluetooth/common/BluetoothUtils.h
@@ -19,16 +19,40 @@ class BluetoothAdvertisingData;
 }
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothNamedValue;
 class BluetoothReplyRunnable;
 class BluetoothValue;
 
+/*
+ * Each profile has its distinct endianness for multi-byte values
+ */
+enum BluetoothProfileEndian {
+  ENDIAN_BIG,
+  ENDIAN_LITTLE,
+  ENDIAN_SDP      = ENDIAN_BIG,     // SDP uses big endian
+  ENDIAN_GAP      = ENDIAN_LITTLE,  // GAP uses little endian
+  ENDIAN_GATT     = ENDIAN_LITTLE,  // GATT uses little endian
+};
+
+/*
+ * A UUID is a 128-bit value. To reduce the burden of storing and transferring
+ * 128-bit UUID values, a range of UUID values has been pre-allocated for
+ * assignment to often-used, registered purposes. UUID values in the
+ * pre-allocated range have aliases that are represented as 16-bit or 32-bit
+ * values.
+ */
+enum BluetoothUuidType {
+  UUID_16_BIT,
+  UUID_32_BIT,
+  UUID_128_BIT,
+};
+
 //
 // Address/String conversion
 //
 
 void
 AddressToString(const BluetoothAddress& aAddress, nsAString& aString);
 
 nsresult
@@ -100,16 +124,46 @@ UuidToString(const BluetoothUuid& aUuid,
  *
  * Note: This utility function is used by gecko internal only to convert uuid
  * string created by gecko back to BluetoothUuid representation.
  */
 nsresult
 StringToUuid(const nsAString& aString, BluetoothUuid& aUuid);
 
 /**
+ * Convert continuous bytes from nsTArray to BluetoothUuid object.
+ * @param aArray [in] The byte array.
+ * @param aOffset [in] The offset of continuous bytes of UUID value.
+ * @param aType [in] The type of UUID.
+ * @param aEndian [in] The endianness of UUID value.
+ * @param aUuid [out] The BluetoothUuid object.
+ */
+nsresult
+BytesToUuid(const nsTArray<uint8_t>& aArray,
+            nsTArray<uint8_t>::index_type aOffset,
+            BluetoothUuidType aType,
+            BluetoothProfileEndian aEndian,
+            BluetoothUuid& aUuid);
+
+/**
+ * Convert BluetoothUuid object to nsTArray with continuous bytes.
+ * @param aUuid [in] The BluetoothUuid object.
+ * @param aType [in] The type of UUID.
+ * @param aEndian [in] The endianness of UUID value.
+ * @param aArray [out] The byte array.
+ * @param aOffset [in] The offset of continuous bytes of UUID value.
+ */
+nsresult
+UuidToBytes(const BluetoothUuid& aUuid,
+            BluetoothUuidType aType,
+            BluetoothProfileEndian aEndian,
+            nsTArray<uint8_t>& aArray,
+            nsTArray<uint8_t>::index_type aOffset);
+
+/**
  * Generate a random uuid.
  *
  * @param aUuid [out] The generated uuid.
  */
 nsresult
 GenerateUuid(BluetoothUuid &aUuid);
 
 /**
--- a/dom/bluetooth/common/webapi/BluetoothAdapter.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothAdapter.cpp
@@ -126,17 +126,17 @@ public:
 private:
   RefPtr<BluetoothAdapter> mAdapter;
 };
 
 class StartLeScanTask final : public BluetoothReplyRunnable
 {
 public:
   StartLeScanTask(BluetoothAdapter* aAdapter, Promise* aPromise,
-                  const nsTArray<nsString>& aServiceUuids)
+                  const nsTArray<BluetoothUuid>& aServiceUuids)
     : BluetoothReplyRunnable(nullptr, aPromise)
     , mAdapter(aAdapter)
     , mServiceUuids(aServiceUuids)
   {
     MOZ_ASSERT(aPromise);
     MOZ_ASSERT(aAdapter);
   }
 
@@ -145,25 +145,25 @@ public:
   {
     aValue.setUndefined();
 
     AutoJSAPI jsapi;
     NS_ENSURE_TRUE(jsapi.Init(mAdapter->GetParentObject()), false);
     JSContext* cx = jsapi.cx();
 
     const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
-    NS_ENSURE_TRUE(v.type() == BluetoothValue::TnsString, false);
+    NS_ENSURE_TRUE(v.type() == BluetoothValue::TBluetoothUuid, false);
 
     /**
      * Create a new discovery handle and wrap it to return. Each
      * discovery handle is one-time-use only.
      */
     RefPtr<BluetoothDiscoveryHandle> discoveryHandle =
       BluetoothDiscoveryHandle::Create(mAdapter->GetParentObject(),
-                                       mServiceUuids, v.get_nsString());
+                                       mServiceUuids, v.get_BluetoothUuid());
 
     if (!ToJSValue(cx, discoveryHandle, aValue)) {
       JS_ClearPendingException(cx);
       return false;
     }
 
     // Append a BluetoothDiscoveryHandle to LeScan handle array.
     mAdapter->AppendLeScanHandle(discoveryHandle);
@@ -175,32 +175,32 @@ public:
   ReleaseMembers() override
   {
     BluetoothReplyRunnable::ReleaseMembers();
     mAdapter = nullptr;
   }
 
 private:
   RefPtr<BluetoothAdapter> mAdapter;
-  nsTArray<nsString> mServiceUuids;
+  nsTArray<BluetoothUuid> mServiceUuids;
 };
 
 class StopLeScanTask final : public BluetoothReplyRunnable
 {
 public:
   StopLeScanTask(BluetoothAdapter* aAdapter,
                  Promise* aPromise,
-                 const nsAString& aScanUuid)
+                 const BluetoothUuid& aScanUuid)
       : BluetoothReplyRunnable(nullptr, aPromise)
       , mAdapter(aAdapter)
       , mScanUuid(aScanUuid)
   {
     MOZ_ASSERT(aPromise);
     MOZ_ASSERT(aAdapter);
-    MOZ_ASSERT(!aScanUuid.IsEmpty());
+    MOZ_ASSERT(!aScanUuid.IsCleared());
   }
 
 protected:
   virtual bool
   ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) override
   {
     mAdapter->RemoveLeScanHandle(mScanUuid);
     aValue.setUndefined();
@@ -211,17 +211,17 @@ protected:
   ReleaseMembers() override
   {
     BluetoothReplyRunnable::ReleaseMembers();
     mAdapter = nullptr;
   }
 
 private:
   RefPtr<BluetoothAdapter> mAdapter;
-  nsString mScanUuid;
+  BluetoothUuid mScanUuid;
 };
 
 class GetDevicesTask : public BluetoothReplyRunnable
 {
 public:
   GetDevicesTask(BluetoothAdapter* aAdapterPtr, nsIDOMDOMRequest* aReq)
     : BluetoothReplyRunnable(aReq)
     , mAdapterPtr(aAdapterPtr)
@@ -361,26 +361,22 @@ BluetoothAdapter::Cleanup()
 {
   UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
 
   // Stop ongoing LE scans and clear the LeScan handle array
   if (!mLeScanHandleArray.IsEmpty()) {
     BluetoothService* bs = BluetoothService::Get();
     NS_ENSURE_TRUE_VOID(bs);
 
-    nsString uuidStr;
-    for (uint32_t i = 0; i < mLeScanHandleArray.Length(); ++i) {
-      mLeScanHandleArray[i]->GetLeScanUuid(uuidStr);
+    for (size_t i = 0; i < mLeScanHandleArray.Length(); ++i) {
+      BluetoothUuid uuid;
+      mLeScanHandleArray[i]->GetLeScanUuid(uuid);
       RefPtr<BluetoothVoidReplyRunnable> results =
         new BluetoothVoidReplyRunnable(nullptr);
-
-      BluetoothUuid uuid;
-      if (NS_SUCCEEDED(StringToUuid(uuidStr, uuid))) {
-        bs->StopLeScanInternal(uuid, results);
-      }
+      bs->StopLeScanInternal(uuid, results);
     }
     mLeScanHandleArray.Clear();
   }
 }
 
 BluetoothGattServer*
 BluetoothAdapter::GetGattServer()
 {
@@ -601,22 +597,22 @@ BluetoothAdapter::SetDiscoveryHandleInUs
 void
 BluetoothAdapter::AppendLeScanHandle(
   BluetoothDiscoveryHandle* aDiscoveryHandle)
 {
   mLeScanHandleArray.AppendElement(aDiscoveryHandle);
 }
 
 void
-BluetoothAdapter::RemoveLeScanHandle(const nsAString& aScanUuid)
+BluetoothAdapter::RemoveLeScanHandle(const BluetoothUuid& aScanUuid)
 {
-  nsString uuid;
-  for (uint32_t i = 0; i < mLeScanHandleArray.Length(); ++i) {
+  for (size_t i = 0; i < mLeScanHandleArray.Length(); ++i) {
+    BluetoothUuid uuid;
     mLeScanHandleArray[i]->GetLeScanUuid(uuid);
-    if (aScanUuid.Equals(uuid)) {
+    if (aScanUuid == uuid) {
       mLeScanHandleArray.RemoveElementAt(i);
       break;
     }
   }
 }
 
 already_AddRefed<Promise>
 BluetoothAdapter::StartDiscovery(ErrorResult& aRv)
@@ -713,17 +709,17 @@ BluetoothAdapter::StartLeScan(const nsTA
   BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled,
                         promise,
                         NS_ERROR_DOM_INVALID_STATE_ERR);
 
   BluetoothService* bs = BluetoothService::Get();
   BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE);
 
   RefPtr<BluetoothReplyRunnable> result =
-    new StartLeScanTask(this, promise, aServiceUuids);
+    new StartLeScanTask(this, promise, serviceUuids);
   bs->StartLeScanInternal(serviceUuids, result);
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 BluetoothAdapter::StopLeScan(BluetoothDiscoveryHandle& aDiscoveryHandle,
                              ErrorResult& aRv)
@@ -744,26 +740,21 @@ BluetoothAdapter::StopLeScan(BluetoothDi
   BluetoothService* bs = BluetoothService::Get();
   BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE);
 
   // Reject the request if there's no ongoing LE Scan using this handle.
   BT_ENSURE_TRUE_REJECT(mLeScanHandleArray.Contains(&aDiscoveryHandle),
                         promise,
                         NS_ERROR_DOM_BLUETOOTH_DONE);
 
-  nsString scanUuidStr;
-  aDiscoveryHandle.GetLeScanUuid(scanUuidStr);
-
   BluetoothUuid scanUuid;
-  BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(StringToUuid(scanUuidStr, scanUuid)),
-                        promise,
-                        NS_ERROR_DOM_OPERATION_ERR);
+  aDiscoveryHandle.GetLeScanUuid(scanUuid);
 
   RefPtr<BluetoothReplyRunnable> result =
-    new StopLeScanTask(this, promise, scanUuidStr);
+    new StopLeScanTask(this, promise, scanUuid);
   bs->StopLeScanInternal(scanUuid, result);
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 BluetoothAdapter::SetName(const nsAString& aName, ErrorResult& aRv)
 {
--- a/dom/bluetooth/common/webapi/BluetoothAdapter.h
+++ b/dom/bluetooth/common/webapi/BluetoothAdapter.h
@@ -215,17 +215,17 @@ public:
   void AppendLeScanHandle(BluetoothDiscoveryHandle* aDiscoveryHandle);
 
   /**
    * Remove the BluetoothDiscoverHandle with the given UUID from LeScan handle
    * array.
    *
    * @param aScanUuid [in] The UUID of the LE scan task.
    */
-  void RemoveLeScanHandle(const nsAString& aScanUuid);
+  void RemoveLeScanHandle(const BluetoothUuid& aScanUuid);
 
 private:
   BluetoothAdapter(nsPIDOMWindowInner* aOwner, const BluetoothValue& aValue);
   ~BluetoothAdapter();
 
   /**
    * Unregister signal handler and clean up LE scan handles.
    */
--- a/dom/bluetooth/common/webapi/BluetoothDevice.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothDevice.cpp
@@ -113,16 +113,27 @@ BluetoothDevice::BluetoothDevice(nsPIDOM
 }
 
 BluetoothDevice::~BluetoothDevice()
 {
   UnregisterBluetoothSignalHandler(mAddress, this);
 }
 
 void
+BluetoothDevice::GetUuids(nsTArray<nsString>& aUuids) const
+{
+  aUuids.Clear();
+  for (size_t i = 0; i < mUuids.Length(); ++i) {
+    nsAutoString uuidStr;
+    UuidToString(mUuids[i], uuidStr);
+    aUuids.AppendElement(uuidStr);
+  }
+}
+
+void
 BluetoothDevice::DisconnectFromOwner()
 {
   DOMEventTargetHelper::DisconnectFromOwner();
   UnregisterBluetoothSignalHandler(mAddress, this);
 }
 
 BluetoothDeviceType
 BluetoothDevice::ConvertUint32ToDeviceType(const uint32_t aValue)
@@ -153,29 +164,25 @@ BluetoothDevice::SetPropertyByValue(cons
     } else {
       AddressToString(value.get_BluetoothAddress(), mAddress);
     }
   } else if (name.EqualsLiteral("Cod")) {
     mCod->Update(value.get_uint32_t());
   } else if (name.EqualsLiteral("Paired")) {
     mPaired = value.get_bool();
   } else if (name.EqualsLiteral("UUIDs")) {
-    // While converting to strings, we sort the received UUIDs and remove
-    // any duplicates.
+    // We sort the received UUIDs and remove any duplicates.
     const nsTArray<BluetoothUuid>& uuids = value.get_ArrayOfBluetoothUuid();
     nsTArray<nsString> uuidStrs;
+    mUuids.Clear();
     for (uint32_t index = 0; index < uuids.Length(); ++index) {
-      nsAutoString uuidStr;
-      UuidToString(uuids[index], uuidStr);
-
-      if (!uuidStrs.Contains(uuidStr)) { // filter out duplicate UUIDs
-        uuidStrs.InsertElementSorted(uuidStr);
+      if (!mUuids.Contains(uuids[index])) { // filter out duplicate UUIDs
+        mUuids.InsertElementSorted(uuids[index]);
       }
     }
-    mUuids = Move(uuidStrs);
     BluetoothDeviceBinding::ClearCachedUuidsValue(this);
   } else if (name.EqualsLiteral("Type")) {
     mType = ConvertUint32ToDeviceType(value.get_uint32_t());
   } else if (name.EqualsLiteral("GattAdv")) {
     MOZ_ASSERT(value.type() == BluetoothValue::TArrayOfuint8_t);
     nsTArray<uint8_t> advData;
     advData = value.get_ArrayOfuint8_t();
     UpdatePropertiesFromAdvData(advData);
@@ -270,33 +277,24 @@ BluetoothDevice::IsDeviceAttributeChange
         return !mName.Equals(remoteNameStr);
       }
     case BluetoothDeviceAttribute::Paired:
       MOZ_ASSERT(aValue.type() == BluetoothValue::Tbool);
       return mPaired != aValue.get_bool();
     case BluetoothDeviceAttribute::Uuids: {
       MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothUuid);
       const auto& uuids = aValue.get_ArrayOfBluetoothUuid();
-
-      nsTArray<nsString> uuidStrs;
-
-      // Construct a sorted uuid set
+      nsTArray<BluetoothUuid> sortedUuids;
+      // Construct a sorted UUID set
       for (size_t index = 0; index < uuids.Length(); ++index) {
-        nsAutoString uuidStr;
-        UuidToString(uuids[index], uuidStr);
-
-        if (!uuidStrs.Contains(uuidStr)) { // filter out duplicate uuids
-          uuidStrs.InsertElementSorted(uuidStr);
+        if (!sortedUuids.Contains(uuids[index])) { // filter out duplicate uuids
+          sortedUuids.InsertElementSorted(uuids[index]);
         }
       }
-
-      // We assume the received uuids array is sorted without duplicate items.
-      // If it's not, we require additional processing before comparing it
-      // directly.
-      return mUuids != uuidStrs;
+      return mUuids != sortedUuids;
     }
     default:
       BT_WARNING("Type %d is not handled", uint32_t(aType));
       return false;
   }
 }
 
 void
@@ -381,68 +379,54 @@ BluetoothDevice::UpdatePropertiesFromAdv
     // Length of the data field which is composed by AD type (1 byte) and
     // AD data (dataFieldLength -1 bytes)
     int dataLength = dataFieldLength - 1;
     if (offset + dataLength >= aAdvData.Length()) {
       break;
     }
 
     // Update UUIDs and name of BluetoothDevice.
-    int type = aAdvData[offset++];
+    BluetoothGapDataType type =
+      static_cast<BluetoothGapDataType>(aAdvData[offset++]);
     switch (type) {
       case GAP_INCOMPLETE_UUID16:
       case GAP_COMPLETE_UUID16:
       case GAP_INCOMPLETE_UUID32:
       case GAP_COMPLETE_UUID32:
       case GAP_INCOMPLETE_UUID128:
       case GAP_COMPLETE_UUID128: {
         mUuids.Clear();
 
-        // The length of uint16_t UUID array
-        uint8_t len = 0;
-        if (GAP_INCOMPLETE_UUID16 && GAP_COMPLETE_UUID16) {
-          len = 1;
-        } else if (GAP_INCOMPLETE_UUID32 && GAP_COMPLETE_UUID32) {
-          len = 2;
-        } else {
-          len = 8;
-        }
-        uint16_t uuid[len];
-
         while (dataLength > 0) {
-          // Read (len * 2) bytes from the data buffer and compose a 16-bits
-          // UUID array.
-          for (uint8_t i = 0; i < len; ++i) {
-            uuid[i] = aAdvData[offset++];
-            uuid[i] += (aAdvData[offset++] << 8);
-            dataLength -= 2;
-          }
-
-          char uuidStr[37]; // one more char to be null-terminated
+          BluetoothUuid uuid;
+          size_t length = 0;
           if (type == GAP_INCOMPLETE_UUID16 || type == GAP_COMPLETE_UUID16) {
-            // Convert 16-bits UUID into string.
-            snprintf(uuidStr, sizeof(uuidStr),
-                     "0000%04x-0000-1000-8000-00805f9b34fb", uuid[0]);
+            length = 2;
+            if (NS_FAILED(BytesToUuid(aAdvData, offset, UUID_16_BIT,
+                                      ENDIAN_GAP, uuid))) {
+              break;
+            }
           } else if (type == GAP_INCOMPLETE_UUID32 ||
                      type == GAP_COMPLETE_UUID32) {
-            // Convert 32-bits UUID into string.
-            snprintf(uuidStr, sizeof(uuidStr),
-                     "%04x%04x-0000-1000-8000-00805f9b34fb", uuid[1], uuid[0]);
+            length = 4;
+            if (NS_FAILED(BytesToUuid(aAdvData, offset, UUID_32_BIT,
+                                      ENDIAN_GAP, uuid))) {
+              break;
+            }
           } else if (type == GAP_INCOMPLETE_UUID128 ||
                      type == GAP_COMPLETE_UUID128) {
-            // Convert 128-bits UUID into string.
-            snprintf(uuidStr, sizeof(uuidStr),
-                     "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
-                     uuid[7], uuid[6], uuid[5], uuid[4],
-                     uuid[3], uuid[2], uuid[1], uuid[0]);
+            length = 16;
+            if (NS_FAILED(BytesToUuid(aAdvData, offset, UUID_128_BIT,
+                                      ENDIAN_GAP, uuid))) {
+              break;
+            }
           }
-          nsString uuidNsString;
-          uuidNsString.AssignLiteral(uuidStr);
-
-          mUuids.AppendElement(uuidNsString);
+          mUuids.AppendElement(uuid);
+          offset += length;
+          dataLength -= length;
         }
 
         BluetoothDeviceBinding::ClearCachedUuidsValue(this);
         break;
       }
       case GAP_SHORTENED_NAME:
         if (!mName.IsEmpty()) break;
       case GAP_COMPLETE_NAME: {
--- a/dom/bluetooth/common/webapi/BluetoothDevice.h
+++ b/dom/bluetooth/common/webapi/BluetoothDevice.h
@@ -54,20 +54,17 @@ public:
     aName = mName;
   }
 
   bool Paired() const
   {
     return mPaired;
   }
 
-  void GetUuids(nsTArray<nsString>& aUuids) const
-  {
-    aUuids = mUuids;
-  }
+  void GetUuids(nsTArray<nsString>& aUuids) const;
 
   BluetoothDeviceType Type() const
   {
     return mType;
   }
 
   BluetoothGatt* GetGatt();
 
@@ -92,16 +89,21 @@ public:
   {
      return GetOwner();
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
   virtual void DisconnectFromOwner() override;
 
+  void GetUuids(nsTArray<BluetoothUuid>& aUuids) const
+  {
+    aUuids = mUuids;
+  }
+
 private:
   BluetoothDevice(nsPIDOMWindowInner* aOwner, const BluetoothValue& aValue);
   ~BluetoothDevice();
 
   /**
    * Set device properties according to properties array
    *
    * @param aValue [in] Properties array to set with
@@ -183,17 +185,17 @@ private:
   /**
    * Whether this device is paired or not.
    */
   bool mPaired;
 
   /**
    * Cached UUID list of services which this device provides.
    */
-  nsTArray<nsString> mUuids;
+  nsTArray<BluetoothUuid> mUuids;
 
   /**
    * Type of this device. Can be unknown/classic/le/dual.
    */
   BluetoothDeviceType mType;
 
   /**
    * GATT client object to interact with the remote device.
--- a/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.cpp
@@ -24,18 +24,18 @@ NS_IMPL_RELEASE_INHERITED(BluetoothDisco
 BluetoothDiscoveryHandle::BluetoothDiscoveryHandle(nsPIDOMWindowInner* aWindow)
   : DOMEventTargetHelper(aWindow)
 {
   MOZ_ASSERT(aWindow);
 }
 
 BluetoothDiscoveryHandle::BluetoothDiscoveryHandle(
   nsPIDOMWindowInner* aWindow,
-  const nsTArray<nsString>& aServiceUuids,
-  const nsAString& aLeScanUuid)
+  const nsTArray<BluetoothUuid>& aServiceUuids,
+  const BluetoothUuid& aLeScanUuid)
   : DOMEventTargetHelper(aWindow)
   , mLeScanUuid(aLeScanUuid)
   , mServiceUuids(aServiceUuids)
 {
   MOZ_ASSERT(aWindow);
 }
 
 BluetoothDiscoveryHandle::~BluetoothDiscoveryHandle()
@@ -52,18 +52,18 @@ BluetoothDiscoveryHandle::Create(nsPIDOM
   RefPtr<BluetoothDiscoveryHandle> handle =
     new BluetoothDiscoveryHandle(aWindow);
   return handle.forget();
 }
 
 already_AddRefed<BluetoothDiscoveryHandle>
 BluetoothDiscoveryHandle::Create(
   nsPIDOMWindowInner* aWindow,
-  const nsTArray<nsString>& aServiceUuids,
-  const nsAString& aLeScanUuid)
+  const nsTArray<BluetoothUuid>& aServiceUuids,
+  const BluetoothUuid& aLeScanUuid)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
 
   RefPtr<BluetoothDiscoveryHandle> handle =
     new BluetoothDiscoveryHandle(aWindow, aServiceUuids, aLeScanUuid);
   return handle.forget();
 }
@@ -84,17 +84,17 @@ BluetoothDiscoveryHandle::DispatchDevice
 }
 
 void
 BluetoothDiscoveryHandle::DispatchLeDeviceEvent(BluetoothDevice* aLeDevice,
   int32_t aRssi, nsTArray<uint8_t>& aScanRecord)
 {
   MOZ_ASSERT(aLeDevice);
 
-  nsTArray<nsString> remoteUuids;
+  nsTArray<BluetoothUuid> remoteUuids;
   aLeDevice->GetUuids(remoteUuids);
 
   bool hasUuidsFilter = !mServiceUuids.IsEmpty();
   bool noAdvertisingUuid  = remoteUuids.IsEmpty();
   // If an LE device doesn't advertise its service UUIDs, it can't possibly pass
   // the UUIDs filter.
   if (hasUuidsFilter && noAdvertisingUuid) {
     return;
--- a/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.h
+++ b/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.h
@@ -23,57 +23,57 @@ class BluetoothDiscoveryHandle final : p
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   static already_AddRefed<BluetoothDiscoveryHandle>
     Create(nsPIDOMWindowInner* aWindow);
 
   static already_AddRefed<BluetoothDiscoveryHandle>
     Create(nsPIDOMWindowInner* aWindow,
-           const nsTArray<nsString>& aServiceUuids,
-           const nsAString& aLeScanUuid);
+           const nsTArray<BluetoothUuid>& aServiceUuids,
+           const BluetoothUuid& aLeScanUuid);
 
   void DispatchDeviceEvent(BluetoothDevice* aDevice);
 
   void DispatchLeDeviceEvent(BluetoothDevice* aLeDevice,
                              int32_t aRssi,
                              nsTArray<uint8_t>& aScanRecord);
 
   IMPL_EVENT_HANDLER(devicefound);
 
-  void GetLeScanUuid(nsString& aLeScanUuid) const
+  void GetLeScanUuid(BluetoothUuid& aLeScanUuid) const
   {
     aLeScanUuid = mLeScanUuid;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   BluetoothDiscoveryHandle(nsPIDOMWindowInner* aWindow);
 
   BluetoothDiscoveryHandle(nsPIDOMWindowInner* aWindow,
-                           const nsTArray<nsString>& aServiceUuids,
-                           const nsAString& aLeScanUuid);
+                           const nsTArray<BluetoothUuid>& aServiceUuids,
+                           const BluetoothUuid& aLeScanUuid);
 
   ~BluetoothDiscoveryHandle();
 
   /**
    * Random generated UUID of LE scan
    *
    * This UUID is used only when the handle is built for LE scan.
    * If BluetoothDiscoveryHandle is built for classic discovery, the value would
    * remain empty string during the entire life cycle.
    */
-  nsString mLeScanUuid;
+  BluetoothUuid mLeScanUuid;
 
   /**
-   * A DOMString array of service UUIDs to discover / scan for.
+   * A BluetoothUuid array of service UUIDs to discover / scan for.
    *
    * This array is only used by LE scan. If BluetoothDiscoveryHandle is built
    * for classic discovery, the array should be empty.
    */
-  nsTArray<nsString> mServiceUuids;
+  nsTArray<BluetoothUuid> mServiceUuids;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_BluetoothDiscoveryHandle_h