Improve BLE Peripheral Management and Socket Closure on Apple.

PiperOrigin-RevId: 805438865
This commit is contained in:
Guogang Li
2025-09-10 11:14:14 -07:00
committed by Copybara-Service
parent 1093ee2794
commit 3c9f6ecdd3
7 changed files with 106 additions and 21 deletions
@@ -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
@@ -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
@@ -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) {