Skip to content

Commit c98660c

Browse files
Remove readAttributeWithEndpointID implementation from MTRDevice.
This is implemented (differently) by the different subclasses. Once this implementation is removed, the following become unreachable and can be removed: * _attributeValueDictionaryForAttributePath * _subscriptionAbleToReport * _readThroughSkipped At that point _subscriptionsAllowed becomes unreachable and can be removed.
1 parent 07789d4 commit c98660c

File tree

1 file changed

+7
-222
lines changed

1 file changed

+7
-222
lines changed

src/darwin/Framework/CHIP/MTRDevice.mm

+7-222
Original file line numberDiff line numberDiff line change
@@ -649,21 +649,7 @@ - (void)_setDSTOffsets:(NSArray<MTRTimeSynchronizationClusterDSTOffsetStruct *>
649649
return outputArray;
650650
}
651651

652-
#pragma mark Subscription and delegate handling
653-
654-
// subscription intervals are in seconds
655-
#define MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MIN (10 * 60) // 10 minutes (for now)
656-
#define MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MAX (60 * 60) // 60 minutes
657-
658-
- (BOOL)_subscriptionsAllowed
659-
{
660-
os_unfair_lock_assert_owner(&self->_lock);
661-
662-
// TODO: XPC: This function and all its callsites should go away from this class.
663-
664-
// We should not allow a subscription for device controllers over XPC.
665-
return ![_deviceController isKindOfClass:MTRDeviceControllerOverXPC.class];
666-
}
652+
#pragma mark Delegate handling
667653

668654
- (void)setDelegate:(id<MTRDeviceDelegate>)delegate queue:(dispatch_queue_t)queue
669655
{
@@ -757,41 +743,6 @@ - (void)nodeMayBeAdvertisingOperational
757743
MTR_LOG("%@ saw new operational advertisement", self);
758744
}
759745

