Skip to content

Commit 2a42270

Browse files
committed
[Darwin] MTRDeviceConnectivityMonitor stopMonitoring crash fix
1 parent 20b1457 commit 2a42270

File tree

2 files changed

+30
-23
lines changed

2 files changed

+30
-23
lines changed

src/darwin/Framework/CHIP/MTRDevice.mm

+23-21
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,8 @@ @implementation MTRDevice {
395395
NSMutableSet<MTRClusterPath *> * _persistedClusters;
396396

397397
// When we last failed to subscribe to the device (either via
398-
// _setupSubscription or via the auto-resubscribe behavior of the
399-
// ReadClient). Nil if we have had no such failures.
398+
// _setupSubscriptionWithReason or via the auto-resubscribe behavior
399+
// of the ReadClient). Nil if we have had no such failures.
400400
NSDate * _Nullable _lastSubscriptionFailureTime;
401401
MTRDeviceConnectivityMonitor * _connectivityMonitor;
402402

@@ -745,10 +745,10 @@ - (void)setDelegate:(id<MTRDeviceDelegate>)delegate queue:(dispatch_queue_t)queu
745745
if ([self _deviceUsesThread]) {
746746
[self _scheduleSubscriptionPoolWork:^{
747747
std::lock_guard lock(self->_lock);
748-
[self _setupSubscription];
748+
[self _setupSubscriptionWithReason:@"delegate is set and subscription is scheduled"];
749749
} inNanoseconds:0 description:@"MTRDevice setDelegate first subscription"];
750750
} else {
751-
[self _setupSubscription];
751+
[self _setupSubscriptionWithReason:@"delegate is set and subscription is needed"];
752752
}
753753
}
754754
}
@@ -788,14 +788,14 @@ - (void)nodeMayBeAdvertisingOperational
788788

789789
MTR_LOG("%@ saw new operational advertisement", self);
790790

791-
[self _triggerResubscribeWithReason:"operational advertisement seen"
791+
[self _triggerResubscribeWithReason:@"operational advertisement seen"
792792
nodeLikelyReachable:YES];
793793
}
794794

