From b62b56c75e87e527460f2f077ceaf72e03944583 Mon Sep 17 00:00:00 2001 From: Francis Tsui Date: Mon, 10 Mar 2025 13:40:18 -0700 Subject: [PATCH] Move Bluetooth UUID16 conversion into Uuid class. PiperOrigin-RevId: 735496175 --- .../platform/implementation/windows/ble_v2.cc | 46 +++++++++---------- internal/platform/uuid.cc | 19 ++++++++ internal/platform/uuid.h | 4 ++ internal/platform/uuid_test.cc | 31 +++++++++++++ 4 files changed, 75 insertions(+), 25 deletions(-) diff --git a/internal/platform/implementation/windows/ble_v2.cc b/internal/platform/implementation/windows/ble_v2.cc index 71609a01..0f948d4b 100644 --- a/internal/platform/implementation/windows/ble_v2.cc +++ b/internal/platform/implementation/windows/ble_v2.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -27,9 +28,8 @@ #include "absl/container/flat_hash_map.h" #include "absl/status/status.h" #include "absl/strings/escaping.h" -#include "absl/strings/numbers.h" + #include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" #include "absl/strings/str_join.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" @@ -165,14 +165,6 @@ constexpr absl::Duration kPeripheralExpiryTime = Minutes(15); // Prevent too frequent cleanup tasks. constexpr absl::Duration kMaxPeripheralCleanupFrequency = Minutes(3); -// The most significant bits and the least significant bits or Bluetooth Base -// UUID. -// See Bluetooth Core Specification 6.0 Vol.3, Part B, Section 2.5.1 -const std::uint64_t kBluetoothBaseUuidMsb = 0x0000000000001000; -const std::uint64_t kBluetoothBaseUuidLsb = 0x800000805F9B34FB; -// Mask for UUID16 bits. -const std::uint64_t kBluetoothBaseUuid16MsbMask = 0x0000FFFF00000000; - // Service Data - 16-bit UUID. From Bluetooth Assigned Numbers Section 2.3. constexpr uint8_t kUuid16ServiceDataType = 0x16; } // namespace @@ -448,12 +440,15 @@ bool BleV2Medium::StartScanning(const Uuid& service_uuid, // This assumes that service_uuid has a valid UUID16 alias. // Verify that service_uuid in in valid range. - DCHECK_EQ(service_uuid_.GetMostSigBits() & ~kBluetoothBaseUuid16MsbMask, - kBluetoothBaseUuidMsb); - DCHECK_EQ(service_uuid_.GetLeastSigBits(), kBluetoothBaseUuidLsb); + std::optional service_uuid16 = service_uuid_.GetBtUuid16(); + if (!service_uuid16.has_value()) { + LOG(WARNING) << __func__ + << ": BLE cannot start to scan because the service UUID is " + "not in valid range."; + return false; + } - service_uuid16_ = - (service_uuid_.GetMostSigBits() & kBluetoothBaseUuid16MsbMask) >> 32; + service_uuid16_ = *service_uuid16; std::unique_ptr watcher = CreateBleWatcher(service_uuid16_); if (watcher == nullptr) { @@ -752,17 +747,16 @@ bool BleV2Medium::StartBleAdvertising( for (const auto& it : advertising_data.service_data) { DataWriter data_writer; + data_writer.ByteOrder(ByteOrder::LittleEndian); - std::string uuid_string = it.first.Get16BitAsString(); - int uuid; - if (!absl::SimpleHexAtoi(uuid_string, &uuid)) { + std::optional uuid16 = it.first.GetBtUuid16(); + if (!uuid16.has_value()) { LOG(WARNING) << "BLE failed to get service UUID."; return false; } + LOG(WARNING) << "BLE service UUID: " << absl::StrCat(absl::Hex(*uuid16)); - LOG(WARNING) << "BLE service UUID: " << absl::StrFormat("%#x", uuid); - - data_writer.WriteUInt16(((uuid >> 8) & 0xff) | ((uuid & 0xff) << 8)); + data_writer.WriteUInt16(*uuid16); for (int i = 0; i < it.second.size(); ++i) { data_writer.WriteByte(static_cast(*(it.second.data() + i))); @@ -1271,15 +1265,17 @@ void BleV2Medium::AdvertisementFoundHandler( uint16_t service_uuid16 = data_reader.ReadUInt16(); for (auto service_uuid : service_uuid_list) { - uint16_t uuid16 = - (service_uuid.GetMostSigBits() & kBluetoothBaseUuid16MsbMask) >> 32; - if (uuid16 == service_uuid16) { + std::optional uuid16 = service_uuid.GetBtUuid16(); + if (!uuid16.has_value()) { + continue; + } + if (*uuid16 == service_uuid16) { std::string data; uint8_t unconsumed_buffer_length = data_reader.UnconsumedBufferLength(); if (unconsumed_buffer_length > 27) { LOG(INFO) << "Skipping extended advertisement with service " - << service_uuid.Get16BitAsString(); + << absl::StrCat(absl::Hex(*uuid16)); return; } for (int i = 0; i < unconsumed_buffer_length; i++) { diff --git a/internal/platform/uuid.cc b/internal/platform/uuid.cc index abba3ec2..4710ede1 100644 --- a/internal/platform/uuid.cc +++ b/internal/platform/uuid.cc @@ -34,6 +34,15 @@ namespace nearby { namespace { +// The most significant bits and the least significant bits or Bluetooth Base +// UUID. +// See Bluetooth Core Specification 6.0 Vol.3, Part B, Section 2.5.1 +const std::uint64_t kBluetoothBaseUuidMsb = 0x0000000000001000; +const std::uint64_t kBluetoothBaseUuidLsb = 0x800000805F9B34FB; +// Mask for UUID16 bits. +const std::uint64_t kBluetoothBaseUuid16MsbMask = 0x0000FFFF00000000; + + std::ostream& write_hex(std::ostream& os, absl::string_view data) { for (const auto b : data) { os << std::setfill('0') << std::setw(2) << std::hex << std::uppercase @@ -135,6 +144,16 @@ std::string Uuid::Get16BitAsString() const { return sixteen_bit_string.str(); } +std::optional Uuid::GetBtUuid16() const { + // Verify that the UUID is in valid range. + if ((GetMostSigBits() & ~kBluetoothBaseUuid16MsbMask) != + kBluetoothBaseUuidMsb || + GetLeastSigBits() != kBluetoothBaseUuidLsb) { + return std::nullopt; + } + return (GetMostSigBits() & kBluetoothBaseUuid16MsbMask) >> 32; +} + std::array Uuid::data() const { std::array data; data[0] = (most_sig_bits_ >> 56) & 0x0ff; diff --git a/internal/platform/uuid.h b/internal/platform/uuid.h index 230e2f29..902e7c8a 100644 --- a/internal/platform/uuid.h +++ b/internal/platform/uuid.h @@ -58,6 +58,10 @@ class Uuid final { // This is needed because Android only support UUID 16 bits in service data // section in advertising data std::string Get16BitAsString() const; + // If the UUID has a valid Bluetooth UUID16 alias, return it, otherwise + // return nullopt. + // See Bluetooth Core Specification 6.0 Vol.3, Part B, Section 2.5.1 + std::optional GetBtUuid16() const; std::uint64_t GetMostSigBits() const { return most_sig_bits_; } std::uint64_t GetLeastSigBits() const { return least_sig_bits_; } diff --git a/internal/platform/uuid_test.cc b/internal/platform/uuid_test.cc index 136ef90e..19d59d69 100644 --- a/internal/platform/uuid_test.cc +++ b/internal/platform/uuid_test.cc @@ -143,5 +143,36 @@ TEST(UuidTest, ConstructUuidFromString) { EXPECT_EQ(std::string(*a), "12345678-1234-1234-1234-123456789012"); } +TEST(UuidTest, GetBtUuid16Succeeds) { + std::optional a = + Uuid::FromString("0000ABCD-0000-1000-8000-00805F9B34FB"); + ASSERT_TRUE(a.has_value()); + + std::optional bt_uuid16 = a->GetBtUuid16(); + + ASSERT_TRUE(bt_uuid16.has_value()); + EXPECT_EQ(bt_uuid16, 0xABCD); +} + +TEST(UuidTest, GetBtUuid16FailsMsb) { + std::optional a = + Uuid::FromString("0100ABCD-0000-1000-8000-00805F9B34FB"); + ASSERT_TRUE(a.has_value()); + + std::optional bt_uuid16 = a->GetBtUuid16(); + + EXPECT_FALSE(bt_uuid16.has_value()); +} + +TEST(UuidTest, GetBtUuid16FailsLsb) { + std::optional a = + Uuid::FromString("0000ABCD-0000-1000-8000-00905F9B34FB"); + ASSERT_TRUE(a.has_value()); + + std::optional bt_uuid16 = a->GetBtUuid16(); + + EXPECT_FALSE(bt_uuid16.has_value()); +} + } // namespace } // namespace nearby