760-
// Return YES if we are in a state where, apart from communication issues with
761-
// the device, we will be able to get reports via our subscription.
762-
- (BOOL)_subscriptionAbleToReport
763-
{
764-
std::lock_guard lock(_lock);
765-
if (![self _delegateExists]) {
766-
// No delegate definitely means no subscription.
767-
return NO;
768-
}
769-
770-
// For unit testing only, matching logic in setDelegate
771-
#ifdef DEBUG
772-
__block BOOL useTestDelegateOverride = NO;
773-
__block BOOL testDelegateShouldSetUpSubscriptionForDevice = NO;
774-
[self _callFirstDelegateSynchronouslyWithBlock:^(id testDelegate) {
775-
if ([testDelegate respondsToSelector:@selector(unitTestShouldSetUpSubscriptionForDevice:)]) {
776-
useTestDelegateOverride = YES;
777-
testDelegateShouldSetUpSubscriptionForDevice = [testDelegate unitTestShouldSetUpSubscriptionForDevice:self];
778-
}
779-
}];
780-
if (useTestDelegateOverride && !testDelegateShouldSetUpSubscriptionForDevice) {
781-
return NO;
782-
}
783-
784-
#endif
785-
786-
// Subscriptions are not able to report if they are not allowed.
787-
return [self _subscriptionsAllowed];
788-
}
789-
790-
// Notification that read-through was skipped for an attribute read.
791-
- (void)_readThroughSkipped
792-
{
793-
}
794-
795746
- (BOOL)_delegateExists
796747
{
797748
os_unfair_lock_assert_owner(&self->_lock);
@@ -1880,147 +1831,12 @@ static BOOL AttributeHasChangesOmittedQuality(MTRAttributePath * attributePath)
18801831
attributeID:(NSNumber *)attributeID
18811832
params:(MTRReadParams * _Nullable)params
18821833
{
1883-
MTRAttributePath * attributePath = [MTRAttributePath attributePathWithEndpointID:endpointID
1884-
clusterID:clusterID
1885-
attributeID:attributeID];
1886-
1887-
BOOL attributeIsSpecified = MTRAttributeIsSpecified(clusterID.unsignedIntValue, attributeID.unsignedIntValue);
1888-
BOOL hasChangesOmittedQuality;
1889-
if (attributeIsSpecified) {
1890-
hasChangesOmittedQuality = AttributeHasChangesOmittedQuality(attributePath);
1891-
} else {
1892-
if (params == nil) {
1893-
hasChangesOmittedQuality = NO;
1894-
} else {
1895-
hasChangesOmittedQuality = !params.assumeUnknownAttributesReportable;
1896-
}
1897-
}
1898-
1899-
// Return current known / expected value right away
1900-
NSDictionary<NSString *, id> * attributeValueToReturn = [self _attributeValueDictionaryForAttributePath:attributePath];
1901-
1902-
// Send read request to device if any of the following are true:
1903-
// 1. Subscription not in a state we can expect reports
1904-
// 2. The attribute has the Changes Omitted quality, so we won't get reports for it.
1905-
// 3. The attribute is not in the spec, and the read params asks to assume
1906-
// an unknown attribute has the Changes Omitted quality.
1907-
if (![self _subscriptionAbleToReport] || hasChangesOmittedQuality) {
1908-
// Read requests container will be a mutable array of items, each being an array containing:
1909-
// [attribute request path, params]
1910-
// Batching handler should only coalesce when params are equal.
1911-
1912-
// For this single read API there's only 1 array item. Use NSNull to stand in for nil params for easy comparison.
1913-
MTRAttributeRequestPath * readRequestPath = [MTRAttributeRequestPath requestPathWithEndpointID:endpointID
1914-
clusterID:clusterID
1915-
attributeID:attributeID];
1916-
NSArray * readRequestData = @[ readRequestPath, params ?: [NSNull null] ];
1917-
1918-
// But first, check if a duplicate read request is already queued and return
1919-
if ([_asyncWorkQueue hasDuplicateForTypeID:MTRDeviceWorkItemDuplicateReadTypeID workItemData:readRequestData]) {
1920-
return attributeValueToReturn;
1921-
}
1922-
1923-
NSMutableArray<NSArray *> * readRequests = [NSMutableArray arrayWithObject:readRequestData];
1924-
1925-
// Create work item, set ready handler to perform task, then enqueue the work
1926-
MTRAsyncWorkItem * workItem = [[MTRAsyncWorkItem alloc] initWithQueue:self.queue];
1927-
uint64_t workItemID = workItem.uniqueID; // capture only the ID, not the work item
1928-
NSNumber * nodeID = [self nodeID];
1929-
1930-
[workItem setBatchingID:MTRDeviceWorkItemBatchingReadID data:readRequests handler:^(id opaqueDataCurrent, id opaqueDataNext) {
1931-
mtr_hide(self); // don't capture self accidentally
1932-
NSMutableArray<NSArray *> * readRequestsCurrent = opaqueDataCurrent;
1933-
NSMutableArray<NSArray *> * readRequestsNext = opaqueDataNext;
1934-
1935-
MTRBatchingOutcome outcome = MTRNotBatched;
1936-
while (readRequestsNext.count) {
1937-
// Can only read up to 9 paths at a time, per spec
1938-
if (readRequestsCurrent.count >= 9) {
1939-
MTR_LOG("Batching read attribute work item [%llu]: cannot add more work, item is full [0x%016llX:%@:0x%llx:0x%llx]", workItemID, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue);
1940-
return outcome;
1941-
}
1942-
1943-
// if params don't match then they cannot be merged
1944-
if (![readRequestsNext[0][MTRDeviceReadRequestFieldParamsIndex]
1945-
isEqual:readRequestsCurrent[0][MTRDeviceReadRequestFieldParamsIndex]]) {
1946-
MTR_LOG("Batching read attribute work item [%llu]: cannot add more work, parameter mismatch [0x%016llX:%@:0x%llx:0x%llx]", workItemID, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue);
1947-
return outcome;
1948-
}
1949-
1950-
// merge the next item's first request into the current item's list
1951-
auto readItem = readRequestsNext.firstObject;
1952-
[readRequestsNext removeObjectAtIndex:0];
1953-
[readRequestsCurrent addObject:readItem];
1954-
MTR_LOG("Batching read attribute work item [%llu]: added %@ (now %lu requests total) [0x%016llX:%@:0x%llx:0x%llx]",
1955-
workItemID, readItem, static_cast<unsigned long>(readRequestsCurrent.count), nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue);
1956-
outcome = MTRBatchedPartially;
1957-
}
1958-
NSCAssert(readRequestsNext.count == 0, @"should have batched everything or returned early");
1959-
return MTRBatchedFully;
1960-
}];
1961-
[workItem setDuplicateTypeID:MTRDeviceWorkItemDuplicateReadTypeID handler:^(id opaqueItemData, BOOL * isDuplicate, BOOL * stop) {
1962-
mtr_hide(self); // don't capture self accidentally
1963-
for (NSArray * readItem in readRequests) {
1964-
if ([readItem isEqual:opaqueItemData]) {
1965-
MTR_LOG("Read attribute work item [%llu] report duplicate %@ [0x%016llX:%@:0x%llx:0x%llx]", workItemID, readItem, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue);
1966-
*isDuplicate = YES;
1967-
*stop = YES;
1968-
return;
1969-
}
1970-
}
1971-
*stop = NO;
1972-
}];
1973-
[workItem setReadyHandler:^(MTRDevice * self, NSInteger retryCount, MTRAsyncWorkCompletionBlock completion) {
1974-
// Sanity check
1975-
if (readRequests.count == 0) {
1976-
MTR_LOG_ERROR("Read attribute work item [%llu] contained no read requests", workItemID);
1977-
completion(MTRAsyncWorkComplete);
1978-
return;
1979-
}
1980-
1981-
// Build the attribute paths from the read requests
1982-
NSMutableArray<MTRAttributeRequestPath *> * attributePaths = [NSMutableArray array];
1983-
for (NSArray * readItem in readRequests) {
1984-
NSAssert(readItem.count == 2, @"invalid read attribute item");
1985-
[attributePaths addObject:readItem[MTRDeviceReadRequestFieldPathIndex]];
1986-
}
1987-
// If param is the NSNull stand-in, then just use nil
1988-
id readParamObject = readRequests[0][MTRDeviceReadRequestFieldParamsIndex];
1989-
MTRReadParams * readParams = (![readParamObject isEqual:[NSNull null]]) ? readParamObject : nil;
1990-
1991-
MTRBaseDevice * baseDevice = [self newBaseDevice];
1992-
[baseDevice
1993-
readAttributePaths:attributePaths
1994-
eventPaths:nil
1995-
params:readParams
1996-
includeDataVersion:YES
1997-
queue:self.queue
1998-
completion:^(NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error) {
1999-
if (values) {
2000-
// Since the format is the same data-value dictionary, this looks like an
2001-
// attribute report
2002-
MTR_LOG("Read attribute work item [%llu] result: %@ [0x%016llX:%@:0x%llX:0x%llX]", workItemID, values, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue);
2003-
[self _handleAttributeReport:values fromSubscription:NO];
2004-
}
2005-
2006-
// TODO: better retry logic
2007-
if (error && (retryCount < 2)) {
2008-
MTR_LOG_ERROR("Read attribute work item [%llu] failed (will retry): %@ [0x%016llX:%@:0x%llx:0x%llx]", workItemID, error, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue);
2009-
completion(MTRAsyncWorkNeedsRetry);
2010-
} else {
2011-
if (error) {
2012-
MTR_LOG("Read attribute work item [%llu] failed (giving up): %@ [0x%016llX:%@:0x%llx:0x%llx]", workItemID, error, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue);
2013-
}
2014-
completion(MTRAsyncWorkComplete);
2015-
}
2016-
}];
2017-
}];
2018-
[_asyncWorkQueue enqueueWorkItem:workItem descriptionWithFormat:@"read %@ 0x%llx 0x%llx", endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue];
2019-
} else {
2020-
[self _readThroughSkipped];
2021-
}
2022-
2023-
return attributeValueToReturn;
1834+
#define ErrorStr "MTRDevice readAttributeWithEndpointID:clusterID:attributeID:params: must be handled by subclasses"
1835+
MTR_LOG_ERROR(ErrorStr);
1836+
#ifdef DEBUG
1837+
NSAssert(NO, @ErrorStr);
1838+
#endif // DEBUG
1839+
return nil;
20241840
}
20251841

20261842
- (void)writeAttributeWithEndpointID:(NSNumber *)endpointID
@@ -2456,37 +2272,6 @@ - (void)_performScheduledExpirationCheck
24562272
[self _checkExpiredExpectedValues];
24572273
}
24582274