795795
// Trigger a resubscribe as needed. nodeLikelyReachable should be YES if we
796796
// have reason to suspect the node is now reachable, NO if we have no idea
797797
// whether it might be.
798-
- (void)_triggerResubscribeWithReason:(const char *)reason nodeLikelyReachable:(BOOL)nodeLikelyReachable
798+
- (void)_triggerResubscribeWithReason:(NSString *)reason nodeLikelyReachable:(BOOL)nodeLikelyReachable
799799
{
800800
assertChipStackLockedByCurrentThread();
801801

@@ -814,7 +814,7 @@ - (void)_triggerResubscribeWithReason:(const char *)reason nodeLikelyReachable:(
814814
// establish a CASE session. And at that point, our subscription will
815815
// trigger the state change as needed.
816816
if (self.reattemptingSubscription) {
817-
[self _reattemptSubscriptionNowIfNeeded];
817+
[self _reattemptSubscriptionNowIfNeededWithReason:reason];
818818
} else {
819819
readClientToResubscribe = self->_currentReadClient;
820820
subscriptionCallback = self->_currentSubscriptionCallback;
@@ -829,7 +829,7 @@ - (void)_triggerResubscribeWithReason:(const char *)reason nodeLikelyReachable:(
829829
// here (e.g. still booting up), but should try again reasonably quickly.
830830
subscriptionCallback->ResetResubscriptionBackoff();
831831
}
832-
readClientToResubscribe->TriggerResubscribeIfScheduled(reason);
832+
readClientToResubscribe->TriggerResubscribeIfScheduled(reason.UTF8String);
833833
}
834834
}
835835

@@ -893,7 +893,7 @@ - (void)_readThroughSkipped
893893
// ReadClient in there. If the dispatch fails, that's fine; it means our
894894
// controller has shut down, so nothing to be done.
895895
[_deviceController asyncDispatchToMatterQueue:^{
896-
[self _triggerResubscribeWithReason:"read-through skipped while not subscribed" nodeLikelyReachable:NO];
896+
[self _triggerResubscribeWithReason:@"read-through skipped while not subscribed" nodeLikelyReachable:NO];
897897
}
898898
errorHandler:nil];
899899
}
@@ -1160,7 +1160,7 @@ - (void)_handleResubscriptionNeededWithDelay:(NSNumber *)resubscriptionDelayMs
11601160
// this block is run -- if other triggering events had happened, this would become a no-op.
11611161
auto resubscriptionBlock = ^{
11621162
[self->_deviceController asyncDispatchToMatterQueue:^{
1163-
[self _triggerResubscribeWithReason:"ResubscriptionNeeded timer fired" nodeLikelyReachable:NO];
1163+
[self _triggerResubscribeWithReason:@"ResubscriptionNeeded timer fired" nodeLikelyReachable:NO];
11641164
} errorHandler:^(NSError * _Nonnull error) {
11651165
// If controller is not running, clear work item from the subscription queue
11661166
MTR_LOG_ERROR("%@ could not dispatch to matter queue for resubscription - error %@", self, error);
@@ -1235,25 +1235,25 @@ - (void)_handleSubscriptionReset:(NSNumber * _Nullable)retryDelay
12351235
// If we started subscription or session establishment but failed, remove item from the subscription pool so we can re-queue.
12361236
[self _clearSubscriptionPoolWork];
12371237

1238-
// Call _reattemptSubscriptionNowIfNeeded when timer fires - if subscription is
1238+
// Call _reattemptSubscriptionNowIfNeededWithReason when timer fires - if subscription is
12391239
// in a better state at that time this will be a no-op.
12401240
auto resubscriptionBlock = ^{
12411241
os_unfair_lock_lock(&self->_lock);
1242-
[self _reattemptSubscriptionNowIfNeeded];
1242+
[self _reattemptSubscriptionNowIfNeededWithReason:@"got subscription reset"];
12431243
os_unfair_lock_unlock(&self->_lock);
12441244
};
12451245

12461246
int64_t resubscriptionDelayNs = static_cast<int64_t>(secondsToWait * NSEC_PER_SEC);
12471247
if ([self _deviceUsesThread]) {
1248-
// For Thread-enabled devices, schedule the _reattemptSubscriptionNowIfNeeded call to run in the subscription pool
1248+
// For Thread-enabled devices, schedule the _reattemptSubscriptionNowIfNeededWithReason call to run in the subscription pool
12491249
[self _scheduleSubscriptionPoolWork:resubscriptionBlock inNanoseconds:resubscriptionDelayNs description:@"MTRDevice resubscription"];
12501250
} else {
12511251
// For non-Thread-enabled devices, just call the resubscription block after the specified time
12521252
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, resubscriptionDelayNs), self.queue, resubscriptionBlock);
12531253
}
12541254
}
12551255

1256-
- (void)_reattemptSubscriptionNowIfNeeded
1256+
- (void)_reattemptSubscriptionNowIfNeededWithReason:(NSString *)reason
12571257
{
12581258
os_unfair_lock_assert_owner(&self->_lock);
12591259
if (!self.reattemptingSubscription) {
@@ -1262,7 +1262,7 @@ - (void)_reattemptSubscriptionNowIfNeeded
12621262

12631263
MTR_LOG("%@ reattempting subscription", self);
12641264
self.reattemptingSubscription = NO;
1265-
[self _setupSubscription];
1265+
[self _setupSubscriptionWithReason:reason];
12661266
}
12671267

12681268
- (void)_handleUnsolicitedMessageFromPublisher
@@ -1284,8 +1284,8 @@ - (void)_handleUnsolicitedMessageFromPublisher
12841284
// reestablishment, this starts the attempt right away
12851285
// TODO: This doesn't really make sense. If we _don't_ have a live
12861286
// ReadClient how did we get this notification and if we _do_ have an active
1287-
// ReadClient, this call or _setupSubscription would be no-ops.
1288-
[self _reattemptSubscriptionNowIfNeeded];
1287+
// ReadClient, this call or _setupSubscriptionWithReason would be no-ops.
1288+
[self _reattemptSubscriptionNowIfNeededWithReason:@"got unsolicited message from publisher"];
12891289
}
12901290

