Bug 1238845 - Implement UUID helper - dom/bluetooth & dom/webidl & layout/build change. r=jocelyn, r=bz
authorTom Tung <ttung@mozilla.com>
Fri, 15 Jan 2016 19:30:46 +0800
changeset 322737 c6ebde846f2d47225592194a716160be1831c5f9
parent 322736 12dfe2b87a791ecb0d6cb193d135d41260c5ca92
child 322738 ad21637bb1cd5adeb4d63cd875a206fcac0c7c82
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjocelyn, bz
bugs1238845
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 1238845 - Implement UUID helper - dom/bluetooth & dom/webidl & layout/build change. r=jocelyn, r=bz
dom/bluetooth/common/BluetoothGattUUIDName.h
dom/bluetooth/common/webapi/BluetoothUUID.cpp
dom/bluetooth/common/webapi/BluetoothUUID.h
dom/bluetooth/moz.build
dom/webidl/BluetoothUUID.webidl
dom/webidl/moz.build
layout/build/nsLayoutStatics.cpp
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/common/BluetoothGattUUIDName.h
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_BluetoothGattUUIDName_h
+#define mozilla_dom_BluetoothGattUUIDName_h
+
+namespace mozilla {
+namespace dom {
+
+struct BluetoothGattUUIDName
+{
+  const char* name;
+  uint16_t uuid;
+};
+
+static BluetoothGattUUIDName ServiceTable[] = {
+  /**
+   * https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
+   */
+  {"alert_notification", 0x1811},
+  {"automation_io", 0x1815},
+  {"battery_service", 0x180F},
+  {"blood_pressure", 0x1810},
+  {"body_composition", 0x181B},
+  {"bond_management", 0x181E},
+  {"continuous_glucose_monitoring", 0x181F},
+  {"current_time", 0x1805},
+  {"cycling_power", 0x1818},
+  {"cycling_speed_and_cadence", 0x1816},
+  {"device_information", 0x180A},
+  {"environmental_sensing", 0x181A},
+  {"generic_access", 0x1800},
+  {"generic_attribute", 0x1801},
+  {"glucose", 0x1808},
+  {"health_thermometer", 0x1809},
+  {"heart_rate", 0x180D},
+  {"http_proxy", 0x1823},
+  {"human_interface_device", 0x1812},
+  {"immediate_alert", 0x1802},
+  {"indoor_positioning", 0x1821},
+  {"internet_protocol_support", 0x1820},
+  {"link_loss", 0x1803},
+  {"location_and_navigation", 0x1819},
+  {"next_dst_change", 0x1807},
+  {"object_transfer", 0x1825},
+  {"phone_alert_status", 0x180E},
+  {"pulse_oximeter", 0x1822},
+  {"reference_time_update", 0x1806},
+  {"running_speed_and_cadence", 0x1814},
+  {"scan_parameters", 0x1813},
+  {"transport_discovery", 0x1824},
+  {"tx_power", 0x1804},
+  {"user_data", 0x181C},
+  {"weight_scale", 0x181D},
+};
+
+static BluetoothGattUUIDName CharacteristicTable[] = {
+  /**
+   * https://developer.bluetooth.org/gatt/characteristics/Pages/\
+   * CharacteristicsHome.aspx
+   */
+  {"aerobic_heart_rate_lower_limit", 0x2A7E},
+  {"aerobic_heart_rate_upper_limit", 0x2A84},
+  {"aerobic_threshold", 0x2A7F},
+  {"age", 0x2A80},
+  {"aggregate", 0x2A5A},
+  {"alert_category_id", 0x2A43},
+  {"alert_category_id_bit_mask", 0x2A42},
+  {"alert_level", 0x2A06},
+  {"alert_notification_control_point", 0x2A44},
+  {"alert_status", 0x2A3F},
+  {"altitude", 0x2AB3},
+  {"anaerobic_heart_rate_lower_limit", 0x2A81},
+  {"anaerobic_heart_rate_upper_limit", 0x2A82},
+  {"anaerobic_threshold", 0x2A83},
+  {"analog", 0x2A58},
+  {"apparent_wind_direction", 0x2A73},
+  {"apparent_wind_speed", 0x2A72},
+  {"gap.appearance", 0x2A01},
+  {"barometric_pressure_trend", 0x2AA3},
+  {"battery_level", 0x2A19},
+  {"blood_pressure_feature", 0x2A49},
+  {"blood_pressure_measurement", 0x2A35},
+  {"body_composition_feature", 0x2A9B},
+  {"body_composition_measurement", 0x2A9C},
+  {"body_sensor_location", 0x2A38},
+  {"bond_management_control_point", 0x2AA4},
+  {"bond_management_feature", 0x2AA5},
+  {"boot_keyboard_input_report", 0x2A22},
+  {"boot_keyboard_output_report", 0x2A32},
+  {"boot_mouse_input_report", 0x2A33},
+  {"gap.central_address_resolution_support", 0x2AA6},
+  {"cgm_feature", 0x2AA8},
+  {"cgm_measurement", 0x2AA7},
+  {"cgm_session_run_time", 0x2AAB},
+  {"cgm_session_start_time", 0x2AAA},
+  {"cgm_specific_ops_control_point", 0x2AAC},
+  {"cgm_status", 0x2AA9},
+  {"csc_feature", 0x2A5C},
+  {"csc_measurement", 0x2A5B},
+  {"current_time", 0x2A2B},
+  {"cycling_power_control_point", 0x2A66},
+  {"cycling_power_feature", 0x2A65},
+  {"cycling_power_measurement", 0x2A63},
+  {"cycling_power_vector", 0x2A64},
+  {"database_change_increment", 0x2A99},
+  {"date_of_birth", 0x2A85},
+  {"date_of_threshold_assessment", 0x2A86},
+  {"date_time", 0x2A08},
+  {"day_date_time", 0x2A0A},
+  {"day_of_week", 0x2A09},
+  {"descriptor_value_changed", 0x2A7D},
+  {"gap.device_name", 0x2A00},
+  {"dew_point", 0x2A7B},
+  {"digital", 0x2A56},
+  {"dst_offset", 0x2A0D},
+  {"elevation", 0x2A6C},
+  {"email_address", 0x2A87},
+  {"exact_time_256", 0x2A0C},
+  {"fat_burn_heart_rate_lower_limit", 0x2A88},
+  {"fat_burn_heart_rate_upper_limit", 0x2A89},
+  {"firmware_revision_string", 0x2A26},
+  {"first_name", 0x2A8A},
+  {"five_zone_heart_rate_limits", 0x2A8B},
+  {"floor_number", 0x2AB2},
+  {"gender", 0x2A8C},
+  {"glucose_feature", 0x2A51},
+  {"glucose_measurement", 0x2A18},
+  {"glucose_measurement_context", 0x2A34},
+  {"gust_factor", 0x2A74},
+  {"hardware_revision_string", 0x2A27},
+  {"heart_rate_control_point", 0x2A39},
+  {"heart_rate_max", 0x2A8D},
+  {"heart_rate_measurement", 0x2A37},
+  {"heat_index", 0x2A7A},
+  {"height", 0x2A8E},
+  {"hid_control_point", 0x2A4C},
+  {"hid_information", 0x2A4A},
+  {"hip_circumference", 0x2A8F},
+  {"http_control_point", 0x2ABA},
+  {"http_entity_body", 0x2AB9},
+  {"http_headers", 0x2AB7},
+  {"http_status_code", 0x2AB8},
+  {"http_security", 0x2ABB},
+  {"humidity", 0x2A6F},
+  {"ieee_11073-20601_regulatory_certification_data_list",
+     0x2A2A},
+  {"indoor_positioning_configuration", 0x2AAD},
+  {"intermediate_blood_pressure", 0x2A36},
+  {"intermediate_temperature", 0x2A1E},
+  {"irradiance", 0x2A77},
+  {"language", 0x2AA2},
+  {"last_name", 0x2A90},
+  {"latitude", 0x2AAE},
+  {"ln_control_point", 0x2A6B},
+  {"ln_feature", 0x2A6A},
+  {"local_east_coordinate.xml", 0x2AB1},
+  {"local_north_coordinate", 0x2AB0},
+  {"local_time_information", 0x2A0F},
+  {"location_and_speed", 0x2A67},
+  {"location_name", 0x2AB5},
+  {"longitude", 0x2AAF},
+  {"magnetic_declination", 0x2A2C},
+  {"magnetic_flux_density_2D", 0x2AA0},
+  {"magnetic_flux_density_3D", 0x2AA1},
+  {"manufacturer_name_string", 0x2A29},
+  {"maximum_recommended_heart_rate", 0x2A91},
+  {"measurement_interval", 0x2A21},
+  {"model_number_string", 0x2A24},
+  {"navigation", 0x2A68},
+  {"new_alert", 0x2A46},
+  {"object_action_control_point", 0x2AC5},
+  {"object_changed", 0x2AC8},
+  {"object_first_created", 0x2AC1},
+  {"object_id", 0x2AC3},
+  {"object_last_modified", 0x2AC2},
+  {"object_list_control_point", 0x2AC6},
+  {"object_list_filter", 0x2AC7},
+  {"object_name", 0x2ABE},
+  {"object_properties", 0x2AC4},
+  {"object_size", 0x2AC0},
+  {"object_type", 0x2ABF},
+  {"object_ots_feature", 0x2ABD},
+  {"gap.peripheral_preferred_connection_parameters",
+     0x2A04},
+  {"gap.peripheral_privacy_flag", 0x2A02},
+  {"plx_continuous_measurement", 0x2A5F},
+  {"plx_features", 0x2A60},
+  {"plx_spot_check_measurement", 0x2A5E},
+  {"pnp_id", 0x2A50},
+  {"pollen_concentration", 0x2A75},
+  {"position_quality", 0x2A69},
+  {"pressure", 0x2A6D},
+  {"protocol_mode", 0x2A4E},
+  {"rainfall", 0x2A78},
+  {"gap.reconnection_address", 0x2A03},
+  {"record_access_control_point", 0x2A52},
+  {"reference_time_information", 0x2A14},
+  {"report", 0x2A4D},
+  {"report_map", 0x2A4B},
+  {"resting_heart_rate", 0x2A92},
+  {"ringer_control_point", 0x2A40},
+  {"ringer_setting", 0x2A41},
+  {"rsc_feature", 0x2A54},
+  {"rsc_measurement", 0x2A53},
+  {"sc_control_point", 0x2A55},
+  {"scan_interval_window", 0x2A4F},
+  {"scan_refresh", 0x2A31},
+  {"sensor_location", 0x2A5D},
+  {"serial_number_string", 0x2A25},
+  {"gatt.service_changed", 0x2A05},
+  {"software_revision_string", 0x2A28},
+  {"sport_type_for_aerobic_and_anaerobic_thresholds",
+     0x2A93},
+  {"supported_new_alert_category", 0x2A47},
+  {"supported_unread_alert_category", 0x2A48},
+  {"system_id", 0x2A23},
+  {"temperature", 0x2A6E},
+  {"temperature_measurement", 0x2A1C},
+  {"temperature_type", 0x2A1D},
+  {"three_zone_heart_rate_limits", 0x2A94},
+  {"time_accuracy", 0x2A12},
+  {"time_source", 0x2A13},
+  {"time_update_control_point", 0x2A16},
+  {"time_update_state", 0x2A17},
+  {"time_with_dst", 0x2A11},
+  {"time_zone", 0x2A0E},
+  {"true_wind_direction", 0x2A71},
+  {"true_wind_speed", 0x2A70},
+  {"two_zone_heart_rate_limit", 0x2A95},
+  {"tx_power_level", 0x2A07},
+  {"uncertainty", 0x2AB4},
+  {"unread_alert_status", 0x2A45},
+  {"uri", 0x2AB6},
+  {"user_control_point", 0x2A9F},
+  {"user_index", 0x2A9A},
+  {"uv_index", 0x2A76},
+  {"vo2_max", 0x2A96},
+  {"waist_circumference", 0x2A97},
+  {"weight", 0x2A98},
+  {"weight_measurement", 0x2A9D},
+  {"weight_scale_feature", 0x2A9E},
+  {"wind_chill", 0x2A79},
+};
+
+static BluetoothGattUUIDName DescriptorTable[] = {
+  /**
+   * https://developer.bluetooth.org/gatt/descriptors/Pages\
+   * /DescriptorsHomePage.aspx
+   */
+  {"gatt.characteristic_extended_properties", 0x2900},
+  {"gatt.characteristic_user_description", 0x2901},
+  {"gatt.client_characteristic_configuration", 0x2902},
+  {"gatt.server_characteristic_configuration", 0x2903},
+  {"gatt.characteristic_presentation_format", 0x2904},
+  {"gatt.characteristic_aggregate_format", 0x2905},
+  {"valid_range", 0x2906},
+  {"external_report_reference", 0x2907},
+  {"report_reference", 0x2908},
+  {"number_of_digitals", 0x2909},
+  {"value_trigger_setting", 0x290A},
+  {"es_configuration", 0x290B},
+  {"es_measurement", 0x290C},
+  {"es_trigger_setting", 0x290D},
+  {"time_trigger_setting", 0x290E},
+};
+
+}// dom
+}// mozilla
+#endif // mozilla_dom_BluetoothGattUUIDName_h
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/common/webapi/BluetoothUUID.cpp
@@ -0,0 +1,234 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/bluetooth/BluetoothCommon.h"
+#include "mozilla/dom/bluetooth/BluetoothGattUUIDName.h"
+#include "mozilla/dom/BluetoothUUID.h"
+#include "mozilla/dom/UnionTypes.h" /* StringOrUnsignedLong */
+
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+bool BluetoothUUID::sInShutdown = false;
+// static
+nsDataHashtable<nsStringHashKey, uint32_t>*
+  BluetoothUUID::sUUIDServiceTable;
+// static
+nsDataHashtable<nsStringHashKey, uint32_t>*
+  BluetoothUUID::sUUIDCharacteristicTable;
+// static
+nsDataHashtable<nsStringHashKey, uint32_t>*
+  BluetoothUUID::sUUIDDescriptorTable;
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BluetoothUUID, mOwner)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothUUID)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothUUID)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothUUID)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+BluetoothUUID::BluetoothUUID(nsPIDOMWindowInner* aOwner)
+  : mOwner(aOwner)
+{
+  MOZ_ASSERT(aOwner);
+}
+
+BluetoothUUID::~BluetoothUUID()
+{
+}
+
+JSObject*
+BluetoothUUID::WrapObject(JSContext* aCx,
+                          JS::Handle<JSObject*> aGivenProto)
+{
+  return BluetoothUUIDBinding::Wrap(aCx, this, aGivenProto);
+}
+
+//static
+void BluetoothUUID::HandleShutdown()
+{
+  sInShutdown = true;
+  delete sUUIDServiceTable;
+  delete sUUIDCharacteristicTable;
+  delete sUUIDDescriptorTable;
+  sUUIDServiceTable = nullptr;
+  sUUIDCharacteristicTable = nullptr;
+  sUUIDDescriptorTable = nullptr;
+}
+
+// static
+void
+BluetoothUUID::InitServiceTable()
+{
+  size_t length = sizeof(ServiceTable) / sizeof(BluetoothGattUUIDName);
+  for (size_t i = 0; i < length; ++i) {
+    sUUIDServiceTable->Put(NS_ConvertUTF8toUTF16(ServiceTable[i].name),
+                           ServiceTable[i].uuid);
+  }
+}
+
+// static
+void
+BluetoothUUID::InitCharacteristicTable()
+{
+  size_t length = sizeof(CharacteristicTable) / sizeof(BluetoothGattUUIDName);
+  for (size_t i = 0; i < length; ++i) {
+    sUUIDCharacteristicTable->Put(NS_ConvertUTF8toUTF16(
+                                    CharacteristicTable[i].name),
+                                  CharacteristicTable[i].uuid);
+  }
+}
+
+// static
+void
+BluetoothUUID::InitDescriptorTable()
+{
+  size_t length = sizeof(DescriptorTable) / sizeof(BluetoothGattUUIDName);
+  for (size_t i = 0; i < length; ++i) {
+    sUUIDDescriptorTable->Put(NS_ConvertUTF8toUTF16(DescriptorTable[i].name),
+                              DescriptorTable[i].uuid);
+  }
+}
+
+/**
+ * Check whether the UUID(aString) is valid or not
+ */
+bool IsValidUUID(const nsAString& aString)
+{
+  size_t length = aString.Length();
+  if (length != 36) {
+    return false;
+  }
+
+  const char16_t* uuid = aString.BeginReading();
+
+  for (size_t i = 0; i < length; ++i) {
+    if (i == 8 || i == 13 || i == 18 || i == 23) {
+      if (uuid[i] != '-') {
+        return false;
+      }
+    } else if ((uuid[i] < '0' || uuid[i] > '9') &&
+               (uuid[i] < 'a' || uuid[i] > 'f')) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+// static
+void
+BluetoothUUID::ResolveUUIDName(const GlobalObject& aGlobal,
+                               const StringOrUnsignedLong& aName,
+                               GattAttribute aAttr, nsAString& aReturn,
+                               ErrorResult& aRv)
+{
+  aReturn.Truncate();
+
+  if (aName.IsUnsignedLong()) {
+    // aName is a 16-bit or 32-bit UUID alias.
+    CanonicalUUID(aGlobal, aName.GetAsUnsignedLong(), aReturn);
+  } else if (aName.IsString()) {
+    uint32_t alias = 0;
+    nsString aString(aName.GetAsString());
+
+    if (IsValidUUID(aString)) {
+      // aName is a valid UUID String.
+      aReturn.Assign(aString);
+    } else if (GetTable(aAttr, aString, alias)) {
+      // The UUID string can be mapped to a known UUID alias.
+      CanonicalUUID(aGlobal, alias, aReturn);
+    } else {
+      // Exception, Syntax error, assign aReturn the error message
+      aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
+                            NS_LITERAL_CSTRING("Invalid name: It can be a"
+                              " 32-bit UUID alias, 128-bit valid UUID "
+                              "(lower-case hex characters) or known "
+                              "Service/Characteristic/Descriptor name."));
+
+      return ;
+    }
+  } else {
+    MOZ_ASSERT(false, "Invalid name: It can be a 32-bit UUID alias, 128-bit "
+                      "valid UUID (lower-case hex characters) or known "
+                      "Service/Characteristic/Descriptor name.");
+  }
+}
+
+// static
+bool
+BluetoothUUID::GetTable(GattAttribute aAttr, const nsAString& aString,
+                        uint32_t& aAlias)
+{
+  // If we're in shutdown, don't create a new instance.
+  NS_ENSURE_FALSE(sInShutdown, false);
+
+  nsDataHashtable<nsStringHashKey, uint32_t>** tableSlot;
+
+  if (aAttr == SERVICE) {
+    tableSlot = &sUUIDServiceTable;
+  } else if (aAttr == CHARACTERISTIC) {
+    tableSlot = &sUUIDCharacteristicTable;
+  } else if (aAttr == DESCRIPTOR) {
+    tableSlot = &sUUIDDescriptorTable;
+  }
+
+  if (!*tableSlot) {
+    (*tableSlot) = new nsDataHashtable<nsStringHashKey, uint32_t>;
+    if (aAttr == SERVICE) {
+      InitServiceTable();
+    } else if (aAttr == CHARACTERISTIC) {
+      InitCharacteristicTable();
+    } else if (aAttr == DESCRIPTOR) {
+      InitDescriptorTable();
+    }
+  }
+
+  return (*tableSlot)->Get(aString, &aAlias);
+}
+
+// static
+void
+BluetoothUUID::GetService(const GlobalObject& aGlobal,
+                          const StringOrUnsignedLong& aName,
+                          nsAString& aReturn, ErrorResult& aRv)
+{
+  ResolveUUIDName(aGlobal, aName, SERVICE, aReturn, aRv);
+}
+
+// static
+void
+BluetoothUUID::GetCharacteristic(const GlobalObject& aGlobal,
+                                 const StringOrUnsignedLong& aName,
+                                 nsAString& aReturn, ErrorResult& aRv)
+{
+  ResolveUUIDName(aGlobal, aName, CHARACTERISTIC, aReturn, aRv);
+}
+
+// static
+void
+BluetoothUUID::GetDescriptor(const GlobalObject& aGlobal,
+                             const StringOrUnsignedLong& aName,
+                             nsAString& aReturn, ErrorResult& aRv)
+{
+  ResolveUUIDName(aGlobal, aName, DESCRIPTOR, aReturn, aRv);
+}
+
+// static
+void
+BluetoothUUID::CanonicalUUID(const GlobalObject& aGlobal, uint32_t aAlias,
+                             nsAString& aReturn)
+{
+  char uuidStr[37];
+
+  // Convert to 128-bit UUID: alias + "-0000-1000-8000-00805f9b34fb".
+  snprintf(uuidStr, sizeof(uuidStr), "%.8x-0000-1000-8000-00805f9b34fb",
+           aAlias);
+
+  aReturn.AssignLiteral(uuidStr);
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/common/webapi/BluetoothUUID.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_BluetoothUUID_h
+#define mozilla_dom_BluetoothUUID_h
+
+#include "mozilla/dom/BluetoothUUIDBinding.h"
+#include "mozilla/StaticPtr.h"
+#include "nsCOMPtr.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+#include "nsIObserver.h"
+#include "nsPIDOMWindow.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+class StringOrUnsignedLong;
+
+class BluetoothUUID final : public nsISupports
+                          , public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BluetoothUUID)
+
+  nsPIDOMWindowInner* GetParentObject() const
+  {
+    return mOwner;
+  }
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
+  /**
+   * Delete sUUIDServiceTable, sUUIDCharacteristicTable, sUUIDDescriptorTable
+   * used by ResolveUUIDName(). To be called from nsLayoutStatics only.
+   */
+  static void HandleShutdown();
+
+  static void GetService(const GlobalObject& aGlobal,
+                         const StringOrUnsignedLong& aName,
+                         nsAString& aReturn, ErrorResult& aRv);
+  static void GetCharacteristic(const GlobalObject& aGlobal,
+                                const StringOrUnsignedLong& aName,
+                                nsAString& aReturn, ErrorResult& aRv);
+  static void GetDescriptor(const GlobalObject& aGlobal,
+                            const StringOrUnsignedLong& aName,
+                            nsAString& aReturn, ErrorResult& aRv);
+
+  static void CanonicalUUID(const GlobalObject& aGlobal, uint32_t aAlias,
+                            nsAString& aReturn);
+
+private:
+  BluetoothUUID(nsPIDOMWindowInner* aOwner);
+  ~BluetoothUUID();
+
+  static void InitServiceTable();
+  static void InitCharacteristicTable();
+  static void InitDescriptorTable();
+
+  enum GattAttribute {
+    SERVICE,
+    CHARACTERISTIC,
+    DESCRIPTOR
+  };
+
+  /**
+   * Convert an UUID string or 16-bit/32-bit UUID alias to a 128-bit UUID based
+   * on its bluetooth attribute.
+   *
+   * @param aGlobal [in] a Global object for static attributes. We have this
+   *                     argument because it needs to call |CanonicalUUID|.
+   * @param aName   [in] an UUID string or 16-bit/32-bit UUID alias.
+   * @param aAttr   [in] a GATT Attribute type.
+   * @param aReturn [out] a 128-bit UUID.
+   */
+  static void ResolveUUIDName(const GlobalObject& aGlobal,
+                              const StringOrUnsignedLong& aName,
+                              GattAttribute aAttr, nsAString& aReturn,
+                              ErrorResult& aRv);
+
+  /**
+   * Get the GATT attribute table based on the GATT attribute and check whether
+   * the UUID string can be mapped to a known alias.
+   *
+   * @param aAttr   [in] a GATT Attribute type.
+   * @param aString [in] an UUID string.
+   * @param aAlias  [out] a known UUID alias if success.
+   * @return success if a UUID string can be mapped in table, fail if it
+   *         cannot.
+   */
+  static bool GetTable(GattAttribute aAttr, const nsAString& aString,
+                       uint32_t& aAlias);
+
+  /****************************************************************************
+   * Variables
+   ***************************************************************************/
+  nsCOMPtr<nsPIDOMWindowInner> mOwner;
+
+  static bool sInShutdown;
+
+  /**
+   * Hash Table of services for mapping service names to its UUID's prefix.
+   */
+  static nsDataHashtable<nsStringHashKey, uint32_t>* sUUIDServiceTable;
+
+  /**
+   * Hash Table of characteristics for mapping characteristic names to its UUID's prefix.
+   */
+  static nsDataHashtable<nsStringHashKey, uint32_t>* sUUIDCharacteristicTable;
+
+  /**
+   * Hash Table of descriptors for mapping descriptor names to its UUID's prefix.
+   */
+  static nsDataHashtable<nsStringHashKey, uint32_t>* sUUIDDescriptorTable;
+};
+
+} // dom
+} // mozilla
+
+#endif // mozilla_dom_BluetoothUUID_h
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -37,16 +37,17 @@ if CONFIG['MOZ_B2G_BT']:
         'common/webapi/BluetoothGattService.cpp',
         'common/webapi/BluetoothLeDeviceEvent.cpp',
         'common/webapi/BluetoothManager.cpp',
         'common/webapi/BluetoothMapRequestHandle.cpp',
         'common/webapi/BluetoothObexAuthHandle.cpp',
         'common/webapi/BluetoothPairingHandle.cpp',
         'common/webapi/BluetoothPairingListener.cpp',
         'common/webapi/BluetoothPbapRequestHandle.cpp',
