@@ -260,9 +260,6 @@ @interface MTRDevice ()
260
260
@property (nonatomic , readonly ) os_unfair_lock timeSyncLock;
261
261
262
262
@property (nonatomic ) chip::FabricIndex fabricIndex;
263
- @property (nonatomic ) NSMutableArray <NSDictionary<NSString *, id> *> * unreportedEvents;
264
- @property (nonatomic ) BOOL receivingReport;
265
- @property (nonatomic ) BOOL receivingPrimingReport;
266
263
267
264
// TODO: instead of all the BOOL properties that are some facet of the state, move to internal state machine that has (at least):
268
265
// Actively receiving report
@@ -371,6 +368,7 @@ - (instancetype)initForSubclassesWithNodeID:(NSNumber *)nodeID controller:(MTRDe
371
368
_delegates = [NSMutableSet set ];
372
369
_deviceController = controller;
373
370
_nodeID = nodeID;
371
+ _state = MTRDeviceStateUnknown;
374
372
}
375
373
376
374
return self;
@@ -820,41 +818,6 @@ - (void)_callFirstDelegateSynchronouslyWithBlock:(void (^)(id<MTRDeviceDelegate>
820
818
}
821
819
#endif
822
820
823
- - (void )_callDelegateDeviceCachePrimed
824
- {
825
- os_unfair_lock_assert_owner (&self->_lock );
826
- [self _callDelegatesWithBlock: ^(id <MTRDeviceDelegate> delegate) {
827
- if ([delegate respondsToSelector: @selector (deviceCachePrimed: )]) {
828
- [delegate deviceCachePrimed: self ];
829
- }
830
- }];
831
- }
832
-
833
- // assume lock is held
834
- - (void )_changeState : (MTRDeviceState)state
835
- {
836
- os_unfair_lock_assert_owner (&self->_lock );
837
- MTRDeviceState lastState = _state;
838
- _state = state;
839
- if (lastState != state) {
840
- if (state != MTRDeviceStateReachable) {
841
- MTR_LOG (" %@ reachability state change %lu => %lu, set estimated start time to nil" , self, static_cast <unsigned long >(lastState),
842
- static_cast <unsigned long >(state));
843
- _estimatedStartTime = nil ;
844
- _estimatedStartTimeFromGeneralDiagnosticsUpTime = nil ;
845
- } else {
846
- MTR_LOG (
847
- " %@ reachability state change %lu => %lu" , self, static_cast <unsigned long >(lastState), static_cast <unsigned long >(state));
848
- }
849
- [self _callDelegatesWithBlock: ^(id <MTRDeviceDelegate> delegate) {
850
- [delegate device: self stateChanged: state];
851
- }];
852
- } else {
853
- MTR_LOG (
854
- " %@ Not reporting reachability state change, since no change in state %lu => %lu" , self, static_cast <unsigned long >(lastState), static_cast <unsigned long >(state));
855
- }
856
- }
857
-
858
821
#ifdef DEBUG
859
822
- (MTRInternalDeviceState)_getInternalState
860
823
{
@@ -906,20 +869,6 @@ - (BOOL)_deviceUsesThread
906
869
return (networkCommissioningClusterFeatureMapValue & MTRNetworkCommissioningFeatureThreadNetworkInterface) != 0 ? YES : NO ;
907
870
}
908
871
909
- - (void )_handleReportBegin
910
- {
911
- std::lock_guard lock (_lock);
912
-
913
- _receivingReport = YES ;
914
- if (_state != MTRDeviceStateReachable) {
915
- [self _changeState: MTRDeviceStateReachable];
916
- }
917
-
918
- // If we currently don't have an established subscription, this must be a
919
- // priming report.
920
- _receivingPrimingReport = YES ;
921
- }
922
-
923
872
- (NSDictionary <MTRClusterPath *, MTRDeviceClusterData *> *)_clusterDataToPersistSnapshot
924
873
{
925
874
os_unfair_lock_assert_owner (&self->_lock );
@@ -1202,49 +1151,6 @@ - (void)setStorageBehaviorConfiguration:(MTRDeviceStorageBehaviorConfiguration *
1202
1151
[self _resetStorageBehaviorState ];
1203
1152
}
1204
1153
1205
- - (void )_handleReportEnd
1206
- {
1207
- std::lock_guard lock (_lock);
1208
- _receivingReport = NO ;
1209
- _receivingPrimingReport = NO ;
1210
- _estimatedStartTimeFromGeneralDiagnosticsUpTime = nil ;
1211
-
1212
- [self _scheduleClusterDataPersistence ];
1213
-
1214
- // After the handling of the report, if we detected a device configuration change, notify the delegate
1215
- // of the same.
1216
- if (_deviceConfigurationChanged) {
1217
- [self _callDelegatesWithBlock: ^(id <MTRDeviceDelegate> delegate) {
1218
- if ([delegate respondsToSelector: @selector (deviceConfigurationChanged: )]) {
1219
- [delegate deviceConfigurationChanged: self ];
1220
- }
1221
- }];
1222
- _deviceConfigurationChanged = NO ;
1223
- }
1224
-
1225
- // Do this after the _deviceConfigurationChanged check, so that we don't
1226
- // call deviceConfigurationChanged: immediately after telling our delegate
1227
- // we are now primed.
1228
- //
1229
- // TODO: Maybe we shouldn't dispatch deviceConfigurationChanged: for the
1230
- // initial priming bits?
1231
- if (!_deviceCachePrimed) {
1232
- // This is the end of the priming sequence of data reports, so we have
1233
- // all the data for the device now.
1234
- _deviceCachePrimed = YES ;
1235
- [self _callDelegateDeviceCachePrimed ];
1236
- }
1237
-
1238
- // For unit testing only
1239
- #ifdef DEBUG
1240
- [self _callDelegatesWithBlock: ^(id testDelegate) {
1241
- if ([testDelegate respondsToSelector: @selector (unitTestReportEndForDevice: )]) {
1242
- [testDelegate unitTestReportEndForDevice: self ];
1243
- }
1244
- }];
1245
- #endif
1246
- }
1247
-
1248
1154
- (BOOL )_interestedPaths : (NSArray * _Nullable)interestedPaths includesAttributePath : (MTRAttributePath *)attributePath
1249
1155
{
1250
1156
for (id interestedPath in interestedPaths) {
@@ -1316,29 +1222,15 @@ - (void)_reportAttributes:(NSArray<NSDictionary<NSString *, id> *> *)attributes
1316
1222
}
1317
1223
}
1318
1224
1319
- - (void )_handleAttributeReport : (NSArray <NSDictionary<NSString *, id> *> *)attributeReport fromSubscription : (BOOL )isFromSubscription
1320
- {
1321
- std::lock_guard lock (_lock);
1322
-
1323
- // _getAttributesToReportWithReportedValues will log attribute paths reported
1324
- [self _reportAttributes: [self _getAttributesToReportWithReportedValues: attributeReport fromSubscription: isFromSubscription]];
1325
- }
1326
-
1327
1225
#ifdef DEBUG
1328
1226
- (void )unitTestInjectEventReport : (NSArray <NSDictionary<NSString *, id> *> *)eventReport
1329
1227
{
1330
- dispatch_async (self.queue , ^{
1331
- [self _handleEventReport: eventReport];
1332
- });
1228
+ NSAssert (NO , @" Unit test injection of reports needs to be handled by subclasses" );
1333
1229
}
1334
1230
1335
1231
- (void )unitTestInjectAttributeReport : (NSArray <NSDictionary<NSString *, id> *> *)attributeReport fromSubscription : (BOOL )isFromSubscription
1336
1232
{
1337
- dispatch_async (self.queue , ^{
1338
- [self _handleReportBegin ];
1339
- [self _handleAttributeReport: attributeReport fromSubscription: isFromSubscription];
1340
- [self _handleReportEnd ];
1341
- });
1233
+ NSAssert (NO , @" Unit test injection of reports needs to be handled by subclasses" );
1342
1234
}
1343
1235
#endif
1344
1236
@@ -1396,111 +1288,6 @@ - (BOOL)_interestedPaths:(NSArray * _Nullable)interestedPaths includesEventPath:
1396
1288
return filteredEvents;
1397
1289
}
1398
1290
1399
- - (void )_handleEventReport : (NSArray <NSDictionary<NSString *, id> *> *)eventReport
1400
- {
1401
- std::lock_guard lock (_lock);
1402
-
1403
- NSDate * oldEstimatedStartTime = _estimatedStartTime;
1404
- // Combine with previous unreported events, if they exist
1405
- NSMutableArray * reportToReturn;
1406
- if (_unreportedEvents) {
1407
- reportToReturn = _unreportedEvents;
1408
- } else {
1409
- reportToReturn = [NSMutableArray array ];
1410
- }
1411
- for (NSDictionary <NSString *, id > * eventDict in eventReport) {
1412
- // Whenever a StartUp event is received, reset the estimated start time
1413
- // New subscription case
1414
- // - Starts Unreachable
1415
- // - Start CASE and send subscription request
1416
- // - Receive priming report ReportBegin
1417
- // - Optionally receive UpTime attribute - update time and save start time estimate
1418
- // - Optionally receive StartUp event
1419
- // - Set estimated system time from event receipt time, or saved UpTime estimate if exists
1420
- // - ReportEnd handler clears the saved start time estimate based on UpTime
1421
- // Subscription dropped from client point of view case
1422
- // - Starts Unreachable
1423
- // - Resubscribe happens after some time, and then same as the above
1424
- // Server resuming subscription after reboot case
1425
- // - Starts Reachable
1426
- // - Receive priming report ReportBegin
1427
- // - Optionally receive UpTime attribute - update time and save value
1428
- // - Optionally receive StartUp event
1429
- // - Set estimated system time from event receipt time, or saved UpTime estimate if exists
1430
- // - ReportEnd handler clears the saved start time estimate based on UpTime
1431
- // Server resuming subscription after timeout case
1432
- // - Starts Reachable
1433
- // - Receive priming report ReportBegin
1434
- // - Optionally receive UpTime attribute - update time and save value
1435
- // - ReportEnd handler clears the saved start time estimate based on UpTime
1436
- MTREventPath * eventPath = eventDict[MTREventPathKey];
1437
- BOOL isStartUpEvent = (eventPath.cluster .unsignedLongValue == MTRClusterIDTypeBasicInformationID)
1438
- && (eventPath.event .unsignedLongValue == MTREventIDTypeClusterBasicInformationEventStartUpID);
1439
- if (isStartUpEvent) {
1440
- if (_estimatedStartTimeFromGeneralDiagnosticsUpTime) {
1441
- // If UpTime was received, make use of it as mark of system start time
1442
- MTR_LOG (" %@ StartUp event: set estimated start time forward to %@" , self,
1443
- _estimatedStartTimeFromGeneralDiagnosticsUpTime);
1444
- _estimatedStartTime = _estimatedStartTimeFromGeneralDiagnosticsUpTime;
1445
- } else {
1446
- // If UpTime was not received, reset estimated start time in case of reboot
1447
- MTR_LOG (" %@ StartUp event: set estimated start time to nil" , self);
1448
- _estimatedStartTime = nil ;
1449
- }
1450
- }
1451
-
1452
- // If event time is of MTREventTimeTypeSystemUpTime type, then update estimated start time as needed
1453
- NSNumber * eventTimeTypeNumber = eventDict[MTREventTimeTypeKey];
1454
- if (!eventTimeTypeNumber) {
1455
- MTR_LOG_ERROR (" %@ Event %@ missing event time type" , self, eventDict);
1456
- continue ;
1457
- }
1458
- MTREventTimeType eventTimeType = (MTREventTimeType) eventTimeTypeNumber.unsignedIntegerValue ;
1459
- if (eventTimeType == MTREventTimeTypeSystemUpTime) {
1460
- NSNumber * eventTimeValueNumber = eventDict[MTREventSystemUpTimeKey];
1461
- if (!eventTimeValueNumber) {
1462
- MTR_LOG_ERROR (" %@ Event %@ missing event time value" , self, eventDict);
1463
- continue ;
1464
- }
1465
- NSTimeInterval eventTimeValue = eventTimeValueNumber.doubleValue ;
1466
- NSDate * potentialSystemStartTime = [NSDate dateWithTimeIntervalSinceNow: -eventTimeValue];
1467
- if (!_estimatedStartTime || ([potentialSystemStartTime compare: _estimatedStartTime] == NSOrderedAscending)) {
1468
- _estimatedStartTime = potentialSystemStartTime;
1469
- }
1470
- }
1471
-
1472
- NSMutableDictionary * eventToReturn = eventDict.mutableCopy ;
1473
- if (_receivingPrimingReport) {
1474
- eventToReturn[MTREventIsHistoricalKey] = @(YES );
1475
- } else {
1476
- eventToReturn[MTREventIsHistoricalKey] = @(NO );
1477
- }
1478
-
1479
- [reportToReturn addObject: eventToReturn];
1480
- }
1481
- if (oldEstimatedStartTime != _estimatedStartTime) {
1482
- MTR_LOG (" %@ updated estimated start time to %@" , self, _estimatedStartTime);
1483
- }
1484
-
1485
- __block BOOL delegatesCalled = NO ;
1486
- [self _iterateDelegatesWithBlock: ^(MTRDeviceDelegateInfo * delegateInfo) {
1487
- // _iterateDelegatesWithBlock calls this with an autorelease pool, and so temporary filtered event reports don't bloat memory
1488
- NSArray <NSDictionary <NSString *, id > *> * filteredEvents = [self _filteredEvents: reportToReturn forInterestedPaths: delegateInfo.interestedPathsForEvents];
1489
- if (filteredEvents.count ) {
1490
- [delegateInfo callDelegateWithBlock: ^(id <MTRDeviceDelegate> delegate) {
1491
- [delegate device: self receivedEventReport: filteredEvents];
1492
- }];
1493
- delegatesCalled = YES ;
1494
- }
1495
- }];
1496
- if (delegatesCalled) {
1497
- _unreportedEvents = nil ;
1498
- } else {
1499
- // save unreported events
1500
- _unreportedEvents = reportToReturn;
1501
- }
1502
- }
1503
-
1504
1291
#ifdef DEBUG
1505
1292
- (void )unitTestClearClusterData
1506
1293
{
@@ -1639,7 +1426,6 @@ - (void)_setCachedAttributeValue:(MTRDeviceDataValueDictionary _Nullable)value f
1639
1426
1640
1427
if (value != nil
1641
1428
&& isFromSubscription
1642
- && !_receivingPrimingReport
1643
1429
&& AttributeHasChangesOmittedQuality (path)) {
1644
1430
// Do not persist new values for Changes Omitted Quality (aka C Quality)
1645
1431
// attributes unless they're part of a Priming Report or from a read response.
@@ -2374,11 +2160,6 @@ - (NSArray *)_getAttributesToReportWithReportedValues:(NSArray<NSDictionary<NSSt
2374
2160
continue ;
2375
2161
}
2376
2162
2377
- // Additional signal to help mark events as being received during priming report in the event the device rebooted and we get a subscription resumption priming report without noticing it became unreachable first
2378
- if (_receivingReport && AttributeHasChangesOmittedQuality (attributePath)) {
2379
- _receivingPrimingReport = YES ;
2380
- }
2381
-
2382
2163
// check if value is different than cache, and report if needed
2383
2164
BOOL shouldReportAttribute = NO ;
2384
2165
0 commit comments