From e95b44cf61de3244e9042f71753310d010a4d67c Mon Sep 17 00:00:00 2001 From: Edwin Wu Date: Thu, 7 Aug 2025 17:06:17 -0700 Subject: [PATCH] Fixes a potential crash when shutting down a `BleMedium`. PiperOrigin-RevId: 792365629 --- .../apple/Mediums/BLEv2/GNCBLEMedium.h | 5 +++++ .../apple/Mediums/BLEv2/GNCBLEMedium.m | 14 ++++++++++++-- .../implementation/apple/Tests/GNCPlatformTest.mm | 6 ++++++ .../platform/implementation/apple/ble_medium.h | 2 +- .../platform/implementation/apple/ble_medium.mm | 3 +++ 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h index b95790a9..65a8e633 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h @@ -238,6 +238,11 @@ typedef void (^GNCGATTConnectionCompletionHandler)(GNCBLEGATTClient *_Nullable c peripheral:(id)remotePeripheral completionHandler:(nullable GNCOpenL2CAPStreamCompletionHandler)completionHandler; +/** + * Stops all BLE operations. + */ +- (void)stop; + @end NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m index 283620d2..0e14d94b 100644 --- a/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m +++ b/internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.m @@ -34,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN static char *const kBLEMediumQueueLabel = "com.nearby.GNCBLEMedium"; // TODO: b/762454867 - Make this a flag. static const NSTimeInterval kPeripheralConnectTimeout = 10.0; // 10 seconds timeout +static const NSTimeInterval kStopTimeout = 5.0; static NSError *AlreadyScanningError() { return [NSError errorWithDomain:GNCBLEErrorDomain code:GNCBLEErrorAlreadyScanning userInfo:nil]; @@ -122,8 +123,17 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( return self; } -- (void)dealloc { - [self cancelConnectionTimeout]; +- (void)stop { + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + dispatch_async(_queue, ^{ + [self cancelConnectionTimeout]; + dispatch_semaphore_signal(semaphore); + }); + dispatch_time_t timeout = + dispatch_time(DISPATCH_TIME_NOW, kStopTimeout * NSEC_PER_SEC); // 5 seconds timeout + if (dispatch_semaphore_wait(semaphore, timeout) != 0) { + GNCLoggerError(@"GNCBLEMedium stop timeout."); + } } - (BOOL)supportsExtendedAdvertisements { diff --git a/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm b/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm index 322d0725..72467db7 100644 --- a/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm @@ -80,4 +80,10 @@ void GNCEnsureFileAtPath(std::string path) { XCTAssertEqualObjects(@(actual.c_str()), expected); } +- (void)testCreateBleV2Medium { + auto bluetooth_adapter = nearby::api::ImplementationPlatform::CreateBluetoothAdapter(); + auto ble_medium = nearby::api::ImplementationPlatform::CreateBleV2Medium(*bluetooth_adapter); + XCTAssertNotEqual(ble_medium.get(), nullptr); +} + @end diff --git a/internal/platform/implementation/apple/ble_medium.h b/internal/platform/implementation/apple/ble_medium.h index 6520221e..bc86ebcd 100644 --- a/internal/platform/implementation/apple/ble_medium.h +++ b/internal/platform/implementation/apple/ble_medium.h @@ -47,7 +47,7 @@ namespace apple { class BleMedium : public api::ble_v2::BleMedium { public: BleMedium(); - ~BleMedium() override = default; + ~BleMedium() override; // Async interface for StartAdvertising. // diff --git a/internal/platform/implementation/apple/ble_medium.mm b/internal/platform/implementation/apple/ble_medium.mm index 96071ed8..1c9277b2 100644 --- a/internal/platform/implementation/apple/ble_medium.mm +++ b/internal/platform/implementation/apple/ble_medium.mm @@ -82,6 +82,9 @@ NSString *ConvertDataToHexString(NSData *data) { BleMedium::BleMedium() : medium_([[GNCBLEMedium alloc] init]) {} +// ble_medium.mm +BleMedium::~BleMedium() { [medium_ stop]; } + std::unique_ptr BleMedium::StartAdvertising( const api::ble_v2::BleAdvertisementData &advertising_data, api::ble_v2::AdvertiseParameters advertise_set_parameters,