Validate DCT advertisements and filter BLE scan results on Apple.

PiperOrigin-RevId: 943784982
This commit is contained in:
Edwin Wu
2026-07-07 03:15:15 -07:00
committed by Copybara-Service
parent 029ab9765c
commit 618e5bd5d5
7 changed files with 48 additions and 29 deletions
@@ -129,7 +129,8 @@ std::optional<DctAdvertisement> 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;
}
@@ -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
@@ -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<BleAdvertisementData> 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.
@@ -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",
@@ -208,7 +208,7 @@ static const char *const kTestServiceID = "TestServiceID";
}
- (void)testStartMultipleServicesScanning_Success {
std::vector<nearby::Uuid> service_uuids = {nearby::Uuid(0, 0)};
std::vector<nearby::Uuid> 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<nearby::Uuid> service_uuids = {nearby::Uuid(0, 0)};
std::vector<nearby::Uuid> 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) {
@@ -247,6 +247,7 @@ class BleMedium : public api::ble::BleMedium {
GNSPeripheralManager *socketPeripheralManager_;
absl::Mutex scanning_mutex_;
std::vector<Uuid> 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.
@@ -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 <CoreBluetooth/CoreBluetooth.h>
#import <Foundation/Foundation.h>
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
@@ -157,8 +159,17 @@ void BleMedium::HandleAdvertisementFound(id<GNCPeripheral> peripheral,
return;
}
std::vector<Uuid> 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<api::ble::BleMedium::ScanningSession> BleMedium::StartScanning(
{
absl::MutexLock lock(&scanning_mutex_);
scanning_cb_ = std::make_shared<api::ble::BleMedium::ScanningCallback>(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<api::ble::BleMedium::ScanCallback>(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<Uuid> &service_u
{
absl::MutexLock lock(&scanning_mutex_);
scan_cb_ = std::make_shared<api::ble::BleMedium::ScanCallback>(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);