mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Improve BLE Peripheral Management and Socket Closure on Apple.
PiperOrigin-RevId: 805438865
This commit is contained in:
committed by
Copybara-Service
parent
1093ee2794
commit
3c9f6ecdd3
+12
@@ -96,6 +96,18 @@
|
||||
- (void)addPeripheralServiceManager:(GNSPeripheralServiceManager *)peripheralServiceManager
|
||||
bleServiceAddedCompletion:(GNSErrorHandler)completion;
|
||||
|
||||
/**
|
||||
* Removes a peripheral service manager from the managed services. It is safe to call this method
|
||||
* even if the service is not added to the BLE service database. If the GNSPeripheralManager
|
||||
* is started, the peripheral service manager will be removed right away from BLE service
|
||||
* database. |completion| is called when the method is done.
|
||||
*
|
||||
* @param serviceUUID The service UUID to remove.
|
||||
* @param completion Callback called when the service was removed.
|
||||
*/
|
||||
- (void)removePeripheralServiceManagerForServiceUUID:(CBUUID *)serviceUUID
|
||||
bleServiceRemovedCompletion:(GNSErrorHandler)completion;
|
||||
|
||||
/**
|
||||
* If the bluetooth is on, all CB services will be added, and the services will be advertised
|
||||
* (according to -[GNSPeripheralServiceManager advertising]. Otherwise, it will be done as soon as
|
||||
|
||||
+24
-7
@@ -143,11 +143,13 @@ static NSTimeInterval gKBTCrashLoopMaxTimeBetweenResetting = 15.f;
|
||||
GNCLoggerInfo(@"Peripheral manager already stopped.");
|
||||
return;
|
||||
}
|
||||
GNCLoggerInfo(@"Peripheral manager stopped.");
|
||||
_started = NO;
|
||||
[self removeAllBleServicesAndStopAdvertising];
|
||||
|
||||
[self removeAllBleServices];
|
||||
_cbPeripheralManager.delegate = nil;
|
||||
_cbPeripheralManager = nil;
|
||||
|
||||
GNCLoggerInfo(@"Peripheral manager stopped.");
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
@@ -199,8 +201,23 @@ static NSTimeInterval gKBTCrashLoopMaxTimeBetweenResetting = 15.f;
|
||||
[self updateAdvertisedServices];
|
||||
}
|
||||
|
||||
- (void)removeAllBleServicesAndStopAdvertising {
|
||||
[_cbPeripheralManager stopAdvertising];
|
||||
- (void)removePeripheralServiceManagerForServiceUUID:(CBUUID *)serviceUUID
|
||||
bleServiceRemovedCompletion:(GNSErrorHandler)completion {
|
||||
GNSPeripheralServiceManager *peripheralServiceManager =
|
||||
[_peripheralServiceManagers objectForKey:serviceUUID];
|
||||
if (peripheralServiceManager == nil) {
|
||||
completion(nil);
|
||||
return;
|
||||
}
|
||||
[_cbPeripheralManager removeService:peripheralServiceManager.cbService];
|
||||
[_peripheralServiceManagers removeObjectForKey:serviceUUID];
|
||||
[peripheralServiceManager didRemoveCBService];
|
||||
|
||||
[self updateAdvertisedServices];
|
||||
completion(nil);
|
||||
}
|
||||
|
||||
- (void)removeAllBleServices {
|
||||
_advertisementInProgressData = nil;
|
||||
_advertisementData = nil;
|
||||
|
||||
@@ -395,15 +412,15 @@ static NSTimeInterval gKBTCrashLoopMaxTimeBetweenResetting = 15.f;
|
||||
// As instructed by Apple enginners, clean-up all internal state when CoreBluetooth is
|
||||
// resetting.
|
||||
[self updateBTCrashLoopHeuristic];
|
||||
[self removeAllBleServicesAndStopAdvertising];
|
||||
[self removeAllBleServices];
|
||||
break;
|
||||
case CBManagerStateUnknown:
|
||||
// Clean-up all internal state when the CoreBluetooth state is unknown.
|
||||
[self removeAllBleServicesAndStopAdvertising];
|
||||
[self removeAllBleServices];
|
||||
break;
|
||||
case CBManagerStateUnauthorized:
|
||||
// Clean-up all internal state if the application is not authorized to use Bluetooth.
|
||||
[self removeAllBleServicesAndStopAdvertising];
|
||||
[self removeAllBleServices];
|
||||
break;
|
||||
case CBManagerStateUnsupported:
|
||||
// The application should have never attempted to start advertising if Bluetooth Low Energy
|
||||
|
||||
+20
-3
@@ -381,17 +381,25 @@ static CBMutableCharacteristic *CreatePairingCharacteristic() {
|
||||
__typeof__(weakSelf) strongSelf = weakSelf;
|
||||
if (!strongSelf || (checkConnected && !socket.isConnected)) {
|
||||
// Socket is gone or disconnected; don't reschedule.
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
if (self.cbServiceState == GNSBluetoothServiceStateNotAdded) {
|
||||
if (completion) {
|
||||
dispatch_async(_queue, completion);
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (![strongSelf.peripheralManager updateOutgoingCharacteristic:data
|
||||
onSocket:socket]) {
|
||||
GNCLoggerInfo(@"Failed to update characteristic value; reschedule");
|
||||
return NO;
|
||||
}
|
||||
if (completion) {
|
||||
dispatch_async(_queue, ^{
|
||||
completion();
|
||||
});
|
||||
dispatch_async(_queue, completion);
|
||||
}
|
||||
return YES;
|
||||
}];
|
||||
@@ -445,6 +453,15 @@ static CBMutableCharacteristic *CreatePairingCharacteristic() {
|
||||
[_peripheralManager
|
||||
updateOutgoingCharOnSocket:socket
|
||||
withHandler:^{
|
||||
if (self.cbServiceState == GNSBluetoothServiceStateNotAdded) {
|
||||
if (completion) {
|
||||
dispatch_async(_queue, ^{
|
||||
completion(nil);
|
||||
});
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
BOOL wasSent = [_peripheralManager updateOutgoingCharacteristic:data
|
||||
onSocket:socket];
|
||||
if (wasSent) {
|
||||
|
||||
@@ -235,6 +235,8 @@ class BleMedium : public api::ble_v2::BleMedium {
|
||||
|
||||
absl::Mutex l2cap_server_socket_mutex_;
|
||||
BleL2capServerSocket *l2cap_server_socket_ptr_ = nullptr;
|
||||
|
||||
dispatch_queue_t connection_callback_queue_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace apple
|
||||
|
||||
@@ -54,6 +54,8 @@
|
||||
#import "internal/platform/implementation/apple/utils.h"
|
||||
|
||||
static NSString *const kWeaveServiceUUID = @"FEF3";
|
||||
static const char *const kConnectionCallbackQueueLabel =
|
||||
"com.google.nearby.ble_medium.connection_callback_queue";
|
||||
|
||||
// Timeout for BLE operations that are initiated by a call to a public API.
|
||||
static const UInt8 kApiTimeoutInSeconds = 12;
|
||||
@@ -82,7 +84,10 @@ NSString *ConvertDataToHexString(NSData *data) {
|
||||
|
||||
} // namespace
|
||||
|
||||
BleMedium::BleMedium() : medium_([[GNCBLEMedium alloc] init]) {}
|
||||
BleMedium::BleMedium() : medium_([[GNCBLEMedium alloc] init]) {
|
||||
connection_callback_queue_ =
|
||||
dispatch_queue_create(kConnectionCallbackQueueLabel, DISPATCH_QUEUE_SERIAL);
|
||||
}
|
||||
|
||||
// ble_medium.mm
|
||||
BleMedium::~BleMedium() { [medium_ stop]; }
|
||||
@@ -115,8 +120,6 @@ bool BleMedium::StartAdvertising(const api::ble_v2::BleAdvertisementData &advert
|
||||
NSMutableDictionary<CBUUID *, NSData *> *serviceData =
|
||||
ObjCServiceDataFromCPP(advertising_data.service_data);
|
||||
|
||||
[socketPeripheralManager_ start];
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
__block NSError *blockError = nil;
|
||||
[medium_ startAdvertisingData:serviceData
|
||||
@@ -136,8 +139,6 @@ bool BleMedium::StartAdvertising(const api::ble_v2::BleAdvertisementData &advert
|
||||
}
|
||||
|
||||
bool BleMedium::StopAdvertising() {
|
||||
[socketPeripheralManager_ stop];
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
__block NSError *blockError = nil;
|
||||
[medium_ stopAdvertisingWithCompletionHandler:^(NSError *error) {
|
||||
@@ -443,6 +444,19 @@ std::unique_ptr<api::ble_v2::BleServerSocket> BleMedium::OpenServerSocket(
|
||||
const std::string &service_id) {
|
||||
auto server_socket = std::make_unique<BleServerSocket>();
|
||||
__block auto server_socket_ptr = server_socket.get();
|
||||
|
||||
if (socketPeripheralManager_) {
|
||||
[socketPeripheralManager_ stop];
|
||||
}
|
||||
|
||||
socketPeripheralManager_ = [[GNSPeripheralManager alloc] initWithAdvertisedName:nil
|
||||
restoreIdentifier:nil];
|
||||
|
||||
if (socketPeripheralManager_ == nil) {
|
||||
GNCLoggerError(@"Failed to create peripheral manager.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
socketPeripheralServiceManager_ = [[GNSPeripheralServiceManager alloc]
|
||||
initWithBleServiceUUID:[CBUUID UUIDWithString:kWeaveServiceUUID]
|
||||
addPairingCharacteristic:NO
|
||||
@@ -454,18 +468,27 @@ std::unique_ptr<api::ble_v2::BleServerSocket> BleMedium::OpenServerSocket(
|
||||
// have a service ID available to us.
|
||||
serviceID:nil
|
||||
expectedIntroPacket:YES
|
||||
callbackQueue:dispatch_get_main_queue()];
|
||||
callbackQueue:connection_callback_queue_];
|
||||
|
||||
auto socket = std::make_unique<BleSocket>(connection);
|
||||
socket->SetCloseNotifier([socketPeripheralManager = socketPeripheralManager_,
|
||||
serviceUUID = socketPeripheralServiceManager_.serviceUUID]() {
|
||||
[socketPeripheralManager
|
||||
removePeripheralServiceManagerForServiceUUID:serviceUUID
|
||||
bleServiceRemovedCompletion:^(NSError *_Nullable error) {
|
||||
GNCLoggerInfo(@"BleSocket is removed peripheral manager.");
|
||||
}];
|
||||
});
|
||||
|
||||
connection.connectionHandlers = socket->GetInputStream().GetConnectionHandlers();
|
||||
if (server_socket_ptr) {
|
||||
server_socket_ptr->Connect(std::move(socket));
|
||||
}
|
||||
|
||||
GNCLoggerInfo(@"BleServerSocket is created with connection");
|
||||
});
|
||||
return YES;
|
||||
}];
|
||||
socketPeripheralManager_ = [[GNSPeripheralManager alloc] initWithAdvertisedName:nil
|
||||
restoreIdentifier:nil];
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
__block NSError *blockError = nil;
|
||||
@@ -528,7 +551,7 @@ std::unique_ptr<api::ble_v2::BleL2capServerSocket> BleMedium::OpenL2capServerSoc
|
||||
[GNCBLEL2CAPConnection connectionWithStream:stream
|
||||
serviceID:@(service_id_str.c_str())
|
||||
incomingConnection:YES
|
||||
callbackQueue:dispatch_get_main_queue()];
|
||||
callbackQueue:connection_callback_queue_];
|
||||
auto socket = std::make_unique<BleL2capSocket>(connection);
|
||||
{
|
||||
absl::MutexLock lock(&l2cap_server_socket_mutex_);
|
||||
@@ -586,7 +609,7 @@ std::unique_ptr<api::ble_v2::BleSocket> BleMedium::Connect(
|
||||
connectionWithSocket:nssocket
|
||||
serviceID:@(service_id.c_str())
|
||||
expectedIntroPacket:NO
|
||||
callbackQueue:dispatch_get_main_queue()];
|
||||
callbackQueue:connection_callback_queue_];
|
||||
socket = std::make_unique<BleSocket>(connection, peripheral_id);
|
||||
connection.connectionHandlers =
|
||||
socket->GetInputStream().GetConnectionHandlers();
|
||||
@@ -631,7 +654,7 @@ std::unique_ptr<api::ble_v2::BleL2capSocket> BleMedium::ConnectOverL2cap(
|
||||
[GNCBLEL2CAPConnection connectionWithStream:stream
|
||||
serviceID:@(service_id_str.c_str())
|
||||
incomingConnection:NO
|
||||
callbackQueue:dispatch_get_main_queue()];
|
||||
callbackQueue:connection_callback_queue_];
|
||||
// Blocked call to wait for the packet validation result.
|
||||
// TODO: b/419654808 - Remove this once the packet validation is moved to the
|
||||
// Connections layer.
|
||||
|
||||
@@ -120,6 +120,9 @@ class BleSocket : public api::ble_v2::BleSocket {
|
||||
|
||||
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Sets a notifier that will be called when the socket is closed.
|
||||
void SetCloseNotifier(absl::AnyInvocable<void()> notifier) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
@@ -128,6 +131,7 @@ class BleSocket : public api::ble_v2::BleSocket {
|
||||
std::unique_ptr<BleInputStream> input_stream_;
|
||||
std::unique_ptr<BleOutputStream> output_stream_;
|
||||
api::ble_v2::BlePeripheral::UniqueId peripheral_id_;
|
||||
absl::AnyInvocable<void()> close_notifier_;
|
||||
};
|
||||
|
||||
} // namespace apple
|
||||
|
||||
@@ -201,11 +201,21 @@ Exception BleSocket::Close() {
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
void BleSocket::SetCloseNotifier(absl::AnyInvocable<void()> notifier) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
close_notifier_ = std::move(notifier);
|
||||
}
|
||||
|
||||
void BleSocket::DoClose() {
|
||||
if (!closed_) {
|
||||
input_stream_->Close();
|
||||
output_stream_->Close();
|
||||
closed_ = true;
|
||||
|
||||
if (close_notifier_) {
|
||||
close_notifier_();
|
||||
close_notifier_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user