12911291
- (void)_markDeviceAsUnreachableIfNeverSubscribed
@@ -1941,7 +1941,7 @@ - (void)_setupConnectivityMonitoring
19411941
self->_connectivityMonitor = [[MTRDeviceConnectivityMonitor alloc] initWithCompressedFabricID:compressedFabricID nodeID:self.nodeID];
19421942
[self->_connectivityMonitor startMonitoringWithHandler:^{
19431943
[self->_deviceController asyncDispatchToMatterQueue:^{
1944-
[self _triggerResubscribeWithReason:"device connectivity changed" nodeLikelyReachable:YES];
1944+
[self _triggerResubscribeWithReason:@"device connectivity changed" nodeLikelyReachable:YES];
19451945
}
19461946
errorHandler:nil];
19471947
} queue:self.queue];
@@ -1959,12 +1959,12 @@ - (void)_stopConnectivityMonitoring
19591959
}
19601960

19611961
// assume lock is held
1962-
- (void)_setupSubscription
1962+
- (void)_setupSubscriptionWithReason:(NSString *)reason
19631963
{
19641964
os_unfair_lock_assert_owner(&self->_lock);
19651965

19661966
if (![self _subscriptionsAllowed]) {
1967-
MTR_LOG("_setupSubscription: Subscriptions not allowed. Do not set up subscription");
1967+
MTR_LOG("%@ _setupSubscription: Subscriptions not allowed. Do not set up subscription", self);
19681968
return;
19691969
}
19701970

@@ -1986,6 +1986,8 @@ - (void)_setupSubscription
19861986

19871987
[self _changeInternalState:MTRInternalDeviceStateSubscribing];
19881988

1989+
MTR_LOG("%@ setting up subscription with reason: %@", self, reason);
1990+
19891991
// Set up a timer to mark as not reachable if it takes too long to set up a subscription
19901992
MTRWeakReference<MTRDevice *> * weakSelf = [MTRWeakReference weakReferenceWithObject:self];
19911993
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, static_cast<int64_t>(kSecondsToWaitBeforeMarkingUnreachableAfterSettingUpSubscription) * static_cast<int64_t>(NSEC_PER_SEC)), self.queue, ^{
@@ -3512,7 +3514,7 @@ - (void)_deviceMayBeReachable
35123514

35133515
MTR_LOG("%@ _deviceMayBeReachable called", self);
35143516

3515-
[self _triggerResubscribeWithReason:"SPI client indicated the device may now be reachable"
3517+
[self _triggerResubscribeWithReason:@"SPI client indicated the device may now be reachable"
35163518
nodeLikelyReachable:YES];
35173519
}
35183520

src/darwin/Framework/CHIP/MTRDeviceConnectivityMonitor.mm

+7-2
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ - (void)_stopMonitoring
258258
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, kSharedConnectionLingerIntervalSeconds * NSEC_PER_SEC), sSharedResolverQueue, ^{
259259
std::lock_guard lock(sConnectivityMonitorLock);
260260

261-
if (!sConnectivityMonitorCount) {
261+
if (!sConnectivityMonitorCount && sSharedResolverConnection) {
262262
MTR_LOG("MTRDeviceConnectivityMonitor: Closing shared resolver connection");
263263
DNSServiceRefDeallocate(sSharedResolverConnection);
264264
sSharedResolverConnection = NULL;
@@ -271,9 +271,14 @@ - (void)_stopMonitoring
271271

272272
- (void)stopMonitoring
273273
{
274+
MTR_LOG("%@ stop connectivity monitoring for %@", self, self->_instanceName);
275+
std::lock_guard lock(sConnectivityMonitorLock);
276+
if (!sSharedResolverConnection || !sSharedResolverQueue) {
277+
MTR_LOG("%@ shared resolver connection already stopped - nothing to do", self);
278+
}
279+
274280
// DNSServiceRefDeallocate must be called on the same queue set on the shared connection.
275281
dispatch_async(sSharedResolverQueue, ^{
276-
MTR_LOG("%@ stop connectivity monitoring for %@", self, self->_instanceName);
277282
std::lock_guard lock(sConnectivityMonitorLock);
278283
[self _stopMonitoring];
279284
});

0 commit comments

Comments
 (0)