+        'common/webapi/BluetoothUUID.cpp',
         'ipc/BluetoothChild.cpp',
         'ipc/BluetoothParent.cpp',
         'ipc/BluetoothServiceChildProcess.cpp'
     ]
     LOCAL_INCLUDES += [
         'common',
         'common/webapi',
         'ipc'
@@ -134,16 +135,17 @@ if CONFIG['MOZ_B2G_BT']:
 # Exported interfaces
 #
 
 EXPORTS.mozilla.dom.bluetooth.ipc += [
     'ipc/BluetoothMessageUtils.h',
 ]
 EXPORTS.mozilla.dom.bluetooth += [
     'common/BluetoothCommon.h',
+    'common/BluetoothGattUUIDName.h',
     'common/BluetoothHashKeys.h',
     'common/webapi/BluetoothAdapter.h',
     'common/webapi/BluetoothClassOfDevice.h',
     'common/webapi/BluetoothDevice.h',
     'common/webapi/BluetoothDiscoveryHandle.h',
     'common/webapi/BluetoothGatt.h',
     'common/webapi/BluetoothGattAttributeEvent.h',
     'common/webapi/BluetoothGattCharacteristic.h',
@@ -153,16 +155,19 @@ EXPORTS.mozilla.dom.bluetooth += [
     'common/webapi/BluetoothLeDeviceEvent.h',
     'common/webapi/BluetoothManager.h',
     'common/webapi/BluetoothMapRequestHandle.h',
     'common/webapi/BluetoothObexAuthHandle.h',
     'common/webapi/BluetoothPairingHandle.h',
     'common/webapi/BluetoothPairingListener.h',
     'common/webapi/BluetoothPbapRequestHandle.h'
 ]
+EXPORTS.mozilla.dom += [
+    'common/webapi/BluetoothUUID.h'
+]
 
 UNIFIED_SOURCES += [
     'common/BluetoothCommon.cpp',
 ]
 
 IPDL_SOURCES += [
     'ipc/BluetoothTypes.ipdlh',
     'ipc/PBluetooth.ipdl',
new file mode 100644
--- /dev/null
+++ b/dom/webidl/BluetoothUUID.webidl
@@ -0,0 +1,27 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://webbluetoothcg.github.io/web-bluetooth/#uuids
+ *
+ */
+
+typedef DOMString UUID;
+typedef (DOMString or unsigned long) BluetoothServiceUUID;
+typedef (DOMString or unsigned long) BluetoothCharacteristicUUID;
+typedef (DOMString or unsigned long) BluetoothDescriptorUUID;
+
+[Pref="dom.bluetooth.webbluetooth.enable", CheckAnyPermissions="bluetooth"]
+interface BluetoothUUID
+{
+  [Throws]
+  static UUID getService(BluetoothServiceUUID name);
+  [Throws]
+  static UUID getCharacteristic(BluetoothCharacteristicUUID name);
+  [Throws]
+  static UUID getDescriptor(BluetoothDescriptorUUID name);
+
+  static UUID canonicalUUID([EnforceRange] unsigned long alias);
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -708,16 +708,17 @@ if CONFIG['MOZ_B2G_BT']:
         'BluetoothManager.webidl',
         'BluetoothMapParameters.webidl',
         'BluetoothMapRequestHandle.webidl',
         'BluetoothObexAuthHandle.webidl',
         'BluetoothPairingHandle.webidl',
         'BluetoothPairingListener.webidl',
         'BluetoothPbapParameters.webidl',
         'BluetoothPbapRequestHandle.webidl',
+        'BluetoothUUID.webidl',
     ]
 
 if CONFIG['MOZ_SIMPLEPUSH']:
     WEBIDL_FILES += [
         'SimplePushManager.webidl'
     ]
 else:
     WEBIDL_FILES += [
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -127,16 +127,20 @@ using namespace mozilla::system;
 #include "nsDocument.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "CameraPreferences.h"
 #include "TouchManager.h"
 #include "MediaDecoder.h"
 #include "mozilla/layers/CompositorLRU.h"
 #include "mozilla/dom/devicestorage/DeviceStorageStatics.h"
 
+#ifdef MOZ_B2G_BT
+#include "mozilla/dom/BluetoothUUID.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::net;
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
 
 nsrefcnt nsLayoutStatics::sLayoutStaticRefcnt = 0;
 
 nsresult
@@ -435,9 +439,13 @@ nsLayoutStatics::Shutdown()
 
   nsDocument::XPCOMShutdown();
 
   CacheObserver::Shutdown();
 
   CameraPreferences::Shutdown();
 
   PromiseDebugging::Shutdown();
+
+#ifdef MOZ_B2G_BT
+  BluetoothUUID::HandleShutdown();
+#endif
 }