Fixed deadlock during stop scanning on iOS

PiperOrigin-RevId: 791998760
This commit is contained in:
Guogang Li
2025-08-06 22:47:41 -07:00
committed by Copybara-Service
parent 807bf7172f
commit ddd4f922b9
6 changed files with 88 additions and 35 deletions
+31 -8
View File
@@ -1,7 +1,3 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("@rules_cc//cc:objc_library.bzl", "objc_library")
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,6 +11,11 @@ load("@rules_cc//cc:objc_library.bzl", "objc_library")
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("@rules_cc//cc:objc_library.bzl", "objc_library")
licenses(["notice"])
package(default_visibility = [
@@ -25,13 +26,35 @@ package(default_visibility = [
"//sharing:__subpackages__",
])
objc_library(
name = "comm",
srcs = [
"multi_thread_executor.mm",
],
hdrs = [
"multi_thread_executor.h",
"scheduled_executor.h",
"single_thread_executor.h",
],
deps = [
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:uuid",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:types",
"//internal/platform/implementation/apple/Flags",
"//internal/platform/implementation/apple/Log:GNCLogger",
"//third_party/apple_frameworks:CoreBluetooth",
"//third_party/apple_frameworks:Foundation",
],
)
objc_library(
name = "apple",
srcs = [
"awdl.mm",
"crypto.mm",
"device_info.mm",
"multi_thread_executor.mm",
"platform.mm",
"preferences_manager.mm",
"scheduled_executor.mm",
@@ -42,10 +65,7 @@ objc_library(
hdrs = [
"awdl.h",
"device_info.h",
"multi_thread_executor.h",
"preferences_manager.h",
"scheduled_executor.h",
"single_thread_executor.h",
"timer.h",
"wifi.h",
"wifi_hotspot.h",
@@ -55,6 +75,7 @@ objc_library(
aspect_hints = ["//tools/build_defs/swift:no_module"],
features = ["-layering_check"],
deps = [
":comm",
":Platform_cc",
":Shared",
":ble_v2",
@@ -119,10 +140,12 @@ objc_library(
# Prevent Objective-C++ headers from being pulled into swift.
aspect_hints = ["//tools/build_defs/swift:no_module"],
deps = [
":comm",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:uuid",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:types",
"//internal/platform/implementation/apple/Flags",
"//internal/platform/implementation/apple/Log:GNCLogger",
"//internal/platform/implementation/apple/Mediums",
@@ -17,7 +17,7 @@
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPClient.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPServer.h"
// #import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEL2CAPStream.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCCentralManager.h"
@class GNCBLEGATTServer;
@class GNCBLEGATTClient;
@@ -101,6 +101,20 @@ typedef void (^GNCGATTConnectionCompletionHandler)(GNCBLEGATTClient *_Nullable c
*/
@interface GNCBLEMedium : NSObject
/**
* Initializes the BLE medium.
*/
- (instancetype)init;
/**
* Initializes the BLE medium with a custom central manager.
*
* @param centralManager The central manager to use for BLE operations.
* @param queue The queue to use for all internal operations.
*/
- (instancetype)initWithCentralManager:(id<GNCCentralManager>)centralManager
queue:(nullable dispatch_queue_t)queue;
/** The hardware supports BOTH advertising extensions and extended scans. */
@property(nonatomic, readonly) BOOL supportsExtendedAdvertisements;
@@ -171,8 +185,7 @@ typedef void (^GNCGATTConnectionCompletionHandler)(GNCBLEGATTClient *_Nullable c
* @param completionHandler Called on a private queue with @c nil if successfully resumed scanning
* or an error if one has occurred.
*/
- (void)resumeMediumScanning:
(nullable GNCStartScanningCompletionHandler)completionHandler;
- (void)resumeMediumScanning:(nullable GNCStartScanningCompletionHandler)completionHandler;
/**
* Starts a GATT server.
@@ -96,11 +96,11 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer(
}
- (instancetype)init {
dispatch_queue_t queue = dispatch_queue_create(kBLEMediumQueueLabel, DISPATCH_QUEUE_SERIAL);
CBCentralManager *centralManager =
[[CBCentralManager alloc] initWithDelegate:self
queue:_queue
queue:queue
options:@{CBCentralManagerOptionShowPowerAlertKey : @NO}];
dispatch_queue_t queue = dispatch_queue_create(kBLEMediumQueueLabel, DISPATCH_QUEUE_SERIAL);
return [self initWithCentralManager:centralManager queue:queue];
}
@@ -506,43 +506,33 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer(
#pragma mark - CBCentralManagerDelegate
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
dispatch_async(_queue, ^{
[self gnc_centralManagerDidUpdateState:central];
});
[self gnc_centralManagerDidUpdateState:central];
}
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary<NSString *, id> *)advertisementData
RSSI:(NSNumber *)RSSI {
dispatch_async(_queue, ^{
[self gnc_centralManager:central
didDiscoverPeripheral:peripheral
advertisementData:advertisementData
RSSI:RSSI];
});
[self gnc_centralManager:central
didDiscoverPeripheral:peripheral
advertisementData:advertisementData
RSSI:RSSI];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
dispatch_async(_queue, ^{
[self gnc_centralManager:central didConnectPeripheral:peripheral];
});
[self gnc_centralManager:central didConnectPeripheral:peripheral];
}
- (void)centralManager:(CBCentralManager *)central
didFailToConnectPeripheral:(CBPeripheral *)peripheral
error:(nullable NSError *)error {
dispatch_async(_queue, ^{
[self gnc_centralManager:central didFailToConnectPeripheral:peripheral error:error];
});
[self gnc_centralManager:central didFailToConnectPeripheral:peripheral error:error];
}
- (void)centralManager:(CBCentralManager *)central
didDisconnectPeripheral:(CBPeripheral *)peripheral
error:(nullable NSError *)error {
dispatch_async(_queue, ^{
[self gnc_centralManager:central didDisconnectPeripheral:peripheral error:error];
});
[self gnc_centralManager:central didDisconnectPeripheral:peripheral error:error];
}
@end
@@ -65,6 +65,7 @@ objc_library(
"//internal/platform/implementation/apple", # buildcleaner: keep
"//internal/platform/implementation/apple:Shared",
"//internal/platform/implementation/apple:ble_v2",
"//internal/platform/implementation/apple:comm",
"//internal/platform/implementation/apple/Mediums",
"//third_party/apple_frameworks:CommonCrypto",
"//third_party/apple_frameworks:CoreBluetooth",
@@ -29,6 +29,7 @@
#import "internal/platform/implementation/apple/ble_l2cap_server_socket.h"
#import "internal/platform/implementation/apple/ble_server_socket.h"
#import "internal/platform/implementation/apple/bluetooth_adapter_v2.h"
#import "internal/platform/implementation/apple/single_thread_executor.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/uuid.h"
@@ -202,6 +203,9 @@ class BleMedium : public api::ble_v2::BleMedium {
NSDictionary<CBUUID *, NSData *> *service_data);
NSDate *GetLastTimestampToCleanExpiredAdvertisementPackets();
// The executor for handling callbacks.
apple::SingleThreadExecutor callback_executor_;
GNCBLEMedium *medium_;
PeripheralsMap peripherals_;
@@ -200,7 +200,8 @@ std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> BleMedium::StartScannin
[medium_ startScanningForService:serviceUUID
advertisementFoundHandler:^(id<GNCPeripheral> peripheral,
NSDictionary<CBUUID *, NSData *> *serviceData) {
HandleAdvertisementFound(peripheral, serviceData);
callback_executor_.Execute(
[this, peripheral, serviceData] { HandleAdvertisementFound(peripheral, serviceData); });
}
completionHandler:^(NSError *error) {
if (scanning_cb_.start_scanning_result) {
@@ -234,7 +235,8 @@ bool BleMedium::StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLeve
[medium_ startScanningForService:serviceUUID
advertisementFoundHandler:^(id<GNCPeripheral> peripheral,
NSDictionary<CBUUID *, NSData *> *serviceData) {
HandleAdvertisementFound(peripheral, serviceData);
callback_executor_.Execute(
[this, peripheral, serviceData] { HandleAdvertisementFound(peripheral, serviceData); });
}
completionHandler:^(NSError *error) {
if (error != nil) {
@@ -276,7 +278,8 @@ bool BleMedium::StartMultipleServicesScanning(const std::vector<Uuid> &service_u
[medium_ startScanningForMultipleServices:serviceUUIDs
advertisementFoundHandler:^(id<GNCPeripheral> peripheral,
NSDictionary<CBUUID *, NSData *> *serviceData) {
HandleAdvertisementFound(peripheral, serviceData);
callback_executor_.Execute(
[this, peripheral, serviceData] { HandleAdvertisementFound(peripheral, serviceData); });
}
completionHandler:^(NSError *error) {
if (error != nil) {
@@ -349,7 +352,26 @@ std::unique_ptr<api::ble_v2::GattClient> BleMedium::ConnectToGattServer(
return nullptr;
}
__block api::ble_v2::ClientGattConnectionCallback blockCallback = std::move(callback);
api::ble_v2::ClientGattConnectionCallback thread_callback = {
.on_characteristic_changed_cb =
[this,
call_on_characteristic_changed_cb = std::move(callback.on_characteristic_changed_cb)](
absl::string_view characteristic_uuid) mutable {
callback_executor_.Execute([characteristic_uuid = std::string(characteristic_uuid),
call_on_characteristic_changed_cb = std::move(
call_on_characteristic_changed_cb)]() mutable {
call_on_characteristic_changed_cb(characteristic_uuid);
});
},
.disconnected_cb =
[this, call_disconnected_cb = std::move(callback.disconnected_cb)]() mutable {
callback_executor_.Execute(
[call_disconnected_cb = std::move(call_disconnected_cb)]() mutable {
call_disconnected_cb();
});
}};
__block api::ble_v2::ClientGattConnectionCallback blockCallback = std::move(thread_callback);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block GNCBLEGATTClient *blockClient = nil;