From b4b74ca5b4ecb7834a16071f3f683b2e3b31bca5 Mon Sep 17 00:00:00 2001 From: aaronyujiaze Date: Tue, 31 May 2022 12:27:07 -0700 Subject: [PATCH] Add Extended Advertising support in Nearby Connections layer PiperOrigin-RevId: 452112156 --- .../implementation/windows/ble_medium.cc | 52 ++++++-- .../implementation/windows/ble_medium_test.cc | 121 +++++++++++++++++- 2 files changed, 162 insertions(+), 11 deletions(-) diff --git a/internal/platform/implementation/windows/ble_medium.cc b/internal/platform/implementation/windows/ble_medium.cc index 55f49e88..caeaff22 100644 --- a/internal/platform/implementation/windows/ble_medium.cc +++ b/internal/platform/implementation/windows/ble_medium.cc @@ -77,6 +77,11 @@ bool BleMedium::StartAdvertising( DataWriter data_writer; + // TODO(b/234229562): Add parsing logic for fast_advertisement_service_uuid + // and insert into the 0x16 Service Data field in the BLE advertisement when + // Fast Advertisement is enabled. For Extended Advertising, use the same + // hardcoded Copresence service uuid 0xFEF3. + // Copresence Service UUID 0xfef3 (little-endian) data_writer.WriteUInt16(kCopresenceServiceUuid); @@ -93,19 +98,48 @@ bool BleMedium::StartAdvertising( data_sections.Append(service_data); advertisement_.DataSections() = data_sections; - publisher_ = BluetoothLEAdvertisementPublisher(advertisement_); + // Use Extended Advertising if Fast Advertisement Service Uuid is empty string + // because the long format advertisement will be used + if (fast_advertisement_service_uuid.empty()) { + publisher_ = BluetoothLEAdvertisementPublisher(advertisement_); + publisher_.UseExtendedAdvertisement(true); - publisher_token_ = - publisher_.StatusChanged({this, &BleMedium::PublisherHandler}); + publisher_token_ = + publisher_.StatusChanged({this, &BleMedium::PublisherHandler}); - publisher_started_promise_ = std::promise(); + publisher_started_promise_ = std::promise(); - std::future publisher_state_future = - publisher_started_promise_.get_future(); + std::future publisher_state_future = + publisher_started_promise_.get_future(); - publisher_.Start(); + publisher_.Start(); - return publisher_state_future.get() == PublisherState::kStarted; + return publisher_state_future.get() == PublisherState::kStarted; + } else { + // Extended Advertisement not supported, must make sure advertisement_bytes + // is less than 27 bytes + if (advertisement_bytes.size() <= 27) { + publisher_ = BluetoothLEAdvertisementPublisher(advertisement_); + publisher_.UseExtendedAdvertisement(false); + + publisher_token_ = + publisher_.StatusChanged({this, &BleMedium::PublisherHandler}); + + publisher_started_promise_ = std::promise(); + + std::future publisher_state_future = + publisher_started_promise_.get_future(); + + publisher_.Start(); + + return publisher_state_future.get() == PublisherState::kStarted; + } else { + // otherwise no-op + NEARBY_LOGS(INFO) << "Everyone Mode unavailable for hardware that does " + "not support Extended Advertising."; + return false; + } + } } bool BleMedium::StopAdvertising(const std::string& service_id) { @@ -123,6 +157,7 @@ bool BleMedium::StopAdvertising(const std::string& service_id) { return publisher_state_future.get() == PublisherState::kStopped; } +// TODO(b/234229557): Add BlePeripheral discovery logic bool BleMedium::StartScanning( const std::string& service_id, const std::string& fast_advertisement_service_uuid, @@ -158,7 +193,6 @@ bool BleMedium::StartScanning( bool BleMedium::StopScanning(const std::string& service_id) { absl::MutexLock lock(&mutex_); - NEARBY_LOGS(INFO) << "Windows Ble StopScanning: service_id=" << service_id; watcher_stopped_promise_ = std::promise(); diff --git a/internal/platform/implementation/windows/ble_medium_test.cc b/internal/platform/implementation/windows/ble_medium_test.cc index 4f84a1e4..5a894411 100644 --- a/internal/platform/implementation/windows/ble_medium_test.cc +++ b/internal/platform/implementation/windows/ble_medium_test.cc @@ -36,7 +36,7 @@ constexpr uint8_t kFastAdvertisementFlagBitmask = 0x02; constexpr uint8_t kPcpBitmask = 0x1F; constexpr uint8_t kVisibilityBitmask = 0x01; -TEST(BleMedium, DISABLED_StartAdvertising) { +TEST(BleMedium, DISABLED_StartAdvertising_FastAdvertisement) { BluetoothAdapter bluetoothAdapter; BleMedium ble_medium(bluetoothAdapter); @@ -61,7 +61,7 @@ TEST(BleMedium, DISABLED_StartAdvertising) { // (1 byte) body_length advertising_data_byte_array.at(1) = static_cast( - 0x19); // always 25 bytes for Fast Advertisement + 0x17); // always 23 bytes for Fast Advertisement // (1 byte) Nearby Connection version [3-bits] + pcp [5-bits] uint8_t ble_connections_version = @@ -117,6 +117,123 @@ TEST(BleMedium, DISABLED_StartAdvertising) { ble_medium.StartAdvertising("NearbyShare", advertising_data, "\xfe\xf3")); } +TEST(BleMedium, DISABLED_StartAdvertising_ExtendedAdvertising) { + BluetoothAdapter bluetoothAdapter; + BleMedium ble_medium(bluetoothAdapter); + + std::array advertising_data_byte_array; + + // (1 byte) version [3-bits] + socket_version [3-bits] + + // fast_advertisement_flag [1-bit] + reserved [1-bit] + uint8_t ble_medium_version = 0x02; // mediums::BleAdvertisement::Version::kV2 + uint8_t socket_version = + 0x02; // mediums::BleAdvertisement::SocketVersion::kV2 + bool fast_advertisement = false; // Is Fast Advertisement + + uint8_t ble_medium_advertisement_metadata_byte = + (ble_medium_version << 5) & kVersionBitmask; + ble_medium_advertisement_metadata_byte |= + (socket_version << 2) & kSocketVersionBitmask; + ble_medium_advertisement_metadata_byte |= + ((fast_advertisement ? 1 : 0) << 1) & kFastAdvertisementFlagBitmask; + + advertising_data_byte_array.at(0) = + static_cast(ble_medium_advertisement_metadata_byte); + + // (3 bytes) service_id_hash + for (int i = 0; i < 3; ++i) { + advertising_data_byte_array.at(1 + i) = static_cast(0x00); + } + + // (4 bytes) body_length + advertising_data_byte_array.at(7) = static_cast( + 0x9C); // max 156 bytes for Extended Advertising + + // (1 byte) Nearby Connection version [3-bits] + pcp [5-bits] + uint8_t ble_connections_version = + 0x01; // connections::BleAdvertisement::Version::kV1 + uint8_t pcp = 0x02; // connections::Pcp::kP2pCluster + + uint8_t ble_connections_advertisement_metadata_byte = + (ble_connections_version << 5) & kVersionBitmask; + ble_connections_advertisement_metadata_byte |= pcp & kPcpBitmask; + advertising_data_byte_array.at(8) = + static_cast(ble_connections_advertisement_metadata_byte); + + // (3 bytes) service_id_hash + for (int i = 0; i < 3; ++i) { + advertising_data_byte_array.at(9 + i) = static_cast(0x00); + } + + // (4 bytes) endpoint_id + for (int i = 0; i < 4; ++i) { + advertising_data_byte_array.at(12 + i) = static_cast(0x00); + } + + // (1 byte) endpoint_info_size + advertising_data_byte_array.at(16) = static_cast( + 0x83); // max 131-bytes for Extended Advertising + + // =========endpoint_info [Max 131-bytes]============ + // (1 byte) Nearby Share version [3-bits] + visibility [1-bit] + reserved + // [4-bits] + uint8_t nearby_share_version = 0x00; // nearby share v1 + uint8_t visibility = 0x00; // [placeholder] sharing::Visibility::kAllContacts + + uint8_t nearby_share_metadata_byte = + (nearby_share_version << 5) & kVersionBitmask; + nearby_share_metadata_byte |= ((visibility & kVisibilityBitmask) << 4); + + advertising_data_byte_array.at(17) = static_cast(0x00); + + // (2 bytes) salt + for (int i = 0; i < 2; ++i) { + advertising_data_byte_array.at(18 + i) = static_cast(0x00); + } + + // (14 bytes) encrypted_metadata_key + for (int i = 0; i < 14; ++i) { + advertising_data_byte_array.at(20 + i) = static_cast(0x00); + } + + // [optional] + // (1 byte) human_readable_name_size + advertising_data_byte_array.at(34) = static_cast(0x72); + + // [optional] + // (max 114 bytes) human_readable_name + for (int i = 0; i < 114; ++i) { + advertising_data_byte_array.at(35 + i) = static_cast(0x00); + } + // =========endpoint_info [131-bytes]============ + + // (6 bytes) bluetooth_mac_address + for (int i = 0; i < 6; ++i) { + advertising_data_byte_array.at(149 + i) = static_cast(0x00); + } + + // (1 byte) uwb_address_size + advertising_data_byte_array.at(155) = static_cast(0x72); + + // (8 bytes) uwb_address + for (int i = 0; i < 6; ++i) { + advertising_data_byte_array.at(156 + i) = static_cast(0x00); + } + + // (1 byte) extra_field [web_rtc_connectable] + advertising_data_byte_array.at(164) = static_cast(0x72); + + // (2 bytes) device_token + for (int i = 0; i < 2; ++i) { + advertising_data_byte_array.at(165 + i) = static_cast(0x00); + } + + ByteArray advertising_data(advertising_data_byte_array); + + EXPECT_TRUE( + ble_medium.StartAdvertising("NearbyShare", advertising_data, "")); +} + TEST(BleMedium, DISABLED_StopAdvertising) { BluetoothAdapter bluetoothAdapter; BleMedium ble_medium(bluetoothAdapter);