|
28 | 28 | #import "MTRCommandTimedCheck.h"
|
29 | 29 | #import "MTRConversion.h"
|
30 | 30 | #import "MTRDefines_Internal.h"
|
| 31 | +#import "MTRDeviceConnectivityMonitor.h" |
31 | 32 | #import "MTRDeviceControllerOverXPC.h"
|
32 | 33 | #import "MTRDeviceController_Internal.h"
|
33 | 34 | #import "MTRDevice_Internal.h"
|
@@ -355,6 +356,7 @@ @implementation MTRDevice {
|
355 | 356 | // _setupSubscription or via the auto-resubscribe behavior of the
|
356 | 357 | // ReadClient). Nil if we have had no such failures.
|
357 | 358 | NSDate * _Nullable _lastSubscriptionFailureTime;
|
| 359 | + MTRDeviceConnectivityMonitor * _connectivityMonitor; |
358 | 360 | }
|
359 | 361 |
|
360 | 362 | - (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller
|
@@ -669,6 +671,8 @@ - (void)invalidate
|
669 | 671 | // subscription. In that case, _internalDeviceState will update when the
|
670 | 672 | // subscription is actually terminated.
|
671 | 673 |
|
| 674 | + [self _stopConnectivityMonitoring]; |
| 675 | + |
672 | 676 | os_unfair_lock_unlock(&self->_lock);
|
673 | 677 | }
|
674 | 678 |
|
@@ -861,6 +865,9 @@ - (void)_handleSubscriptionEstablished
|
861 | 865 |
|
862 | 866 | [self _changeState:MTRDeviceStateReachable];
|
863 | 867 |
|
| 868 | + // No need to monitor connectivity after subscription establishment |
| 869 | + [self _stopConnectivityMonitoring]; |
| 870 | + |
864 | 871 | os_unfair_lock_unlock(&self->_lock);
|
865 | 872 |
|
866 | 873 | os_unfair_lock_lock(&self->_timeSyncLock);
|
@@ -894,6 +901,9 @@ - (void)_handleResubscriptionNeeded
|
894 | 901 | // former case we recently had a subscription and do not want to be forcing
|
895 | 902 | // retries immediately.
|
896 | 903 | _lastSubscriptionFailureTime = [NSDate now];
|
| 904 | + |
| 905 | + // Set up connectivity monitoring in case network routability changes for the positive, to accellerate resubscription |
| 906 | + [self _setupConnectivityMonitoring]; |
897 | 907 | }
|
898 | 908 |
|
899 | 909 | - (void)_handleSubscriptionReset:(NSNumber * _Nullable)retryDelay
|
@@ -1241,6 +1251,44 @@ - (void)_createDataVersionFilterListFromDictionary:(NSDictionary<MTRClusterPath
|
1241 | 1251 | *count = maxDataVersionFilterSize;
|
1242 | 1252 | }
|
1243 | 1253 |
|
| 1254 | +- (void)_setupConnectivityMonitoring |
| 1255 | +{ |
| 1256 | + // Dispatch to own queue first to avoid deadlock with syncGetCompressedFabricID |
| 1257 | + dispatch_async(self.queue, ^{ |
| 1258 | + // Get the required info before setting up the connectivity monitor |
| 1259 | + NSNumber * compressedFabricID = [self->_deviceController syncGetCompressedFabricID]; |
| 1260 | + if (!compressedFabricID) { |
| 1261 | + MTR_LOG_INFO("%@ could not get compressed fabricID", self); |
| 1262 | + return; |
| 1263 | + } |
| 1264 | + |
| 1265 | + // Now lock for _connectivityMonitor |
| 1266 | + std::lock_guard lock(self->_lock); |
| 1267 | + if (self->_connectivityMonitor) { |
| 1268 | + // already monitoring |
| 1269 | + return; |
| 1270 | + } |
| 1271 | + |
| 1272 | + self->_connectivityMonitor = [[MTRDeviceConnectivityMonitor alloc] initWithCompressedFabricID:compressedFabricID nodeID:self.nodeID]; |
| 1273 | + [self->_connectivityMonitor startMonitoringWithHandler:^{ |
| 1274 | + [self->_deviceController asyncDispatchToMatterQueue:^{ |
| 1275 | + [self _triggerResubscribeWithReason:"read-through skipped while not subscribed" nodeLikelyReachable:YES]; |
| 1276 | + } |
| 1277 | + errorHandler:nil]; |
| 1278 | + } queue:self.queue]; |
| 1279 | + }); |
| 1280 | +} |
| 1281 | + |
| 1282 | +- (void)_stopConnectivityMonitoring |
| 1283 | +{ |
| 1284 | + os_unfair_lock_assert_owner(&_lock); |
| 1285 | + |
| 1286 | + if (_connectivityMonitor) { |
| 1287 | + [_connectivityMonitor stopMonitoring]; |
| 1288 | + _connectivityMonitor = nil; |
| 1289 | + } |
| 1290 | +} |
| 1291 | + |
1244 | 1292 | // assume lock is held
|
1245 | 1293 | - (void)_setupSubscription
|
1246 | 1294 | {
|
@@ -1462,6 +1510,9 @@ - (void)_setupSubscription
|
1462 | 1510 | callback->AdoptClusterStateCache(std::move(clusterStateCache));
|
1463 | 1511 | callback.release();
|
1464 | 1512 | }];
|
| 1513 | + |
| 1514 | + // Set up connectivity monitoring in case network becomes routable after any part of the subscription process goes into backoff retries. |
| 1515 | + [self _setupConnectivityMonitoring]; |
1465 | 1516 | }
|
1466 | 1517 |
|
1467 | 1518 | #ifdef DEBUG
|
|
0 commit comments