From 01f439b9ad439e222363235957e224dcedd3122d Mon Sep 17 00:00:00 2001 From: edwinwu Date: Wed, 18 May 2022 17:43:34 -0700 Subject: [PATCH] [BLE Refactor] Add Extended advertisement support. PiperOrigin-RevId: 449619994 --- connections/implementation/mediums/BUILD | 1 + connections/implementation/mediums/ble_v2.cc | 367 +++++++++++------- connections/implementation/mediums/ble_v2.h | 34 +- .../mediums/ble_v2/ble_advertisement.h | 1 + .../ble_v2/ble_advertisement_header.cc | 12 +- .../mediums/ble_v2/ble_advertisement_header.h | 15 +- .../ble_v2/ble_advertisement_header_test.cc | 7 +- .../ble_v2/discovered_peripheral_tracker.cc | 50 ++- .../ble_v2/discovered_peripheral_tracker.h | 13 + .../discovered_peripheral_tracker_test.cc | 36 -- internal/platform/ble_v2.cc | 20 +- internal/platform/ble_v2.h | 11 +- internal/platform/ble_v2_test.cc | 65 ++-- internal/platform/implementation/ble_v2.h | 63 ++- internal/platform/implementation/g3/ble_v2.cc | 55 +-- internal/platform/implementation/g3/ble_v2.h | 13 +- .../platform/implementation/windows/ble_v2.cc | 91 ++--- .../platform/implementation/windows/ble_v2.h | 13 +- .../implementation/windows/ble_v2_test.cc | 11 +- internal/platform/medium_environment.cc | 19 +- 20 files changed, 513 insertions(+), 384 deletions(-) diff --git a/connections/implementation/mediums/BUILD b/connections/implementation/mediums/BUILD index 8d6cc2f7..1bf4f9cb 100644 --- a/connections/implementation/mediums/BUILD +++ b/connections/implementation/mediums/BUILD @@ -50,6 +50,7 @@ cc_library( "//internal/platform:logging", "//internal/platform:types", "//proto/mediums:web_rtc_signaling_frames_cc_proto", + "@com_google_absl//absl/container:btree", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/functional:bind_front", diff --git a/connections/implementation/mediums/ble_v2.cc b/connections/implementation/mediums/ble_v2.cc index 7025c6d2..c8de4a85 100644 --- a/connections/implementation/mediums/ble_v2.cc +++ b/connections/implementation/mediums/ble_v2.cc @@ -19,7 +19,6 @@ #include #include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" #include "connections/implementation/mediums/ble_v2/ble_advertisement.h" #include "connections/implementation/mediums/ble_v2/ble_advertisement_header.h" #include "connections/implementation/mediums/ble_v2/ble_utils.h" @@ -40,7 +39,7 @@ namespace { using ::location::nearby::api::ble_v2::BleAdvertisementData; using ::location::nearby::api::ble_v2::GattCharacteristic; -using ::location::nearby::api::ble_v2::PowerMode; +using ::location::nearby::api::ble_v2::TxPowerLevel; constexpr int kMaxAdvertisementLength = 512; constexpr int kDummyServiceIdLength = 128; @@ -62,8 +61,8 @@ BleV2::~BleV2() { while (!scanned_service_ids_.empty()) { StopScanning(*scanned_service_ids_.begin()); } - while (!advertising_service_ids_.empty()) { - StopAdvertising(*advertising_service_ids_.begin()); + while (!advertising_infos_.empty()) { + StopAdvertising(advertising_infos_.begin()->first); } serial_executor_.Shutdown(); @@ -76,7 +75,6 @@ bool BleV2::IsAvailable() const { return IsAvailableLocked(); } -// TODO(edwinwu): Break down the function. bool BleV2::StartAdvertising(const std::string& service_id, const ByteArray& advertisement_bytes, PowerLevel power_level, @@ -117,152 +115,99 @@ bool BleV2::StartAdvertising(const std::string& service_id, // Wrap the connections advertisement to the medium advertisement. ByteArray service_id_hash = mediums::bleutils::GenerateHash( service_id, mediums::BleAdvertisement::kServiceIdHashLength); - ByteArray medium_advertisement_bytes{mediums::BleAdvertisement{ + // Get psm value from L2CAP server if L2CAP is supported. Now just use the + // default value. + int psm = mediums::BleAdvertisementHeader::kDefaultPsmValue; + mediums::BleAdvertisement medium_advertisement = { mediums::BleAdvertisement::Version::kV2, mediums::BleAdvertisement::SocketVersion::kV2, /*service_id_hash=*/is_fast_advertisement ? ByteArray{} : service_id_hash, - advertisement_bytes, mediums::bleutils::GenerateDeviceToken(), - mediums::BleAdvertisementHeader::kDefaultPsmValue}}; - if (medium_advertisement_bytes.Empty()) { + advertisement_bytes, + mediums::bleutils::GenerateDeviceToken(), + psm}; + if (!medium_advertisement.IsValid()) { NEARBY_LOGS(INFO) << "Failed to BLE advertise because we could not wrap a " "connection advertisement to medium advertisement."; return false; } - // Assemble AdvertisingData and ScanResponseData. - BleAdvertisementData advertising_data; - BleAdvertisementData scan_response_data; - if (is_fast_advertisement) { - advertising_data.is_connectable = true; - advertising_data.tx_power_level = - BleAdvertisementData::kUnspecifiedTxPowerLevel; - advertising_data.service_uuids.insert( - std::string(mediums::bleutils::kCopresenceServiceUuid)); + advertising_infos_.insert( + {service_id, + AdvertisingInfo{.medium_advertisement = medium_advertisement, + .power_level = power_level, + .is_fast_advertisement = is_fast_advertisement}}); - scan_response_data.is_connectable = true; - scan_response_data.tx_power_level = - BleAdvertisementData::kUnspecifiedTxPowerLevel; - scan_response_data.service_data.insert( - {std::string(mediums::bleutils::kCopresenceServiceUuid), - medium_advertisement_bytes}); - } else { - // Stop the current advertisement GATT server if there are no incoming - // sockets connected to this device. - // - // The reason for aggressively restarting a GATT server is to make sure this - // class is not using a stale server object that may not be actually running - // anymore (possibly due to Bluetooth being turned off). - // - // Changing one's GATT server while a remote device is connected to it leads - // to a loss of GATT callbacks for that remote device. The only time a - // remote device is indefinitely connected to this device's GATT server is - // when it has a BLE socket connection. - // TODO(b/213835576): Check the BLE Connections is off. We set the fake - // value for the time being till connections is implemented. - bool no_incoming_ble_sockets = true; - if (no_incoming_ble_sockets) { - NEARBY_LOGS(VERBOSE) - << "Aggressively stopping any pre-existing advertisement GATT " - "servers because no incoming BLE sockets are connected"; - StopAdvertisementGattServerLocked(); - } + // Stop the pre-existing BLE advertisement if there is one. + medium_.StopAdvertising(); - // Start a GATT server to deliver the full advertisement data. If fail to - // advertise the header, we must shut this down before the method returns. - if (!IsAdvertisementGattServerRunningLocked()) { - if (!StartAdvertisementGattServerLocked(service_id, - medium_advertisement_bytes)) { - NEARBY_LOGS(ERROR) - << "Failed to start BLE advertising for service_id=" << service_id - << " because the advertisement GATT server failed to start."; - return false; - } - } - - ByteArray advertisement_header_bytes(CreateAdvertisementHeader()); - if (advertisement_header_bytes.Empty()) { - NEARBY_LOGS(INFO) << "Failed to BLE advertise because we could not " - "create an advertisement header."; - // Failed to start BLE advertising, so stop the advertisement GATT - // server. - StopAdvertisementGattServerLocked(); - return false; - } - - advertising_data.is_connectable = true; - advertising_data.tx_power_level = - BleAdvertisementData::kUnspecifiedTxPowerLevel; - - scan_response_data.is_connectable = true; - scan_response_data.tx_power_level = - BleAdvertisementData::kUnspecifiedTxPowerLevel; - scan_response_data.service_uuids.insert( - std::string(mediums::bleutils::kCopresenceServiceUuid)); - scan_response_data.service_data.insert( - {std::string(mediums::bleutils::kCopresenceServiceUuid), - advertisement_header_bytes}); - } - - if (!medium_.StartAdvertising(advertising_data, scan_response_data, - PowerLevelToPowerMode(power_level))) { - NEARBY_LOGS(ERROR) - << "Failed to turn on BLE advertising with advertisement bytes=" - << absl::BytesToHexString(advertisement_bytes.data()) - << ", is_fast_advertisement=" << is_fast_advertisement; - - // If BLE advertising was not successful, stop the advertisement GATT - // server. - StopAdvertisementGattServerLocked(); + if (!StartAdvertisingLocked(service_id)) { + advertising_infos_.erase(service_id); return false; } - - NEARBY_LOGS(INFO) << "Started BLE advertising with advertisement bytes=" - << absl::BytesToHexString(advertisement_bytes.data()) - << " for service_id=" << service_id; - advertising_service_ids_.insert(service_id); return true; } bool BleV2::StopAdvertising(const std::string& service_id) { MutexLock lock(&mutex_); - if (!IsAdvertisingLocked(service_id)) { NEARBY_LOGS(INFO) << "Cannot stop BLE advertising for service_id=" << service_id << " because it never started."; return false; } + // Stop the BLE advertisement. We will restart it later if necessary. + NEARBY_LOGS(INFO) << "Turned off BLE advertising with service_id=" + << service_id; + advertising_infos_.erase(service_id); + medium_.StopAdvertising(); + // Remove the GATT advertisements. gatt_advertisements_.clear(); + // Restart the BLE advertisement if there is still an advertiser. // TODO(b/213835576): Check the BLE Connections is off. We set the fake // value for the time being till connections is implemented. bool no_incoming_ble_sockets = true; - // Set the value of characteristic to empty if there is still an advertiser. - if (!hosted_gatt_characteristics_.empty()) { - ByteArray empty_value = {}; - for (const auto& characteristic : hosted_gatt_characteristics_) { - if (!gatt_server_->UpdateCharacteristic(characteristic, empty_value)) { - NEARBY_LOGS(ERROR) - << "Failed to clear characteristic uuid=" << characteristic.uuid - << " after stopping BLE advertisement for service_id=" - << service_id; + if (advertising_infos_.empty() && !no_incoming_ble_sockets) { + return true; + } + if (!advertising_infos_.empty()) { + if (!hosted_gatt_characteristics_.empty()) { + // Set the value of characteristic to empty if there is still an + // advertiser. + ByteArray empty_value = {}; + for (const auto& characteristic : hosted_gatt_characteristics_) { + if (!gatt_server_->UpdateCharacteristic(characteristic, empty_value)) { + NEARBY_LOGS(ERROR) + << "Failed to clear characteristic uuid=" << characteristic.uuid + << " after stopping BLE advertisement for service_id=" + << service_id; + } } + hosted_gatt_characteristics_.clear(); } - hosted_gatt_characteristics_.clear(); - } else if (no_incoming_ble_sockets) { - // Otherwise, if we aren't restarting the BLE advertisement, then shutdown - // the gatt server if it's not in use. - NEARBY_LOGS(VERBOSE) - << "Aggressively stopping any pre-existing advertisement GATT servers " - "because no incoming BLE sockets are connected."; - StopAdvertisementGattServerLocked(); + // Get the next service_id to restart BLE advertisement. + const std::string& service_id = advertising_infos_.begin()->first; + if (!StartAdvertisingLocked(service_id)) { + NEARBY_LOGS(ERROR) + << "Failed to restart BLE advertisement after stopping " + "BLE advertisement for service_id=" + << service_id; + advertising_infos_.erase(service_id); + return false; + } + NEARBY_LOGS(INFO) << "Restart BLE advertising with service_id=" + << service_id; + return true; } - NEARBY_LOGS(INFO) << "Turned off BLE advertising with service_id=" - << service_id; - advertising_service_ids_.erase(service_id); - return medium_.StopAdvertising(); + // If we aren't restarting the BLE advertisement, then shutdown + // the gatt server if it's not in use. + NEARBY_LOGS(VERBOSE) << "Aggressively stopping any pre-existing " + "advertisement GATT servers " + "because no incoming BLE sockets are connected."; + StopAdvertisementGattServerLocked(); + return true; } bool BleV2::IsAdvertising(const std::string& service_id) const { @@ -317,7 +262,7 @@ bool BleV2::StartScanning(const std::string& service_id, PowerLevel power_level, // changed. if (!medium_.StartScanning( std::string(mediums::bleutils::kCopresenceServiceUuid), - PowerLevelToPowerMode(power_level), + PowerLevelToTxPowerLevel(power_level), { .advertisement_found_cb = [this](BleV2Peripheral peripheral, @@ -406,7 +351,7 @@ bool BleV2::IsScanning(const std::string& service_id) const { bool BleV2::IsAvailableLocked() const { return medium_.IsValid(); } bool BleV2::IsAdvertisingLocked(const std::string& service_id) const { - return advertising_service_ids_.contains(service_id); + return advertising_infos_.contains(service_id); } bool BleV2::IsScanningLocked(const std::string& service_id) const { @@ -499,7 +444,7 @@ void BleV2::ProcessFetchGattAdvertisementsRequest( // from the GATT server. bool read_success = true; std::unique_ptr gatt_client = medium_.ConnectToGattServer( - std::move(peripheral), PowerLevelToPowerMode(PowerLevel::kHighPower), + std::move(peripheral), PowerLevelToTxPowerLevel(PowerLevel::kHighPower), /*ClientGattConnectionCallback=*/{}); if (!gatt_client || !gatt_client->IsValid()) { advertisement_read_result.RecordLastReadStatus(false); @@ -565,7 +510,8 @@ bool BleV2::StopAdvertisementGattServerLocked() { return true; } -ByteArray BleV2::CreateAdvertisementHeader() { +ByteArray BleV2::CreateAdvertisementHeader( + int psm, bool extended_advertisement_advertised) { // Create a randomized dummy service id to anonymize the header with. ByteArray dummy_service_id_bytes = Utils::GenerateRandomBytes(kDummyServiceIdLength); @@ -583,8 +529,7 @@ ByteArray BleV2::CreateAdvertisementHeader() { const ByteArray& gatt_advertisement = item.second.second; bloom_filter.Add(service_id); - // Compute the next hash according to the algorithm in - // https://source.corp.google.com/piper///depot/google3/java/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/mediums/bluetooth/BluetoothLowEnergy.java;rcl=428397891;l=1043 + // Compute the next hash. std::string advertisement_bodies = absl::StrCat( advertisement_hash.AsStringView(), gatt_advertisement.AsStringView()); @@ -594,21 +539,183 @@ ByteArray BleV2::CreateAdvertisementHeader() { return ByteArray(mediums::BleAdvertisementHeader( mediums::BleAdvertisementHeader::Version::kV2, - /*extended_advertisement=*/false, + extended_advertisement_advertised, /*num_slots=*/gatt_advertisements_.size(), ByteArray(bloom_filter), - advertisement_hash, /*psm=*/0)); + advertisement_hash, psm)); } -PowerMode BleV2::PowerLevelToPowerMode(PowerLevel power_level) { +bool BleV2::StartAdvertisingLocked(const std::string& service_id) { + const auto it = advertising_infos_.find(service_id); + if (it == advertising_infos_.end()) { + NEARBY_LOGS(WARNING) << "Failed to BLE advertise with service_id=" + << service_id; + return false; + } + + const AdvertisingInfo& info = it->second; + if (info.is_fast_advertisement) { + return StartFastAdvertisingLocked(info.power_level, + info.medium_advertisement); + } else { + return StartRegularAdvertisingLocked(service_id, info.power_level, + info.medium_advertisement); + } +} + +bool BleV2::StartFastAdvertisingLocked( + PowerLevel power_level, + const mediums::BleAdvertisement& medium_advertisement) { + // Begin building the fast BLE advertisement. + BleAdvertisementData advertising_data; + ByteArray medium_advertisement_bytes = ByteArray(medium_advertisement); + advertising_data.is_extended_advertisement = false; + advertising_data.service_data.insert( + {std::string(mediums::bleutils::kCopresenceServiceUuid), + medium_advertisement_bytes}); + + // Finally, start the fast advertising operation. + if (!medium_.StartAdvertising( + advertising_data, + {.tx_power_level = PowerLevelToTxPowerLevel(power_level), + .is_connectable = true})) { + NEARBY_LOGS(ERROR) << "Failed to turn on BLE fast advertising with " + "advertisement bytes=" + << absl::BytesToHexString( + medium_advertisement_bytes.data()); + return false; + } + return true; +} + +bool BleV2::StartRegularAdvertisingLocked( + const std::string& service_id, PowerLevel power_level, + const mediums::BleAdvertisement& medium_advertisement) { + // Begin building the regular BLE advertisement. + BleAdvertisementData advertising_data; + ByteArray medium_advertisement_bytes = + medium_.IsExtendedAdvertisementsAvailable() + ? medium_advertisement.ByteArrayWithExtraField() + : ByteArray(medium_advertisement); + + // Start extended advertisement first if available. + bool extended_regular_advertisement_success = false; + if (medium_.IsExtendedAdvertisementsAvailable()) { + advertising_data.is_extended_advertisement = true; + advertising_data.service_data.insert( + {std::string(mediums::bleutils::kCopresenceServiceUuid), + medium_advertisement_bytes}); + + // Start the extended regular advertising operation. + extended_regular_advertisement_success = medium_.StartAdvertising( + advertising_data, + {.tx_power_level = PowerLevelToTxPowerLevel(power_level), + .is_connectable = true}); + if (!extended_regular_advertisement_success) { + NEARBY_LOGS(ERROR) + << "Failed to turn on BLE extended regular advertising with " + "advertisement bytes=" + << absl::BytesToHexString(medium_advertisement_bytes.data()); + } + } + + // Start GATT advertisement no matter extended advertisment succeeded or not. + // This is to ensure that legacy devices which don't support extended + // advertisement can get the advertisement via GATT connection. + bool gatt_advertisement_success = StartGattAdvertisingLocked( + service_id, power_level, medium_advertisement.GetPsm(), + medium_advertisement_bytes, extended_regular_advertisement_success); + + return extended_regular_advertisement_success || gatt_advertisement_success; +} + +bool BleV2::StartGattAdvertisingLocked( + const std::string& service_id, PowerLevel power_level, int psm, + const ByteArray& medium_advertisement_bytes, + bool extended_advertisement_advertised) { + // Begin building the GATT BLE advertisement header. + BleAdvertisementData advertising_data; + advertising_data.is_extended_advertisement = false; + + // Stop the current advertisement GATT server if there are no incoming + // sockets connected to this device. + // + // The reason for aggressively restarting a GATT server is to make sure this + // class is not using a stale server object that may not be actually running + // anymore (possibly due to Bluetooth being turned off). + // + // Changing one's GATT server while a remote device is connected to it leads + // to a loss of GATT callbacks for that remote device. The only time a + // remote device is indefinitely connected to this device's GATT server is + // when it has a BLE socket connection. + // TODO(b/213835576): Check the BLE Connections is off. We set the fake + // value for the time being till connections is implemented. + bool no_incoming_ble_sockets = true; + if (no_incoming_ble_sockets) { + NEARBY_LOGS(VERBOSE) + << "Aggressively stopping any pre-existing advertisement GATT " + "servers because no incoming BLE sockets are connected"; + StopAdvertisementGattServerLocked(); + } + + // Start a GATT server to deliver the full advertisement data. If fail to + // advertise the header, we must shut this down before the method returns. + if (!IsAdvertisementGattServerRunningLocked()) { + if (!StartAdvertisementGattServerLocked(service_id, + medium_advertisement_bytes)) { + NEARBY_LOGS(ERROR) + << "Failed to turn on BLE GATT advertising for service_id=" + << service_id + << " because the advertisement GATT server failed to start."; + return false; + } + } + + // Begin building the regular BLE advertisement (backed by a GATT server). + // Add the advertisement header. + ByteArray advertisement_header_bytes = + CreateAdvertisementHeader(psm, extended_advertisement_advertised); + if (advertisement_header_bytes.Empty()) { + NEARBY_LOGS(ERROR) + << "Failed to turn on BLE GATT advertising because we could not " + "create an advertisement header."; + // Failed to create an advertisement header, so stop the advertisement + // GATT server. + StopAdvertisementGattServerLocked(); + return false; + } + + advertising_data.service_data.insert( + {std::string(mediums::bleutils::kCopresenceServiceUuid), + advertisement_header_bytes}); + + // Finally, start the regular advertising operation. + if (!medium_.StartAdvertising( + advertising_data, + {.tx_power_level = PowerLevelToTxPowerLevel(power_level), + .is_connectable = true})) { + NEARBY_LOGS(ERROR) << "Failed to turn on BLE GATT advertising with " + "advertisement bytes=" + << absl::BytesToHexString( + medium_advertisement_bytes.data()); + // If BLE advertising was not successful, stop the advertisement GATT + // server. + StopAdvertisementGattServerLocked(); + return false; + } + + return true; +} + +TxPowerLevel BleV2::PowerLevelToTxPowerLevel(PowerLevel power_level) { switch (power_level) { case PowerLevel::kHighPower: - return PowerMode::kHigh; + return TxPowerLevel::kHigh; case PowerLevel::kLowPower: // Medium power is about the size of a conference room. // Any lower and we won't be visible at a distance. - return PowerMode::kMedium; + return TxPowerLevel::kMedium; default: - return PowerMode::kUnknown; + return TxPowerLevel::kUnknown; } } diff --git a/connections/implementation/mediums/ble_v2.h b/connections/implementation/mediums/ble_v2.h index 5d883860..ea1e40d6 100644 --- a/connections/implementation/mediums/ble_v2.h +++ b/connections/implementation/mediums/ble_v2.h @@ -20,9 +20,11 @@ #include #include +#include "absl/container/btree_map.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "connections/implementation/mediums/ble_v2/advertisement_read_result.h" +#include "connections/implementation/mediums/ble_v2/ble_advertisement.h" #include "connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h" #include "connections/implementation/mediums/bluetooth_radio.h" #include "connections/power_level.h" @@ -63,8 +65,7 @@ class BleV2 final { // but much more efficient to discover. bool StartAdvertising(const std::string& service_id, const ByteArray& advertisement_bytes, - PowerLevel power_level, - bool is_fast_advertisement) + PowerLevel power_level, bool is_fast_advertisement) ABSL_LOCKS_EXCLUDED(mutex_); // Disables BLE advertising. @@ -101,6 +102,12 @@ class BleV2 final { } private: + struct AdvertisingInfo { + mediums::BleAdvertisement medium_advertisement; + PowerLevel power_level; + bool is_fast_advertisement; + }; + // Same as IsAvailable(), but must be called with `mutex_` held. bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); @@ -129,9 +136,26 @@ class BleV2 final { bool StopAdvertisementGattServerLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - ByteArray CreateAdvertisementHeader() ABSL_SHARED_LOCKS_REQUIRED(mutex_); + ByteArray CreateAdvertisementHeader(int psm, + bool extended_advertisement_advertised) + ABSL_SHARED_LOCKS_REQUIRED(mutex_); + bool StartAdvertisingLocked(const std::string& service_id) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + bool StartFastAdvertisingLocked( + PowerLevel power_level, + const mediums::BleAdvertisement& medium_advertisement) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + bool StartRegularAdvertisingLocked( + const std::string& service_id, PowerLevel power_level, + const mediums::BleAdvertisement& medium_advertisement) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + bool StartGattAdvertisingLocked(const std::string& service_id, + PowerLevel power_level, int psm, + const ByteArray& medium_advertisement_bytes, + bool extended_advertisement_advertised) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - api::ble_v2::PowerMode PowerLevelToPowerMode(PowerLevel power_level); + api::ble_v2::TxPowerLevel PowerLevelToTxPowerLevel(PowerLevel power_level); void RunOnBleThread(Runnable runnable); @@ -142,7 +166,7 @@ class BleV2 final { BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_); BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_); BleV2Medium medium_ ABSL_GUARDED_BY(mutex_){adapter_}; - absl::flat_hash_set advertising_service_ids_ + absl::btree_map advertising_infos_ ABSL_GUARDED_BY(mutex_); std::unique_ptr gatt_server_ ABSL_GUARDED_BY(mutex_); absl::flat_hash_map> diff --git a/connections/implementation/mediums/ble_v2/ble_advertisement.h b/connections/implementation/mediums/ble_v2/ble_advertisement.h index a5bb5407..82e7ba67 100644 --- a/connections/implementation/mediums/ble_v2/ble_advertisement.h +++ b/connections/implementation/mediums/ble_v2/ble_advertisement.h @@ -98,6 +98,7 @@ class BleAdvertisement { const ByteArray &&GetData() const && { return std::move(data_); } ByteArray GetDeviceToken() const { return device_token_; } int GetPsm() const { return psm_; } + void SetPsm(int psm) { psm_ = psm; } private: // Represents the extra fields of the `BleAdvertisement` used in Advertising + diff --git a/connections/implementation/mediums/ble_v2/ble_advertisement_header.cc b/connections/implementation/mediums/ble_v2/ble_advertisement_header.cc index 674bbd39..041425d5 100644 --- a/connections/implementation/mediums/ble_v2/ble_advertisement_header.cc +++ b/connections/implementation/mediums/ble_v2/ble_advertisement_header.cc @@ -20,7 +20,6 @@ #include #include "absl/strings/str_cat.h" -#include "internal/platform/base64_utils.h" #include "internal/platform/base_input_stream.h" #include "internal/platform/logging.h" @@ -36,7 +35,7 @@ constexpr int BleAdvertisementHeader::kDefaultPsmValue; constexpr int BleAdvertisementHeader::kPsmValueByteLength; BleAdvertisementHeader::BleAdvertisementHeader( - Version version, bool extended_advertisement, int num_slots, + Version version, bool support_extended_advertisement, int num_slots, const ByteArray &service_id_bloom_filter, const ByteArray &advertisement_hash, int psm) { if (version != Version::kV2 || num_slots < 0 || @@ -46,7 +45,7 @@ BleAdvertisementHeader::BleAdvertisementHeader( } version_ = version; - extended_advertisement_ = extended_advertisement; + support_extended_advertisement_ = support_extended_advertisement; num_slots_ = num_slots; service_id_bloom_filter_ = service_id_bloom_filter; advertisement_hash_ = advertisement_hash; @@ -87,7 +86,7 @@ BleAdvertisementHeader::BleAdvertisementHeader( return; } // The next 1 bit is supposed to be the extended advertisement flag. - extended_advertisement_ = + support_extended_advertisement_ = ((version_and_num_slots_byte & kExtendedAdvertismentBitMask) >> 4) == 1; // The lower 4 bits are supposed to be the number of slots. num_slots_ = static_cast(version_and_num_slots_byte & kNumSlotsBitmask); @@ -120,7 +119,7 @@ BleAdvertisementHeader::operator ByteArray() const { (static_cast(version_) << 5) & kVersionBitmask; // The next 1 bit is extended advertisement flag. version_and_num_slots_byte |= - (static_cast(extended_advertisement_) << 4) & + (static_cast(support_extended_advertisement_) << 4) & kExtendedAdvertismentBitMask; // The next 5 bits are the number of slots. version_and_num_slots_byte |= @@ -145,7 +144,8 @@ BleAdvertisementHeader::operator ByteArray() const { bool BleAdvertisementHeader::operator==( const BleAdvertisementHeader &rhs) const { return GetVersion() == rhs.GetVersion() && - IsExtendedAdvertisement() == rhs.IsExtendedAdvertisement() && + IsSupportExtendedAdvertisement() == + rhs.IsSupportExtendedAdvertisement() && GetNumSlots() == rhs.GetNumSlots() && GetServiceIdBloomFilter() == rhs.GetServiceIdBloomFilter() && GetAdvertisementHash() == rhs.GetAdvertisementHash() && diff --git a/connections/implementation/mediums/ble_v2/ble_advertisement_header.h b/connections/implementation/mediums/ble_v2/ble_advertisement_header.h index 9d37d8b3..ba4763f5 100644 --- a/connections/implementation/mediums/ble_v2/ble_advertisement_header.h +++ b/connections/implementation/mediums/ble_v2/ble_advertisement_header.h @@ -60,13 +60,14 @@ class BleAdvertisementHeader { bool operator==(const BleAdvertisementHeader &rhs) const; template friend H AbslHashValue(H h, const BleAdvertisementHeader &b) { - return H::combine(std::move(h), b.version_, b.extended_advertisement_, - b.num_slots_, b.service_id_bloom_filter_, - b.advertisement_hash_, b.psm_); + return H::combine(std::move(h), b.version_, + b.support_extended_advertisement_, b.num_slots_, + b.service_id_bloom_filter_, b.advertisement_hash_, + b.psm_); } BleAdvertisementHeader() = default; - BleAdvertisementHeader(Version version, bool extended_advertisement, + BleAdvertisementHeader(Version version, bool support_extended_advertisement, int num_slots, const ByteArray &service_id_bloom_filter, const ByteArray &advertisement_hash, int psm); @@ -82,7 +83,9 @@ class BleAdvertisementHeader { bool IsValid() const { return version_ == Version::kV2; } Version GetVersion() const { return version_; } - bool IsExtendedAdvertisement() const { return extended_advertisement_; } + bool IsSupportExtendedAdvertisement() const { + return support_extended_advertisement_; + } int GetNumSlots() const { return num_slots_; } ByteArray GetServiceIdBloomFilter() const { return service_id_bloom_filter_; } ByteArray GetAdvertisementHash() const { return advertisement_hash_; } @@ -99,7 +102,7 @@ class BleAdvertisementHeader { static constexpr int kNumSlotsBitmask = 0x00F; Version version_ = Version::kUndefined; - bool extended_advertisement_ = false; + bool support_extended_advertisement_ = false; int num_slots_ = 0; ByteArray service_id_bloom_filter_; ByteArray advertisement_hash_; diff --git a/connections/implementation/mediums/ble_v2/ble_advertisement_header_test.cc b/connections/implementation/mediums/ble_v2/ble_advertisement_header_test.cc index 0c712df2..5e746cbc 100644 --- a/connections/implementation/mediums/ble_v2/ble_advertisement_header_test.cc +++ b/connections/implementation/mediums/ble_v2/ble_advertisement_header_test.cc @@ -18,7 +18,6 @@ #include "gtest/gtest.h" #include "absl/hash/hash_testing.h" -#include "internal/platform/base64_utils.h" namespace location { namespace nearby { @@ -44,7 +43,7 @@ TEST(BleAdvertisementHeaderTest, ConstructionWorks) { EXPECT_TRUE(ble_advertisement_header.IsValid()); EXPECT_EQ(kVersion, ble_advertisement_header.GetVersion()); - EXPECT_FALSE(ble_advertisement_header.IsExtendedAdvertisement()); + EXPECT_FALSE(ble_advertisement_header.IsSupportExtendedAdvertisement()); EXPECT_EQ(kNumSlots, ble_advertisement_header.GetNumSlots()); EXPECT_EQ(service_id_bloom_filter, ble_advertisement_header.GetServiceIdBloomFilter()); @@ -161,7 +160,7 @@ TEST(BleAdvertisementHeaderTest, ConstructionFromSerializedStringWorks) { EXPECT_TRUE(ble_advertisement_header.IsValid()); EXPECT_EQ(kVersion, ble_advertisement_header.GetVersion()); - EXPECT_FALSE(ble_advertisement_header.IsExtendedAdvertisement()); + EXPECT_FALSE(ble_advertisement_header.IsSupportExtendedAdvertisement()); EXPECT_EQ(kNumSlots, ble_advertisement_header.GetNumSlots()); EXPECT_EQ(service_id_bloom_filter, ble_advertisement_header.GetServiceIdBloomFilter()); @@ -188,7 +187,7 @@ TEST(BleAdvertisementHeaderTest, ConstructionFromExtraBytesWorks) { EXPECT_TRUE(long_ble_advertisement_header.IsValid()); EXPECT_EQ(kVersion, long_ble_advertisement_header.GetVersion()); - EXPECT_FALSE(ble_advertisement_header.IsExtendedAdvertisement()); + EXPECT_FALSE(ble_advertisement_header.IsSupportExtendedAdvertisement()); EXPECT_EQ(kNumSlots, long_ble_advertisement_header.GetNumSlots()); EXPECT_EQ(service_id_bloom_filter, long_ble_advertisement_header.GetServiceIdBloomFilter()); diff --git a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc index 11b4e228..8501e4e0 100644 --- a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc +++ b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.cc @@ -15,6 +15,7 @@ #include "connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h" #include +#include #include #include #include @@ -84,6 +85,12 @@ void DiscoveredPeripheralTracker::ProcessFoundBleAdvertisement( return; } + if (IsSkippableGattAdvertisement(advertisement_data)) { + NEARBY_LOGS(INFO) + << "Ignore GATT advertisement and wait for extended advertisement."; + return; + } + HandleAdvertisement(peripheral, advertisement_data); HandleAdvertisementHeader(peripheral, advertisement_data, std::move(advertisement_fetcher)); @@ -129,6 +136,21 @@ void DiscoveredPeripheralTracker::ClearDataForServiceId( } } +bool DiscoveredPeripheralTracker::IsSkippableGattAdvertisement( + const api::ble_v2::BleAdvertisementData& advertisement_data) { + if (!is_extended_advertisement_available_) { + // Don't skip any advertisement if the scanner doesn't support extended + // advertisement. + return false; + } + + BleAdvertisementHeader advertisement_header( + ExtractAdvertisementHeaderBytes(advertisement_data)); + + return advertisement_header.IsValid() && + advertisement_header.IsSupportExtendedAdvertisement(); +} + void DiscoveredPeripheralTracker::ClearGattAdvertisement( const BleAdvertisement& gatt_advertisement) { const auto gai_it = gatt_advertisement_infos_.find(gatt_advertisement); @@ -176,18 +198,17 @@ void DiscoveredPeripheralTracker::HandleAdvertisement( // First filter out kCopresenceServiceUuid and see if any Caller UUID // existed; if not then just take the kCopresenceServiceUuid as // |service_uuid|. - std::vector extracted_uuids; + absl::flat_hash_map extracted_uuids; // Filter out kCoprsence service uuid. - std::remove_copy_if(advertisement_data.service_uuids.begin(), - advertisement_data.service_uuids.end(), - std::back_inserter(extracted_uuids), - [](const std::string& advertisement_data_service_uuid) { - return advertisement_data_service_uuid == - bleutils::kCopresenceServiceUuid; - }); + std::remove_copy_if( + advertisement_data.service_data.begin(), + advertisement_data.service_data.end(), + std::inserter(extracted_uuids, extracted_uuids.end()), + [](const std::pair& + pair) { return pair.first == bleutils::kCopresenceServiceUuid; }); std::string service_uuid; if (!extracted_uuids.empty()) { - service_uuid = extracted_uuids.front(); + service_uuid = extracted_uuids.begin()->first; } else { service_uuid = std::string(bleutils::kCopresenceServiceUuid); } @@ -214,9 +235,9 @@ ByteArray DiscoveredPeripheralTracker::ExtractInterestingAdvertisementBytes( // advertisements are contained within this BLE advertisement. for (const auto& item : service_id_infos_) { const ServiceIdInfo& service_id_info = item.second; - // Check if there's service data for this fast advertisement - // service UUID. If so, we can short-circuit since all BLE - // advertisements can contain at most ONE fast advertisement. + // Check if there's service data for this fast advertisement service UUID. + // If so, we can short-circuit since all BLE advertisements can contain at + // most ONE fast advertisement. const auto sd_it = advertisement_data.service_data.find( service_id_info.fast_advertisement_service_uuid); if (sd_it != advertisement_data.service_data.end()) { @@ -410,10 +431,7 @@ bool DiscoveredPeripheralTracker::ShouldRemoveHeader( // remove the physical header for the new incoming regular extended // advertisement. Otherwise, it make the device to fetch advertisement when // received a physical header again. - // TODO(b/213835576) : Implement API to fetch the support for extended - // advertisement from platform impl. - bool is_extended_advertisement_available = false; - if (is_extended_advertisement_available) { + if (is_extended_advertisement_available_) { if (!IsDummyAdvertisementHeader(old_advertisement_header) && IsDummyAdvertisementHeader(new_advertisement_header)) { return false; diff --git a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h index f5d4b082..88127ce0 100644 --- a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h +++ b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker.h @@ -59,6 +59,11 @@ class DiscoveredPeripheralTracker { mediums::AdvertisementReadResult&>(); }; + explicit DiscoveredPeripheralTracker( + bool is_extended_advertisement_available = false) + : is_extended_advertisement_available_( + is_extended_advertisement_available) {} + // Starts tracking discoveries for a particular service Id. // // service_id - The service ID to track. @@ -138,6 +143,13 @@ class DiscoveredPeripheralTracker { void ClearDataForServiceId(const std::string& service_id) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + // Returns true if `advertisement_data` is AdvertisementHeader and is marked + // as exented_advertisement. This is to avoid reading advertisement from GATT + // connection, which has been advertised by extended advertisement. + bool IsSkippableGattAdvertisement( + const api::ble_v2::BleAdvertisementData& advertisement_data) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + // Clears out all data related to the provided GATT advertisement. This // includes: // 1. Removing the corresponding GATT advertisement from @@ -237,6 +249,7 @@ class DiscoveredPeripheralTracker { ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); Mutex mutex_; + bool is_extended_advertisement_available_; // ------------ SERVICE ID MAPS ------------ // Entries in these maps all follow the same lifecycle. Entries are added in diff --git a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker_test.cc b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker_test.cc index 8d6f2b57..33c48940 100644 --- a/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker_test.cc +++ b/connections/implementation/mediums/ble_v2/discovered_peripheral_tracker_test.cc @@ -211,8 +211,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!fast_advertisement_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kFastAdvertisementServiceUuid)); advertisement_data.service_data.insert( {std::string(kFastAdvertisementServiceUuid), fast_advertisement_bytes}); } @@ -252,8 +250,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!fast_advertisement_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kFastAdvertisementServiceUuid)); advertisement_data.service_data.insert( {std::string(kFastAdvertisementServiceUuid), fast_advertisement_bytes}); } @@ -298,8 +294,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!fast_advertisement_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kFastAdvertisementServiceUuid)); advertisement_data.service_data.insert( {std::string(kFastAdvertisementServiceUuid), fast_advertisement_bytes}); } @@ -357,14 +351,10 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } if (!fast_advertisement_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kFastAdvertisementServiceUuid)); advertisement_data.service_data.insert( {std::string(kFastAdvertisementServiceUuid), fast_advertisement_bytes}); } @@ -406,8 +396,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } @@ -444,8 +432,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } @@ -492,8 +478,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } @@ -540,8 +524,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } @@ -585,8 +567,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } @@ -636,14 +616,10 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } if (!fast_advertisement_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kFastAdvertisementServiceUuid)); advertisement_data.service_data.insert( {std::string(kFastAdvertisementServiceUuid), fast_advertisement_bytes}); } @@ -700,14 +676,10 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } if (!fast_advertisement_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kFastAdvertisementServiceUuid)); advertisement_data.service_data.insert( {std::string(kFastAdvertisementServiceUuid), fast_advertisement_bytes}); } @@ -761,8 +733,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, LostPeripheralForAdvertisementLost) { api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } @@ -841,14 +811,10 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } if (!fast_advertisement_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kFastAdvertisementServiceUuid)); advertisement_data.service_data.insert( {std::string(kFastAdvertisementServiceUuid), fast_advertisement_bytes}); } @@ -907,8 +873,6 @@ TEST_F(DiscoveredPeripheralTrackerTest, api::ble_v2::BleAdvertisementData advertisement_data; if (!advertisement_header_bytes.Empty()) { - advertisement_data.service_uuids.insert( - std::string(kCopresenceServiceUuid)); advertisement_data.service_data.insert( {std::string(kCopresenceServiceUuid), advertisement_header_bytes}); } diff --git a/internal/platform/ble_v2.cc b/internal/platform/ble_v2.cc index 24da066f..e9cb8696 100644 --- a/internal/platform/ble_v2.cc +++ b/internal/platform/ble_v2.cc @@ -28,26 +28,26 @@ namespace nearby { using ::location::nearby::api::ble_v2::BleAdvertisementData; using ::location::nearby::api::ble_v2::GattCharacteristic; -using ::location::nearby::api::ble_v2::PowerMode; +using ::location::nearby::api::ble_v2::TxPowerLevel; bool BleV2Medium::StartAdvertising( const BleAdvertisementData& advertising_data, - const BleAdvertisementData& scan_response_data, PowerMode power_mode) { - return impl_->StartAdvertising(advertising_data, scan_response_data, - power_mode); + api::ble_v2::AdvertiseParameters advertise_parameters) { + return impl_->StartAdvertising(advertising_data, advertise_parameters); } bool BleV2Medium::StopAdvertising() { return impl_->StopAdvertising(); } bool BleV2Medium::StartScanning(const std::string& service_uuid, - PowerMode power_mode, ScanCallback callback) { + TxPowerLevel tx_power_level, + ScanCallback callback) { MutexLock lock(&mutex_); if (scanning_enabled_) { NEARBY_LOGS(INFO) << "Ble Scanning already enabled; impl=" << GetImpl(); return false; } bool success = impl_->StartScanning( - service_uuid, power_mode, + service_uuid, tx_power_level, { .advertisement_found_cb = [this](api::ble_v2::BlePeripheral& peripheral, @@ -119,7 +119,7 @@ std::unique_ptr BleV2Medium::StartGattServer( } std::unique_ptr BleV2Medium::ConnectToGattServer( - BleV2Peripheral peripheral, PowerMode power_mode, + BleV2Peripheral peripheral, TxPowerLevel tx_power_level, ClientGattConnectionCallback callback) { { MutexLock lock(&mutex_); @@ -128,7 +128,7 @@ std::unique_ptr BleV2Medium::ConnectToGattServer( std::unique_ptr api_gatt_client = impl_->ConnectToGattServer( - peripheral.GetImpl(), power_mode, + peripheral.GetImpl(), tx_power_level, { .disconnected_cb = [this]() { @@ -139,5 +139,9 @@ std::unique_ptr BleV2Medium::ConnectToGattServer( return std::make_unique(std::move(api_gatt_client)); } +bool BleV2Medium::IsExtendedAdvertisementsAvailable() { + return impl_->IsExtendedAdvertisementsAvailable(); +} + } // namespace nearby } // namespace location diff --git a/internal/platform/ble_v2.h b/internal/platform/ble_v2.h index 103944e8..cd32c304 100644 --- a/internal/platform/ble_v2.h +++ b/internal/platform/ble_v2.h @@ -24,6 +24,7 @@ #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/byte_array.h" #include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/platform.h" #include "internal/platform/mutex.h" namespace location { @@ -153,13 +154,13 @@ class BleV2Medium final { // Returns true once the BLE advertising has been initiated. bool StartAdvertising( const api::ble_v2::BleAdvertisementData& advertising_data, - const api::ble_v2::BleAdvertisementData& scan_response_data, - api::ble_v2::PowerMode power_mode); + api::ble_v2::AdvertiseParameters advertise_parameters); bool StopAdvertising(); // Returns true once the BLE scan has been initiated. bool StartScanning(const std::string& service_uuid, - api::ble_v2::PowerMode power_mode, ScanCallback callback); + api::ble_v2::TxPowerLevel tx_power_level, + ScanCallback callback); bool StopScanning(); // Starts Gatt Server for waiting to client connection. @@ -169,9 +170,11 @@ class BleV2Medium final { // Returns a new GattClient connection to a gatt server. // There is only one instance of GattServer can run at a time. std::unique_ptr ConnectToGattServer( - BleV2Peripheral peripheral, api::ble_v2::PowerMode power_mode, + BleV2Peripheral peripheral, api::ble_v2::TxPowerLevel tx_power_level, ClientGattConnectionCallback callback); + bool IsExtendedAdvertisementsAvailable(); + bool IsValid() const { return impl_ != nullptr; } api::ble_v2::BleMedium* GetImpl() const { return impl_.get(); } diff --git a/internal/platform/ble_v2_test.cc b/internal/platform/ble_v2_test.cc index cea5245f..6465c11b 100644 --- a/internal/platform/ble_v2_test.cc +++ b/internal/platform/ble_v2_test.cc @@ -30,13 +30,14 @@ namespace { using ::location::nearby::api::ble_v2::BleAdvertisementData; using ::location::nearby::api::ble_v2::GattCharacteristic; -using ::location::nearby::api::ble_v2::PowerMode; +using ::location::nearby::api::ble_v2::TxPowerLevel; using ::testing::Optional; constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); constexpr absl::string_view kAdvertisementString = "\x0a\x0b\x0c\x0d"; +constexpr absl::string_view kAdvertisementHeaderString = "\x0x\x0y\x0z"; constexpr absl::string_view kCopresenceServiceUuid = "F3FE"; -constexpr PowerMode kPowerMode(PowerMode::kHigh); +constexpr TxPowerLevel kTxPowerLevel(TxPowerLevel::kHigh); // A stub BlePeripheral implementation. class BlePeripheralStub : public api::ble_v2::BlePeripheral { @@ -80,10 +81,11 @@ TEST_F(BleV2MediumTest, CanStartFastScanningAndFastAdvertising) { BluetoothAdapter adapter_b; BleV2Medium ble_a(adapter_a); BleV2Medium ble_b(adapter_b); + ByteArray advertisement_bytes{std::string(kAdvertisementString)}; CountDownLatch found_latch(1); EXPECT_TRUE(ble_a.StartScanning( - std::string(kCopresenceServiceUuid), kPowerMode, + {std::string(kCopresenceServiceUuid)}, kTxPowerLevel, { .advertisement_found_cb = [&found_latch](BleV2Peripheral peripheral, @@ -92,16 +94,23 @@ TEST_F(BleV2MediumTest, CanStartFastScanningAndFastAdvertising) { }, })); - // Assemble fast advertising and scan response data. + // Fail to start extended advertisement due to g3 Ble medium does not support. BleAdvertisementData advertising_data; - advertising_data.service_uuids.insert(std::string(kCopresenceServiceUuid)); - BleAdvertisementData scan_response_data; - scan_response_data.service_data.insert( - {std::string(kCopresenceServiceUuid), - ByteArray(std::string(kAdvertisementString))}); + advertising_data.is_extended_advertisement = true; + advertising_data.service_data.insert( + {std::string(kCopresenceServiceUuid), advertisement_bytes}); + EXPECT_FALSE(ble_b.StartAdvertising( + advertising_data, + {.tx_power_level = kTxPowerLevel, .is_connectable = true})); + + // Succeed to start regular advertisement. + advertising_data.is_extended_advertisement = false; + advertising_data.service_data = { + {std::string(kCopresenceServiceUuid), advertisement_bytes}}; + EXPECT_TRUE(ble_b.StartAdvertising( + advertising_data, + {.tx_power_level = kTxPowerLevel, .is_connectable = true})); - EXPECT_TRUE( - ble_b.StartAdvertising(advertising_data, scan_response_data, kPowerMode)); EXPECT_TRUE(found_latch.Await(kWaitDuration).result()); EXPECT_TRUE(ble_a.StopScanning()); EXPECT_TRUE(ble_b.StopAdvertising()); @@ -114,10 +123,12 @@ TEST_F(BleV2MediumTest, CanStartScanningAndAdvertising) { BluetoothAdapter adapter_b; BleV2Medium ble_a(adapter_a); BleV2Medium ble_b(adapter_b); + ByteArray advertisement_bytes{std::string(kAdvertisementString)}; + ByteArray advertisement_header_bytes{std::string(kAdvertisementHeaderString)}; CountDownLatch found_latch(1); EXPECT_TRUE(ble_a.StartScanning( - std::string(kCopresenceServiceUuid), kPowerMode, + {std::string(kCopresenceServiceUuid)}, kTxPowerLevel, { .advertisement_found_cb = [&found_latch](BleV2Peripheral peripheral, @@ -126,16 +137,23 @@ TEST_F(BleV2MediumTest, CanStartScanningAndAdvertising) { }, })); - // Assemble regular advertising and scan response data. - BleAdvertisementData advertising_data = {}; - BleAdvertisementData scan_response_data; - scan_response_data.service_uuids.insert(std::string(kCopresenceServiceUuid)); - scan_response_data.service_data.insert( - {std::string(kCopresenceServiceUuid), - ByteArray(std::string(kAdvertisementString))}); + // Fail to start extended advertisement due to g3 Ble medium does not support. + BleAdvertisementData advertising_data; + advertising_data.is_extended_advertisement = true; + advertising_data.service_data.insert( + {std::string(kCopresenceServiceUuid), advertisement_bytes}); + EXPECT_FALSE(ble_b.StartAdvertising( + advertising_data, + {.tx_power_level = kTxPowerLevel, .is_connectable = true})); + + // Succeed to start regular advertisement. + advertising_data.is_extended_advertisement = false; + advertising_data.service_data = { + {std::string(kCopresenceServiceUuid), advertisement_header_bytes}}; + EXPECT_TRUE(ble_b.StartAdvertising( + advertising_data, + {.tx_power_level = kTxPowerLevel, .is_connectable = true})); - EXPECT_TRUE( - ble_b.StartAdvertising(advertising_data, scan_response_data, kPowerMode)); EXPECT_TRUE(found_latch.Await(kWaitDuration).result()); EXPECT_TRUE(ble_a.StopScanning()); EXPECT_TRUE(ble_b.StopAdvertising()); @@ -145,7 +163,7 @@ TEST_F(BleV2MediumTest, CanStartScanningAndAdvertising) { TEST_F(BleV2MediumTest, CanStartGattServer) { env_.Start(); BluetoothAdapter adapter; - BleV2Medium ble{adapter}; + BleV2Medium ble(adapter); std::string characteristic_uuid = "characteristic_uuid"; std::unique_ptr gatt_server = @@ -157,6 +175,7 @@ TEST_F(BleV2MediumTest, CanStartGattServer) { GattCharacteristic::Permission::kRead}; std::vector properties = { GattCharacteristic::Property::kRead}; + // NOLINTNEXTLINE(google3-legacy-absl-backports) absl::optional gatt_characteristic = gatt_server->CreateCharacteristic(std::string(kCopresenceServiceUuid), characteristic_uuid, permissions, @@ -207,7 +226,7 @@ TEST_F(BleV2MediumTest, GattClientConnectToGattServerWorks) { auto ble_peripheral = std::make_unique(/*mac_address=*/"ABCD"); std::unique_ptr gatt_client = ble_b.ConnectToGattServer( - BleV2Peripheral(ble_peripheral.get()), kPowerMode, + BleV2Peripheral(ble_peripheral.get()), kTxPowerLevel, /*ClientGattConnectionCallback=*/{}); ASSERT_NE(gatt_client, nullptr); diff --git a/internal/platform/implementation/ble_v2.h b/internal/platform/implementation/ble_v2.h index 6045ad97..70b1c9df 100644 --- a/internal/platform/implementation/ble_v2.h +++ b/internal/platform/implementation/ble_v2.h @@ -24,7 +24,6 @@ #include #include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" #include "absl/strings/string_view.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" @@ -38,7 +37,7 @@ namespace api { namespace ble_v2 { // Coarse representation of power settings throughout all BLE operations. -enum class PowerMode { +enum class TxPowerLevel { kUnknown = 0, kUltraLow = 1, kLow = 2, @@ -46,6 +45,16 @@ enum class PowerMode { kHigh = 4, }; +// https://developer.android.com/reference/android/bluetooth/le/AdvertisingSetParameters.Builder +// +// The preferences for Advertising. +struct AdvertiseParameters { + // The transmission power level for the advertising. + TxPowerLevel tx_power_level; + // Whether the advertisement type should be connectable or non-connectable. + bool is_connectable; +}; + // https://developer.android.com/reference/android/bluetooth/le/AdvertiseData // // Bundle of data found in a BLE advertisement. @@ -54,27 +63,17 @@ enum class PowerMode { // 0000xxxx-0000-1000-8000-00805F9B34FB. This makes it possible to store two // byte service UUIDs in the advertisement. struct BleAdvertisementData { - using TxPowerLevel = std::int8_t; - - static constexpr TxPowerLevel kUnspecifiedTxPowerLevel = - std::numeric_limits::min(); - - bool is_connectable; - - // If tx_power_level is not set to kUnspecifiedTxPowerLevel, platform - // implementer needs to set the TxPowerLevel. - TxPowerLevel tx_power_level; - - // If the set is not empty, the platform implementer needs to add the - // service_uuids in the advertisement data. - absl::flat_hash_set service_uuids; + // Broadcasts a BLE extended advertisement if it is true. + bool is_extended_advertisement; // Maps service UUIDs to their service data. // - // Note if platform can't advertise data from Data type (0x16) - // (reaonly in iOS), then (iOS) should advertise data via LocalName data - // type (0x08). It means the iOS should take the first index of service_data - // as the data for LocalName type. + // For each platform should follow to set the service UUID(key) and service + // data(value): + // + // iOS : 16 bit service UUID (type=0x03) + LocalName data (type=0x08) + // Windows: Service data (type=0x16) + // Android: 16 bit service UUID (type=0x03) + Service data (type=0x16) absl::flat_hash_map service_data; }; @@ -274,15 +273,9 @@ class BleMedium { // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#startAdvertising(android.bluetooth.le.AdvertiseSettings,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseCallback) // // Starts BLE advertising and returns whether or not it was successful. - // - // Power mode should be interpreted in the following way: - // LOW: - // - TX power = medium - // HIGH: - // - TX power = high - virtual bool StartAdvertising(const BleAdvertisementData& advertising_data, - const BleAdvertisementData& scan_response_data, - PowerMode power_mode) = 0; + virtual bool StartAdvertising( + const BleAdvertisementData& advertising_data, + AdvertiseParameters advertise_set_parameters) = 0; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#stopAdvertising(android.bluetooth.le.AdvertiseCallback) // @@ -312,7 +305,7 @@ class BleMedium { // // Starts scanning and returns whether or not it was successful. // - // Power mode should be interpreted in the following way: + // TX Power level should be interpreted in the following way: // LOW: // - Scan window = ~512ms // - Scan interval = ~5120ms @@ -320,7 +313,8 @@ class BleMedium { // - Scan window = ~4096ms // - Scan interval = ~4096ms virtual bool StartScanning(const std::string& service_uuid, - PowerMode power_mode, ScanCallback callback) = 0; + TxPowerLevel tx_power_level, + ScanCallback callback) = 0; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#stopScan(android.bluetooth.le.ScanCallback) // @@ -347,13 +341,13 @@ class BleMedium { // Connects to a GATT server and negotiates the specified connection // parameters. Returns nullptr upon error. // - // Power mode should be interpreted in the following way: + // TX Power level should be interpreted in the following way: // HIGH: // - Connection interval = ~11.25ms - 15ms // LOW: // - Connection interval = ~100ms - 125ms virtual std::unique_ptr ConnectToGattServer( - BlePeripheral& peripheral, PowerMode power_mode, + BlePeripheral& peripheral, TxPowerLevel tx_power_level, ClientGattConnectionCallback callback) = 0; // Establishes a BLE socket to the specified remote peripheral. Returns @@ -361,6 +355,9 @@ class BleMedium { virtual std::unique_ptr EstablishBleSocket( BlePeripheral* peripheral, const BleSocketLifeCycleCallback& callback) = 0; + + // Requests if support extended advertisement. + virtual bool IsExtendedAdvertisementsAvailable() = 0; }; } // namespace ble_v2 diff --git a/internal/platform/implementation/g3/ble_v2.cc b/internal/platform/implementation/g3/ble_v2.cc index d6072326..88d7f099 100644 --- a/internal/platform/implementation/g3/ble_v2.cc +++ b/internal/platform/implementation/g3/ble_v2.cc @@ -35,19 +35,19 @@ namespace { using ::location::nearby::api::ble_v2::BleAdvertisementData; using ::location::nearby::api::ble_v2::BleSocket; using ::location::nearby::api::ble_v2::BleSocketLifeCycleCallback; -using ::location::nearby::api::ble_v2::PowerMode; +using ::location::nearby::api::ble_v2::TxPowerLevel; -std::string PowerModeToName(PowerMode power_mode) { +std::string TxPowerLevelToName(TxPowerLevel power_mode) { switch (power_mode) { - case PowerMode::kUltraLow: + case TxPowerLevel::kUltraLow: return "UltraLow"; - case PowerMode::kLow: + case TxPowerLevel::kLow: return "Low"; - case PowerMode::kMedium: + case TxPowerLevel::kMedium: return "Medium"; - case PowerMode::kHigh: + case TxPowerLevel::kHigh: return "High"; - case PowerMode::kUnknown: + case TxPowerLevel::kUnknown: return "Unknown"; } } @@ -67,28 +67,24 @@ BleV2Medium::~BleV2Medium() { bool BleV2Medium::StartAdvertising( const BleAdvertisementData& advertising_data, - const BleAdvertisementData& scan_response_data, PowerMode power_mode) { + api::ble_v2::AdvertiseParameters advertise_parameters) { NEARBY_LOGS(INFO) - << "G3 Ble StartAdvertising:, advertising_data.service_uuids size=" - << advertising_data.service_uuids.size() - << ", scan_response_data.service_data size=" - << scan_response_data.service_data.size() - << ", power_mode=" << PowerModeToName(power_mode); + << "G3 Ble StartAdvertising: advertising_data.is_extended_advertisement=" + << advertising_data.is_extended_advertisement + << ", advertising_data.service_data size=" + << advertising_data.service_data.size() << ", tx_power_level=" + << TxPowerLevelToName(advertise_parameters.tx_power_level) + << ", is_connectable=" << advertise_parameters.is_connectable; + if (advertising_data.is_extended_advertisement && + !is_support_extended_advertisement_) { + NEARBY_LOGS(INFO) + << "G3 Ble StartAdvertising does not support extended advertisement"; + return false; + } absl::MutexLock lock(&mutex_); - - // Reassemble advertisement data from advertising and scan response - // data. - api::ble_v2::BleAdvertisementData advertisement_data; - if (!advertising_data.service_uuids.empty()) { - advertisement_data.service_uuids = advertising_data.service_uuids; - } else { - advertisement_data.service_uuids = scan_response_data.service_uuids; - } - advertisement_data.service_data = scan_response_data.service_data; - MediumEnvironment::Instance().UpdateBleV2MediumForAdvertising( - /*enabled=*/true, *this, adapter_->GetPeripheralV2(), advertisement_data); + /*enabled=*/true, *this, adapter_->GetPeripheralV2(), advertising_data); return true; } @@ -104,7 +100,8 @@ bool BleV2Medium::StopAdvertising() { } bool BleV2Medium::StartScanning(const std::string& service_uuid, - PowerMode power_mode, ScanCallback callback) { + TxPowerLevel tx_power_level, + ScanCallback callback) { NEARBY_LOGS(INFO) << "G3 Ble StartScanning"; absl::MutexLock lock(&mutex_); @@ -136,7 +133,7 @@ bool BleV2Medium::StartListeningForIncomingBleSockets( void BleV2Medium::StopListeningForIncomingBleSockets() {} std::unique_ptr BleV2Medium::ConnectToGattServer( - api::ble_v2::BlePeripheral& peripheral, PowerMode power_mode, + api::ble_v2::BlePeripheral& peripheral, TxPowerLevel tx_power_level, api::ble_v2::ClientGattConnectionCallback callback) { return std::make_unique(); } @@ -147,6 +144,10 @@ std::unique_ptr BleV2Medium::EstablishBleSocket( return nullptr; } +bool BleV2Medium::IsExtendedAdvertisementsAvailable() { + return is_support_extended_advertisement_; +} + std::optional BleV2Medium::GattServer::CreateCharacteristic( absl::string_view service_uuid, absl::string_view characteristic_uuid, diff --git a/internal/platform/implementation/g3/ble_v2.h b/internal/platform/implementation/g3/ble_v2.h index 89be8e20..142c51db 100644 --- a/internal/platform/implementation/g3/ble_v2.h +++ b/internal/platform/implementation/g3/ble_v2.h @@ -38,12 +38,12 @@ class BleV2Medium : public api::ble_v2::BleMedium { // Returns true once the Ble advertising has been initiated. bool StartAdvertising( const api::ble_v2::BleAdvertisementData& advertising_data, - const api::ble_v2::BleAdvertisementData& scan_response_data, - api::ble_v2::PowerMode power_mode) override ABSL_LOCKS_EXCLUDED(mutex_); + api::ble_v2::AdvertiseParameters advertise_parameters) override + ABSL_LOCKS_EXCLUDED(mutex_); bool StopAdvertising() override ABSL_LOCKS_EXCLUDED(mutex_); bool StartScanning(const std::string& service_uuid, - api::ble_v2::PowerMode power_mode, + api::ble_v2::TxPowerLevel tx_power_level, ScanCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_); bool StopScanning() override ABSL_LOCKS_EXCLUDED(mutex_); @@ -56,7 +56,8 @@ class BleV2Medium : public api::ble_v2::BleMedium { void StopListeningForIncomingBleSockets() override ABSL_LOCKS_EXCLUDED(mutex_); std::unique_ptr ConnectToGattServer( - api::ble_v2::BlePeripheral& peripheral, api::ble_v2::PowerMode power_mode, + api::ble_v2::BlePeripheral& peripheral, + api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::ClientGattConnectionCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_); std::unique_ptr EstablishBleSocket( @@ -64,6 +65,8 @@ class BleV2Medium : public api::ble_v2::BleMedium { const api::ble_v2::BleSocketLifeCycleCallback& callback) override ABSL_LOCKS_EXCLUDED(mutex_); + bool IsExtendedAdvertisementsAvailable() override; + BluetoothAdapter& GetAdapter() { return *adapter_; } private: @@ -113,6 +116,8 @@ class BleV2Medium : public api::ble_v2::BleMedium { absl::Mutex mutex_; BluetoothAdapter* adapter_; // Our device adapter; read-only. + // TODO(edwinwu): Adds extended advertisement for testing. + bool is_support_extended_advertisement_ = false; }; } // namespace g3 diff --git a/internal/platform/implementation/windows/ble_v2.cc b/internal/platform/implementation/windows/ble_v2.cc index 5f6b656b..b4ba597a 100644 --- a/internal/platform/implementation/windows/ble_v2.cc +++ b/internal/platform/implementation/windows/ble_v2.cc @@ -20,7 +20,6 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/ble_v2.h" -#include "internal/platform/implementation/shared/count_down_latch.h" #include "internal/platform/logging.h" #include "winrt/Windows.Devices.Bluetooth.Advertisement.h" #include "winrt/Windows.Devices.Bluetooth.h" @@ -32,12 +31,13 @@ namespace windows { namespace { +using ::location::nearby::api::ble_v2::AdvertiseParameters; using ::location::nearby::api::ble_v2::BleAdvertisementData; using ::location::nearby::api::ble_v2::BleSocket; using ::location::nearby::api::ble_v2::BleSocketLifeCycleCallback; using ::location::nearby::api::ble_v2::GattClient; -using ::location::nearby::api::ble_v2::PowerMode; using ::location::nearby::api::ble_v2::ServerGattConnectionCallback; +using ::location::nearby::api::ble_v2::TxPowerLevel; using ::winrt::Windows::Devices::Bluetooth::BluetoothError; using ::winrt::Windows::Devices::Bluetooth::Advertisement:: BluetoothLEAdvertisement; @@ -61,22 +61,23 @@ using ::winrt::Windows::Devices::Bluetooth::Advertisement:: BluetoothLEAdvertisementWatcherStoppedEventArgs; using ::winrt::Windows::Devices::Bluetooth::Advertisement:: BluetoothLEScanningMode; +using ::winrt::Windows::Storage::Streams::Buffer; using ::winrt::Windows::Storage::Streams::DataWriter; template using IVector = winrt::Windows::Foundation::Collections::IVector; -std::string PowerModeToName(PowerMode power_mode) { - switch (power_mode) { - case PowerMode::kUltraLow: +std::string TxPowerLevelToName(TxPowerLevel tx_power_level) { + switch (tx_power_level) { + case TxPowerLevel::kUltraLow: return "UltraLow"; - case PowerMode::kLow: + case TxPowerLevel::kLow: return "Low"; - case PowerMode::kMedium: + case TxPowerLevel::kMedium: return "Medium"; - case PowerMode::kHigh: + case TxPowerLevel::kHigh: return "High"; - case PowerMode::kUnknown: + case TxPowerLevel::kUnknown: return "Unknown"; } } @@ -90,66 +91,33 @@ BleV2Medium::BleV2Medium(api::BluetoothAdapter& adapter) BleV2Medium::~BleV2Medium() {} -// TODO(edwinwu): Modify advertising abstraction APIs and fit all data into one // advertisement packet and populate accordingly -bool BleV2Medium::StartAdvertising( - const BleAdvertisementData& advertising_data, - const BleAdvertisementData& scan_response_data, PowerMode power_mode) { +bool BleV2Medium::StartAdvertising(const BleAdvertisementData& advertising_data, + AdvertiseParameters advertising_parameters) { NEARBY_LOGS(INFO) - << "Windows Ble StartAdvertising:, advertising_data.service_uuids size=" - << advertising_data.service_uuids.size() - << ", scan_response_data.service_data size=" - << scan_response_data.service_data.size() - << ", power_mode=" << PowerModeToName(power_mode); + << "Windows Ble StartAdvertising:, advertising_data.service_data size=" + << advertising_data.service_data.size() << ", tx_power_level=" + << TxPowerLevelToName(advertising_parameters.tx_power_level); + + if (advertising_data.service_data.empty()) return false; absl::MutexLock lock(&mutex_); // (AD type 0x16) Service Data - constexpr uint8_t kCopresenceServiceUuid[] = {0xf3, 0xfe}; DataWriter data_writer; + auto it = advertising_data.service_data.begin(); + const std::string& service_uuid = it->first; + const ByteArray& service_bytes = it->second; - // (2 bytes) 16-bit Service UUID 0xf3fe - data_writer.WriteByte(kCopresenceServiceUuid[1]); // 0xfe - data_writer.WriteByte(kCopresenceServiceUuid[0]); // 0xf3 - - // (1 byte) version [3-bits] + socket_version [3-bits] + - // fast_advertisement_flag [1-bit] + reserved [1-bit] - data_writer.WriteByte(0x00); - - // (1 byte) body_length - data_writer.WriteByte(0x00); - - // (1 byte) Nearby Connection version [3-bits] + pcp [5-bits] - data_writer.WriteByte(0x00); - - // (4 bytes) endpoint_id - for (int i = 0; i < 4; ++i) { - data_writer.WriteByte(0x00); + if (service_uuid.size() < 2) { + return false; } + data_writer.WriteByte(service_uuid[0]); + data_writer.WriteByte(service_uuid[1]); - // (1 byte) endpoint_info_size - data_writer.WriteByte(0x11); // always 17-bytes for Fast Advertisement - - // =========endpoint_info [17-bytes]============ - // (1 byte) Nearby Share version [3-bits] + visibility [1-bit] + reserved - // [4-bits] - data_writer.WriteByte(0x00); - - // (2 bytes) salt - for (int i = 0; i < 2; ++i) { - data_writer.WriteByte(0x00); - } - - // (14 bytes) encrypted_metadata_key - for (int i = 0; i < 14; ++i) { - data_writer.WriteByte(0x00); - } - // =========endpoint_info [17-bytes]============ - - // (2 bytes) device_token - for (int i = 0; i < 2; ++i) { - data_writer.WriteByte(0x00); - } + Buffer buffer(service_bytes.size()); + std::memcpy(buffer.data(), service_bytes.data(), service_bytes.size()); + data_writer.WriteBuffer(buffer); BluetoothLEAdvertisementDataSection service_data = BluetoothLEAdvertisementDataSection(0x16, data_writer.DetachBuffer()); @@ -217,7 +185,8 @@ bool BleV2Medium::StopAdvertising() { } bool BleV2Medium::StartScanning(const std::string& service_uuid, - PowerMode power_mode, ScanCallback callback) { + TxPowerLevel tx_power_level, + ScanCallback callback) { NEARBY_LOGS(INFO) << "Windows Ble StartScanning"; absl::MutexLock lock(&mutex_); watcher_started_callback_ = [this]() { @@ -290,7 +259,7 @@ bool BleV2Medium::StartListeningForIncomingBleSockets( void BleV2Medium::StopListeningForIncomingBleSockets() {} std::unique_ptr BleV2Medium::ConnectToGattServer( - api::ble_v2::BlePeripheral& peripheral, PowerMode power_mode, + api::ble_v2::BlePeripheral& peripheral, TxPowerLevel tx_power_level, api::ble_v2::ClientGattConnectionCallback callback) { return nullptr; } diff --git a/internal/platform/implementation/windows/ble_v2.h b/internal/platform/implementation/windows/ble_v2.h index cd00cc0c..c981113d 100644 --- a/internal/platform/implementation/windows/ble_v2.h +++ b/internal/platform/implementation/windows/ble_v2.h @@ -19,9 +19,6 @@ #include #include -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" -#include "absl/strings/escaping.h" #include "absl/synchronization/mutex.h" #include "internal/platform/byte_array.h" #include "internal/platform/implementation/ble_v2.h" @@ -49,12 +46,12 @@ class BleV2Medium : public api::ble_v2::BleMedium { // Returns true once the Ble advertising has been initiated. bool StartAdvertising( const api::ble_v2::BleAdvertisementData& advertising_data, - const api::ble_v2::BleAdvertisementData& scan_response_data, - api::ble_v2::PowerMode power_mode) override ABSL_LOCKS_EXCLUDED(mutex_); + api::ble_v2::AdvertiseParameters advertising_parameters) override + ABSL_LOCKS_EXCLUDED(mutex_); bool StopAdvertising() override ABSL_LOCKS_EXCLUDED(mutex_); bool StartScanning(const std::string& service_uuid, - api::ble_v2::PowerMode power_mode, + api::ble_v2::TxPowerLevel tx_power_level, ScanCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_); bool StopScanning() override ABSL_LOCKS_EXCLUDED(mutex_); @@ -67,13 +64,15 @@ class BleV2Medium : public api::ble_v2::BleMedium { void StopListeningForIncomingBleSockets() override ABSL_LOCKS_EXCLUDED(mutex_); std::unique_ptr ConnectToGattServer( - api::ble_v2::BlePeripheral& peripheral, api::ble_v2::PowerMode power_mode, + api::ble_v2::BlePeripheral& peripheral, + api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::ClientGattConnectionCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_); std::unique_ptr EstablishBleSocket( api::ble_v2::BlePeripheral* peripheral, const api::ble_v2::BleSocketLifeCycleCallback& callback) override ABSL_LOCKS_EXCLUDED(mutex_); + bool IsExtendedAdvertisementsAvailable() override { return false; } BluetoothAdapter& GetAdapter() { return *adapter_; } diff --git a/internal/platform/implementation/windows/ble_v2_test.cc b/internal/platform/implementation/windows/ble_v2_test.cc index fbc7abee..f4742efe 100644 --- a/internal/platform/implementation/windows/ble_v2_test.cc +++ b/internal/platform/implementation/windows/ble_v2_test.cc @@ -34,7 +34,8 @@ TEST(BleV2Medium, DISABLED_StartAdvertising) { api::ble_v2::BleAdvertisementData scan_response_data; EXPECT_TRUE(blev2_medium.StartAdvertising( - advertising_data, scan_response_data, api::ble_v2::PowerMode::kHigh)); + advertising_data, {.tx_power_level = api::ble_v2::TxPowerLevel::kHigh, + .is_connectable = true})); } TEST(BleV2Medium, DISABLED_StopAdvertising) { @@ -42,10 +43,10 @@ TEST(BleV2Medium, DISABLED_StopAdvertising) { BleV2Medium blev2_medium(bluetoothAdapter); api::ble_v2::BleAdvertisementData advertising_data; - api::ble_v2::BleAdvertisementData scan_response_data; EXPECT_TRUE(blev2_medium.StartAdvertising( - advertising_data, scan_response_data, api::ble_v2::PowerMode::kHigh)); + advertising_data, {.tx_power_level = api::ble_v2::TxPowerLevel::kHigh, + .is_connectable = true})); EXPECT_TRUE(blev2_medium.StopAdvertising()); } @@ -67,7 +68,7 @@ TEST(BleV2Medium, DISABLED_StartScanning) { }; EXPECT_TRUE(blev2_medium.StartScanning( - service_uuid, api::ble_v2::PowerMode::kHigh, callback)); + service_uuid, api::ble_v2::TxPowerLevel::kHigh, callback)); EXPECT_TRUE(scan_response_notification.WaitForNotificationWithTimeout( absl::Seconds(5))); @@ -85,7 +86,7 @@ TEST(BleV2Medium, DISABLED_StopScanning) { const api::ble_v2::BleAdvertisementData& advertisement_data) {}; EXPECT_TRUE(blev2_medium.StartScanning( - service_uuid, api::ble_v2::PowerMode::kHigh, callback)); + service_uuid, api::ble_v2::TxPowerLevel::kHigh, callback)); EXPECT_TRUE(blev2_medium.StopScanning()); } diff --git a/internal/platform/medium_environment.cc b/internal/platform/medium_environment.cc index fb8f0205..6932b271 100644 --- a/internal/platform/medium_environment.cc +++ b/internal/platform/medium_environment.cc @@ -539,9 +539,9 @@ void MediumEnvironment::UpdateBleV2MediumForAdvertising( BleV2MediumContext& remote_context = medium_info.second; // Do not send notification to the same medium. if (remote_medium == &medium) continue; - if (!context.advertisement_data.service_uuids.contains( - remote_context.scanning_service_uuid)) - continue; + auto const it = context.advertisement_data.service_data.find( + remote_context.scanning_service_uuid); + if (it == context.advertisement_data.service_data.end()) continue; NEARBY_LOGS(INFO) << "G3 UpdateBleV2MediumForAdvertising, found other medium=" << remote_medium << ", remote_medium_context=" << &remote_context @@ -583,8 +583,9 @@ void MediumEnvironment::UpdateBleV2MediumForScanning( // medium. if (remote_medium == &medium || !remote_context.advertising) continue; - if (!remote_context.advertisement_data.service_uuids.contains( - context.scanning_service_uuid)) + auto const it = remote_context.advertisement_data.service_data.find( + context.scanning_service_uuid); + if (it == remote_context.advertisement_data.service_data.end()) continue; NEARBY_LOGS(INFO) << "G3 UpdateBleV2MediumForScanning, found other medium=" @@ -894,8 +895,8 @@ api::WifiHotspotMedium* MediumEnvironment::GetWifiHotspotMedium( } void MediumEnvironment::UpdateWifiHotspotMediumForStartOrConnect( - api::WifiHotspotMedium& medium, HotspotCredentials* hotspot_credentials, - bool is_ap, bool enabled) { + api::WifiHotspotMedium& medium, HotspotCredentials* hotspot_credentials, + bool is_ap, bool enabled) { if (!enabled_) return; CountDownLatch latch(1); @@ -913,8 +914,8 @@ void MediumEnvironment::UpdateWifiHotspotMediumForStartOrConnect( << "; ssid=" << hotspot_credentials->GetSSID() << "; password=" << hotspot_credentials->GetPassword(); } else { - NEARBY_LOGS(INFO) << "Reset WifiHotspot medium for Hotspot: this=" - << this << "; medium=" << &medium << role_status; + NEARBY_LOGS(INFO) << "Reset WifiHotspot medium for Hotspot: this=" << this + << "; medium=" << &medium << role_status; } MutexLock lock(&mutex_);