From 618e5bd5d512dd32d2f1ef594c907b23a4437619 Mon Sep 17 00:00:00 2001 From: Edwin Wu Date: Tue, 7 Jul 2026 03:13:48 -0700 Subject: [PATCH] Validate DCT advertisements and filter BLE scan results on Apple. PiperOrigin-RevId: 943784982 --- .../advertisements/dct_advertisement.cc | 3 +- .../advertisements/dct_advertisement_test.cc | 5 ++++ .../ble/discovered_peripheral_tracker.cc | 20 +++++-------- internal/platform/implementation/apple/BUILD | 1 + .../apple/Tests/ble_medium_test.mm | 30 +++++++++---------- .../implementation/apple/ble_medium.h | 1 + .../implementation/apple/ble_medium.mm | 17 ++++++++++- 7 files changed, 48 insertions(+), 29 deletions(-) diff --git a/connections/implementation/mediums/advertisements/dct_advertisement.cc b/connections/implementation/mediums/advertisements/dct_advertisement.cc index 59f527dc..c443fce3 100644 --- a/connections/implementation/mediums/advertisements/dct_advertisement.cc +++ b/connections/implementation/mediums/advertisements/dct_advertisement.cc @@ -129,7 +129,8 @@ std::optional DctAdvertisement::Parse( LOG(WARNING) << "Failed to read device information."; return std::nullopt; } - if (device_information->type() != kDataTypeDeviceInformation) { + if (device_information->type() != kDataTypeDeviceInformation || + device_information->value().empty()) { LOG(WARNING) << "Invalid device information."; return std::nullopt; } diff --git a/connections/implementation/mediums/advertisements/dct_advertisement_test.cc b/connections/implementation/mediums/advertisements/dct_advertisement_test.cc index eabf10d2..2377e49a 100644 --- a/connections/implementation/mediums/advertisements/dct_advertisement_test.cc +++ b/connections/implementation/mediums/advertisements/dct_advertisement_test.cc @@ -113,5 +113,10 @@ TEST(DctAdvertisementTest, ParseData) { EXPECT_EQ(dct_advertisement->GetPsm(), 192); } +TEST(DctAdvertisementTest, ParseWithEmptyDeviceInformationDataElement) { + std::string data = std::string("\x20\x25\0\0\x24\0\0\x07", 8); + EXPECT_FALSE(DctAdvertisement::Parse(data).has_value()); +} + } // namespace } // namespace nearby::connections::advertisements::ble diff --git a/connections/implementation/mediums/ble/discovered_peripheral_tracker.cc b/connections/implementation/mediums/ble/discovered_peripheral_tracker.cc index 51e2dd53..a239ebe5 100644 --- a/connections/implementation/mediums/ble/discovered_peripheral_tracker.cc +++ b/connections/implementation/mediums/ble/discovered_peripheral_tracker.cc @@ -66,8 +66,7 @@ constexpr absl::Duration kAdvertisementHeaderExpiry = absl::Seconds(15); // Private c'tor for testing. DiscoveredPeripheralTracker::DiscoveredPeripheralTracker( bool is_extended_advertisement_available, bool start_fetch_executor) - : is_extended_advertisement_available_( - is_extended_advertisement_available), + : is_extended_advertisement_available_(is_extended_advertisement_available), start_fetch_executor_(start_fetch_executor) {} DiscoveredPeripheralTracker::DiscoveredPeripheralTracker( @@ -75,9 +74,7 @@ DiscoveredPeripheralTracker::DiscoveredPeripheralTracker( : DiscoveredPeripheralTracker(is_extended_advertisement_available, /*start_fetch_executor=*/true) {} -DiscoveredPeripheralTracker::~DiscoveredPeripheralTracker() { - Shutdown(); -} +DiscoveredPeripheralTracker::~DiscoveredPeripheralTracker() { Shutdown(); } void DiscoveredPeripheralTracker::StartFetchExecutorIfNeeded() { if (executor_ != nullptr) { @@ -199,7 +196,8 @@ void DiscoveredPeripheralTracker::ProcessFoundBleAdvertisement( return; } - if (advertisement_data.service_data.contains(bleutils::kDctServiceUuid)) { + if (!dct_service_id_hash_to_service_id_map_.empty() && + advertisement_data.service_data.contains(bleutils::kDctServiceUuid)) { std::optional dct_advertisement_data = HandleDctAdvertisement(advertisement_data); @@ -749,15 +747,14 @@ void DiscoveredPeripheralTracker::HandleAdvertisementHeader( // support extended advertisement. if (!advertisement_header.IsSupportExtendedAdvertisement()) { for (auto& item : service_id_infos_) { - item.second.discovered_peripheral_callback - .legacy_device_discovered_cb(); + item.second.discovered_peripheral_callback.legacy_device_discovered_cb(); } } // Determine whether or not we need to read a fresh GATT advertisement. VLOG(1) << "Handle GATT advertisement header with hash " << absl::BytesToHexString( - advertisement_header.GetAdvertisementHash().AsStringView()) + advertisement_header.GetAdvertisementHash().AsStringView()) << " in thread"; if (!ShouldReadRawAdvertisementFromServer(advertisement_header)) { @@ -1015,7 +1012,7 @@ void DiscoveredPeripheralTracker::GattFetchingLoop() { } if (!found_task) { LOG(WARNING) << "No task found, skip to fetch raw advertisement."; - continue;; + continue; } // Check if the task is expired. @@ -1027,8 +1024,7 @@ void DiscoveredPeripheralTracker::GattFetchingLoop() { .AsStringView()) << " is expired, skip to fetch raw advertisement."; } else { - FetchRawAdvertisementsInThread(task.peripheral, - task.advertisement_header, + FetchRawAdvertisementsInThread(task.peripheral, task.advertisement_header, std::move(task.advertisement_fetcher)); } // Clear in progress header after the task is done. diff --git a/internal/platform/implementation/apple/BUILD b/internal/platform/implementation/apple/BUILD index f850bd13..48def85f 100644 --- a/internal/platform/implementation/apple/BUILD +++ b/internal/platform/implementation/apple/BUILD @@ -214,6 +214,7 @@ objc_library( "//internal/platform/implementation/apple/Mediums/BLE/Sockets:Peripheral", "//third_party/apple_frameworks:CoreBluetooth", "//third_party/apple_frameworks:Foundation", + "@com_google_absl//absl/algorithm:container", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/strings", diff --git a/internal/platform/implementation/apple/Tests/ble_medium_test.mm b/internal/platform/implementation/apple/Tests/ble_medium_test.mm index a8fb6199..a72fa8b7 100644 --- a/internal/platform/implementation/apple/Tests/ble_medium_test.mm +++ b/internal/platform/implementation/apple/Tests/ble_medium_test.mm @@ -208,7 +208,7 @@ static const char *const kTestServiceID = "TestServiceID"; } - (void)testStartMultipleServicesScanning_Success { - std::vector service_uuids = {nearby::Uuid(0, 0)}; + std::vector service_uuids = {nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB)}; nearby::api::ble::TxPowerLevel tx_power_level = nearby::api::ble::TxPowerLevel::kUltraLow; bool result = _medium->StartMultipleServicesScanning(service_uuids, tx_power_level, {}); @@ -217,7 +217,7 @@ static const char *const kTestServiceID = "TestServiceID"; } - (void)testStartMultipleServicesScanning_Failure { - std::vector service_uuids = {nearby::Uuid(0, 0)}; + std::vector service_uuids = {nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB)}; nearby::api::ble::TxPowerLevel tx_power_level = nearby::api::ble::TxPowerLevel::kUltraLow; _fakeGNCBLEMedium.startScanningError = [NSError errorWithDomain:@"test" code:0 userInfo:nil]; @@ -295,7 +295,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData); @@ -321,7 +321,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData); @@ -380,7 +380,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData); @@ -408,7 +408,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData); @@ -445,7 +445,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData); @@ -478,7 +478,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData); @@ -664,7 +664,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData); @@ -712,7 +712,7 @@ static const char *const kTestServiceID = "TestServiceID"; [expectation fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { @@ -737,7 +737,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation1 fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback1)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData1); @@ -761,7 +761,7 @@ static const char *const kTestServiceID = "TestServiceID"; serviceData2[[CBUUID UUIDWithString:kTestServiceUUIDString]]); [expectation2 fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback2)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { @@ -794,7 +794,7 @@ static const char *const kTestServiceID = "TestServiceID"; [expectation2 fulfill]; } })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData); @@ -821,7 +821,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation1 fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback1)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { _fakeGNCBLEMedium.advertisementFoundHandler(fakePeripheral, serviceData); @@ -838,7 +838,7 @@ static const char *const kTestServiceID = "TestServiceID"; const nearby::api::ble::BleAdvertisementData &advertisement) { [expectation2 fulfill]; })}; - _medium->StartScanning(nearby::Uuid(0, 0), nearby::api::ble::TxPowerLevel::kUltraLow, + _medium->StartScanning(nearby::Uuid(0x0000FE2C00001000, 0x800000805F9B34FB), nearby::api::ble::TxPowerLevel::kUltraLow, std::move(callback2)); if (_fakeGNCBLEMedium.advertisementFoundHandler) { diff --git a/internal/platform/implementation/apple/ble_medium.h b/internal/platform/implementation/apple/ble_medium.h index 34695757..ca3473e9 100644 --- a/internal/platform/implementation/apple/ble_medium.h +++ b/internal/platform/implementation/apple/ble_medium.h @@ -247,6 +247,7 @@ class BleMedium : public api::ble::BleMedium { GNSPeripheralManager *socketPeripheralManager_; absl::Mutex scanning_mutex_; + std::vector scanning_service_uuids_ ABSL_GUARDED_BY(scanning_mutex_); GNSCentralManager *socketCentralManager_ ABSL_GUARDED_BY(scanning_mutex_); // Used for the blocking version of StartAdvertising and only has an advertisement found callback. diff --git a/internal/platform/implementation/apple/ble_medium.mm b/internal/platform/implementation/apple/ble_medium.mm index 1120f8b6..d083e583 100644 --- a/internal/platform/implementation/apple/ble_medium.mm +++ b/internal/platform/implementation/apple/ble_medium.mm @@ -12,11 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "absl/algorithm/container.h" #import "internal/platform/implementation/apple/ble_medium.h" #import #import +#include #include #include #include @@ -157,8 +159,17 @@ void BleMedium::HandleAdvertisementFound(id peripheral, return; } + std::vector scanning_uuids; + { + absl::MutexLock lock(&scanning_mutex_); + scanning_uuids = scanning_service_uuids_; + } for (CBUUID *key in serviceData.allKeys) { - data.service_data[CPPUUIDFromObjC(key)] = ByteArrayFromNSData(serviceData[key]); + Uuid cpp_uuid = CPPUUIDFromObjC(key); + if (absl::c_find(scanning_uuids, cpp_uuid) == scanning_uuids.end()) { + continue; + } + data.service_data[cpp_uuid] = ByteArrayFromNSData(serviceData[key]); } // Add the peripheral to the map if we haven't discovered it yet. @@ -197,6 +208,7 @@ std::unique_ptr BleMedium::StartScanning( { absl::MutexLock lock(&scanning_mutex_); scanning_cb_ = std::make_shared(std::move(callback)); + scanning_service_uuids_ = {service_uuid}; if (central_manager_factory_) { socketCentralManager_ = central_manager_factory_(serviceUUID); @@ -273,6 +285,7 @@ bool BleMedium::StartScanning(const Uuid &service_uuid, api::ble::TxPowerLevel t { absl::MutexLock lock(&scanning_mutex_); scan_cb_ = std::make_shared(std::move(callback)); + scanning_service_uuids_ = {service_uuid}; if (central_manager_factory_) { socketCentralManager_ = central_manager_factory_(serviceUUID); @@ -331,6 +344,7 @@ bool BleMedium::StartMultipleServicesScanning(const std::vector &service_u { absl::MutexLock lock(&scanning_mutex_); scan_cb_ = std::make_shared(std::move(callback)); + scanning_service_uuids_ = service_uuids; if (central_manager_factory_) { socketCentralManager_ = central_manager_factory_(serviceUUIDs[0]); @@ -379,6 +393,7 @@ bool BleMedium::StopScanning() { [socketCentralManager_ stopNoScanMode]; scan_cb_ = nullptr; scanning_cb_ = nullptr; + scanning_service_uuids_.clear(); } dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);