2459-
// Get attribute value dictionary for an attribute path from the right cache
2460-
- (NSDictionary<NSString *, id> *)_attributeValueDictionaryForAttributePath:(MTRAttributePath *)attributePath
2461-
{
2462-
std::lock_guard lock(_lock);
2463-
2464-
// First check expected value cache
2465-
NSArray * expectedValue = _expectedValueCache[attributePath];
2466-
if (expectedValue) {
2467-
NSDate * now = [NSDate date];
2468-
if ([now compare:expectedValue[MTRDeviceExpectedValueFieldExpirationTimeIndex]] == NSOrderedDescending) {
2469-
// expired - purge and fall through
2470-
_expectedValueCache[attributePath] = nil;
2471-
} else {
2472-
// not yet expired - return result
2473-
return expectedValue[MTRDeviceExpectedValueFieldValueIndex];
2474-
}
2475-
}
2476-
2477-
// Then check read cache
2478-
NSDictionary<NSString *, id> * cachedAttributeValue = [self _cachedAttributeValueForPath:attributePath];
2479-
if (cachedAttributeValue) {
2480-
return cachedAttributeValue;
2481-
} else {
2482-
// TODO: when not found in cache, generated default values should be used
2483-
MTR_LOG("%@ _attributeValueDictionaryForAttributePath: could not find cached attribute values for attribute %@", self,
2484-
attributePath);
2485-
}
2486-
2487-
return nil;
2488-
}
2489-
24902275
- (BOOL)_attributeDataValue:(NSDictionary *)one isEqualToDataValue:(NSDictionary *)theOther
24912276
{
24922277
// Sanity check for nil cases

0 commit comments

Comments
 (0)