Updating XPC interfaces to pass along context, and fixing some retries (#35441)
* Adding diffs
* Restyled by clang-format
* Cleaning up
* Restyled by whitespace
* Restyled by clang-format
---------
Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/src/darwin/Framework/CHIP/MTRDefines_Internal.h b/src/darwin/Framework/CHIP/MTRDefines_Internal.h
index 7894f31..38de3a9 100644
--- a/src/darwin/Framework/CHIP/MTRDefines_Internal.h
+++ b/src/darwin/Framework/CHIP/MTRDefines_Internal.h
@@ -111,3 +111,56 @@
\
return outValue; \
}
+
+#ifndef MTR_OPTIONAL_ATTRIBUTE
+#if __has_feature(objc_arc)
+#define MTR_OPTIONAL_ATTRIBUTE(ATTRIBUTE, VALUE, DICTIONARY) \
+ { \
+ id valueToAdd = VALUE; \
+ if (valueToAdd != nil) { \
+ CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) (__bridge const void *) ATTRIBUTE, (const void *) valueToAdd); \
+ } \
+ }
+#else
+#define MTR_OPTIONAL_ATTRIBUTE(ATTRIBUTE, VALUE, DICTIONARY) \
+ { \
+ id valueToAdd = VALUE; \
+ if (valueToAdd != nil) { \
+ CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) (const void *) ATTRIBUTE, (const void *) valueToAdd); \
+ } \
+ }
+#endif
+#endif
+
+#ifndef MTR_OPTIONAL_COLLECTION_ATTRIBUTE
+#define MTR_OPTIONAL_COLLECTION_ATTRIBUTE(ATTRIBUTE, COLLECTION, DICTIONARY) \
+ if ([COLLECTION count] > 0) { \
+ CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) ATTRIBUTE, (const void *) COLLECTION); \
+ }
+#endif
+
+#ifndef MTR_OPTIONAL_NUMBER_ATTRIBUTE
+#define MTR_OPTIONAL_NUMBER_ATTRIBUTE(ATTRIBUTE, NUMBER, DICTIONARY) \
+ if ([NUMBER intValue] != 0) { \
+ CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) ATTRIBUTE, (const void *) NUMBER); \
+ }
+#endif
+
+#ifndef MTR_REMOVE_ATTRIBUTE
+#define MTR_REMOVE_ATTRIBUTE(ATTRIBUTE, DICTIONARY) \
+ if (ATTRIBUTE != nil && DICTIONARY) { \
+ CFDictionaryRemoveValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) ATTRIBUTE); \
+ }
+#endif
+
+#ifndef MTR_REQUIRED_ATTRIBUTE
+#define MTR_REQUIRED_ATTRIBUTE(ATTRIBUTE, VALUE, DICTIONARY) \
+ { \
+ id valueToAdd = VALUE; \
+ if (valueToAdd != nil) { \
+ CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) ATTRIBUTE, (const void *) valueToAdd); \
+ } else { \
+ MTR_LOG_ERROR("Warning, missing %@ to add to %s", ATTRIBUTE, #DICTIONARY); \
+ } \
+ }
+#endif
diff --git a/src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm b/src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm
index 87ce556..1cd02e2 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm
+++ b/src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm
@@ -34,7 +34,13 @@
static NSSet * GetXPCAllowedClasses()
{
static NSSet * const sXPCAllowedClasses = [NSSet setWithArray:@[
- [NSString class], [NSNumber class], [NSData class], [NSArray class], [NSDictionary class], [NSError class]
+ [NSString class],
+ [NSNumber class],
+ [NSData class],
+ [NSArray class],
+ [NSDictionary class],
+ [NSError class],
+ [NSDate class],
]];
return sXPCAllowedClasses;
}
diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.h b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.h
index c891c10..87218b1 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.h
+++ b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.h
@@ -27,7 +27,7 @@
- (id)initWithUniqueIdentifier:(NSUUID *)UUID machServiceName:(NSString *)machServiceName options:(NSXPCConnectionOptions)options
#endif
- @property(atomic, retain, readwrite)NSXPCConnection * xpcConnection;
+ @property(nullable, atomic, retain, readwrite)NSXPCConnection * xpcConnection;
@end
diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm
index 1bf0888..c58514e 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm
+++ b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm
@@ -19,6 +19,7 @@
#import "MTRDefines_Internal.h"
#import "MTRDeviceController_Internal.h"
#import "MTRDevice_XPC.h"
+#import "MTRDevice_XPC_Internal.h"
#import "MTRLogging_Internal.h"
#import "MTRXPCClientProtocol.h"
#import "MTRXPCServerProtocol.h"
@@ -33,7 +34,10 @@
@interface MTRDeviceController_XPC ()
-@property (nonatomic, retain, readwrite) NSUUID * uniqueIdentifier;
+@property (nonatomic, readwrite, retain) NSUUID * uniqueIdentifier;
+@property (nonnull, atomic, readwrite, retain) MTRXPCDeviceControllerParameters * xpcParameters;
+@property (atomic, readwrite, assign) NSTimeInterval xpcRetryTimeInterval;
+@property (atomic, readwrite, assign) BOOL xpcConnectedOrConnecting;
@end
@@ -48,7 +52,15 @@
NSXPCInterface * interface = [NSXPCInterface interfaceWithProtocol:@protocol(MTRXPCServerProtocol)];
NSSet * allowedClasses = [NSSet setWithArray:@[
- [NSString class], [NSNumber class], [NSData class], [NSArray class], [NSDictionary class], [NSError class], [MTRCommandPath class], [MTRAttributePath class]
+ [NSString class],
+ [NSNumber class],
+ [NSData class],
+ [NSArray class],
+ [NSDictionary class],
+ [NSError class],
+ [MTRCommandPath class],
+ [MTRAttributePath class],
+ [NSDate class],
]];
[interface setClasses:allowedClasses
@@ -62,7 +74,14 @@
{
NSXPCInterface * interface = [NSXPCInterface interfaceWithProtocol:@protocol(MTRXPCClientProtocol)];
NSSet * allowedClasses = [NSSet setWithArray:@[
- [NSString class], [NSNumber class], [NSData class], [NSArray class], [NSDictionary class], [NSError class], [MTRAttributePath class]
+ [NSString class],
+ [NSNumber class],
+ [NSData class],
+ [NSArray class],
+ [NSDictionary class],
+ [NSError class],
+ [MTRAttributePath class],
+ [NSDate class],
]];
[interface setClasses:allowedClasses
forSelector:@selector(device:receivedAttributeReport:)
@@ -83,6 +102,114 @@
return [self.uniqueIdentifier UUIDString];
}
+- (void)_startXPCConnectionRetry
+{
+ if (!self.xpcConnectedOrConnecting) {
+ MTR_LOG("%@: XPC Connection retry - Starting retry for XPC Connection", self);
+ self.xpcRetryTimeInterval = 0.5;
+ mtr_weakify(self);
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (self.xpcRetryTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ mtr_strongify(self);
+ [self _xpcConnectionRetry];
+ });
+ } else {
+ MTR_LOG("%@: XPC Connection retry - Not starting retry for XPC Connection, already trying", self);
+ }
+}
+
+- (void)_xpcConnectionRetry
+{
+ MTR_LOG("%@: XPC Connection retry - timer hit", self);
+ if (!self.xpcConnectedOrConnecting) {
+ if (![self _setupXPCConnection]) {
+#if 0 // FIXME: Not sure why this retry is not working, but I will fix this later
+ MTR_LOG("%@: XPC Connection retry - Scheduling another retry", self);
+ self.xpcRetryTimeInterval = self.xpcRetryTimeInterval >= 1 ? self.xpcRetryTimeInterval * 2 : 1;
+ self.xpcRetryTimeInterval = MIN(60.0, self.xpcRetryTimeInterval);
+ mtr_weakify(self);
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.xpcRetryTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ mtr_strongify(self);
+ [self _xpcConnectionRetry];
+ });
+#else
+ MTR_LOG("%@: XPC Connection failed retry - bailing", self);
+#endif
+ } else {
+ MTR_LOG("%@: XPC Connection retry - connection attempt successful", self);
+ }
+ } else {
+ MTR_LOG("%@: XPC Connection retry - Mid retry, or connected, stopping retry timer", self);
+ }
+}
+
+- (BOOL)_setupXPCConnection
+{
+ self.xpcConnection = self.xpcParameters.xpcConnectionBlock();
+
+ MTR_LOG("%@ Set up XPC Connection: %@", self, self.xpcConnection);
+ if (self.xpcConnection) {
+ mtr_weakify(self);
+ self.xpcConnection.remoteObjectInterface = [self _interfaceForServerProtocol];
+
+ self.xpcConnection.exportedInterface = [self _interfaceForClientProtocol];
+ self.xpcConnection.exportedObject = self;
+
+ self.xpcConnection.interruptionHandler = ^{
+ mtr_strongify(self);
+ MTR_LOG_ERROR("XPC Connection for device controller interrupted: %@", self.xpcParameters.uniqueIdentifier);
+ self.xpcConnectedOrConnecting = NO;
+ self.xpcConnection = nil;
+ [self _startXPCConnectionRetry];
+ };
+
+ self.xpcConnection.invalidationHandler = ^{
+ mtr_strongify(self);
+ MTR_LOG_ERROR("XPC Connection for device controller invalidated: %@", self.xpcParameters.uniqueIdentifier);
+ self.xpcConnectedOrConnecting = NO;
+ self.xpcConnection = nil;
+ [self _startXPCConnectionRetry];
+ };
+
+ MTR_LOG("%@ Activating new XPC connection", self);
+ [self.xpcConnection activate];
+
+ [[self.xpcConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
+ MTR_LOG_ERROR("Checkin error: %@", error);
+ }] deviceController:self.uniqueIdentifier checkInWithContext:[NSDictionary dictionary]];
+
+ // FIXME: Trying to kick all the MTRDevices attached to this controller to re-establish connections
+ // This state needs to be stored properly and re-established at connnection time
+
+ MTR_LOG("%@ Starting existing NodeID Registration", self);
+ for (NSNumber * nodeID in [self.nodeIDToDeviceMap keyEnumerator]) {
+ MTR_LOG("%@ => Registering nodeID: %@", self, nodeID);
+ mtr_weakify(self);
+
+ [[self.xpcConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
+ mtr_strongify(self);
+ MTR_LOG_ERROR("%@ Registration error for device nodeID: %@ : %@", self, nodeID, error);
+ }] deviceController:self.uniqueIdentifier registerNodeID:nodeID];
+ }
+
+ __block BOOL barrierComplete = NO;
+
+ [self.xpcConnection scheduleSendBarrierBlock:^{
+ barrierComplete = YES;
+ MTR_LOG("%@: Barrier complete: %d", self, barrierComplete);
+ }];
+
+ MTR_LOG("%@ Done existing NodeID Registration, barrierComplete: %d", self, barrierComplete);
+ self.xpcConnectedOrConnecting = barrierComplete;
+ } else {
+ MTR_LOG_ERROR("%@ Failed to set up XPC Connection", self);
+ self.xpcConnectedOrConnecting = NO;
+ }
+
+ return (self.xpcConnectedOrConnecting);
+}
+
- (nullable instancetype)initWithParameters:(MTRDeviceControllerAbstractParameters *)parameters
error:(NSError * __autoreleasing *)error
{
@@ -110,30 +237,12 @@
return nil;
}
- self.xpcConnection = connectionBlock();
- self.uniqueIdentifier = UUID;
+ self.xpcParameters = xpcParameters;
self.chipWorkQueue = dispatch_queue_create("MTRDeviceController_XPC_queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
self.nodeIDToDeviceMap = [NSMapTable strongToWeakObjectsMapTable];
+ self.uniqueIdentifier = UUID;
- MTR_LOG("Set up XPC Connection: %@", self.xpcConnection);
- if (self.xpcConnection) {
- self.xpcConnection.remoteObjectInterface = [self _interfaceForServerProtocol];
-
- self.xpcConnection.exportedInterface = [self _interfaceForClientProtocol];
- self.xpcConnection.exportedObject = self;
-
- self.xpcConnection.interruptionHandler = ^{
- MTR_LOG_ERROR("XPC Connection for device controller interrupted: %@", UUID);
- };
-
- self.xpcConnection.invalidationHandler = ^{
- MTR_LOG_ERROR("XPC Connection for device controller invalidated: %@", UUID);
- };
-
- MTR_LOG("Activating new XPC connection");
- [self.xpcConnection activate];
- } else {
- MTR_LOG_ERROR("Failed to set up XPC Connection");
+ if (![self _setupXPCConnection]) {
return nil;
}
}
@@ -159,7 +268,7 @@
self.xpcConnection.exportedObject = self;
MTR_LOG("%s: resuming new XPC connection");
- [self.xpcConnection resume];
+ [self.xpcConnection activate];
} else {
MTR_LOG_ERROR("Failed to set up XPC Connection");
return nil;
@@ -177,13 +286,7 @@
os_unfair_lock_assert_owner(self.deviceMapLock);
MTRDevice * deviceToReturn = [[MTRDevice_XPC alloc] initWithNodeID:nodeID controller:self];
- // If we're not running, don't add the device to our map. That would
- // create a cycle that nothing would break. Just return the device,
- // which will be in exactly the state it would be in if it were created
- // while we were running and then we got shut down.
- if ([self isRunning]) {
- [self.nodeIDToDeviceMap setObject:deviceToReturn forKey:nodeID];
- }
+ [self.nodeIDToDeviceMap setObject:deviceToReturn forKey:nodeID];
MTR_LOG("%s: returning XPC device for node id %@", __PRETTY_FUNCTION__, nodeID);
return deviceToReturn;
}
@@ -255,6 +358,14 @@
[device deviceConfigurationChanged:nodeID];
}
+- (oneway void)device:(NSNumber *)nodeID internalStateUpdated:(NSDictionary *)dictionary
+{
+ MTRDevice_XPC * device = (MTRDevice_XPC *) [self deviceForNodeID:nodeID];
+ MTR_LOG("Received internalStateUpdated: %@ found device: %@", nodeID, device);
+
+ [device device:nodeID internalStateUpdated:dictionary];
+}
+
#pragma mark - MTRDeviceController Protocol Client
// Not Supported via XPC
diff --git a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm
index 70824dd..f554d14 100644
--- a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm
+++ b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm
@@ -254,8 +254,6 @@
@property (nonatomic) ReadClient * currentReadClient;
@property (nonatomic) SubscriptionCallback * currentSubscriptionCallback; // valid when and only when currentReadClient is valid
-@property (nonatomic, weak) id<MTRXPCClientProtocol_MTRDevice> privateInternalStateDelegate;
-
@end
// Declaring selector so compiler won't complain about testing and calling it in _handleReportEnd
@@ -468,31 +466,28 @@
- (NSDictionary *)_internalProperties
{
- id vidOrUnknown, pidOrUnknown;
+ NSMutableDictionary * properties = [NSMutableDictionary dictionary];
+ std::lock_guard lock(_descriptionLock);
- {
- std::lock_guard lock(_descriptionLock);
+ MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyKeyVendorID, _vid, properties);
+ MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyKeyProductID, _pid, properties);
+ MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyNetworkFeatures, _allNetworkFeatures, properties);
+ MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyDeviceState, [NSNumber numberWithUnsignedInteger:_internalDeviceStateForDescription], properties);
+ MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionAttemptWait, [NSNumber numberWithUnsignedInt:_lastSubscriptionAttemptWaitForDescription], properties);
+ MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyMostRecentReportTime, _mostRecentReportTimeForDescription, properties);
+ MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionFailureTime, _lastSubscriptionFailureTimeForDescription, properties);
- vidOrUnknown = _vid ?: @"Unknown";
- pidOrUnknown = _pid ?: @"Unknown";
- // id networkFeatures = _allNetworkFeatures;
- // id internalDeviceState = _internalDeviceStateForDescription;
- // id lastSubscriptionAttemptWait = _lastSubscriptionAttemptWaitForDescription;
- // id mostRecentReportTime = _mostRecentReportTimeForDescription;
- // id lastSubscriptionFailureTime = _lastSubscriptionFailureTimeForDescription;
- }
-
- return @{
- kMTRDeviceInternalPropertyKeyVendorID : vidOrUnknown,
- kMTRDeviceInternalPropertyKeyProductID : pidOrUnknown,
- };
+ return properties;
}
-- (void)_notifyPrivateInternalPropertiesDelegateOfChanges
+- (void)_notifyDelegateOfPrivateInternalPropertiesChanges
{
- if ([self.privateInternalStateDelegate respondsToSelector:@selector(device:internalStateUpdated:)]) {
- [self.privateInternalStateDelegate device:self.nodeID internalStateUpdated:[self _internalProperties]];
- }
+ os_unfair_lock_assert_owner(&self->_lock);
+ [self _callDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
+ if ([delegate respondsToSelector:@selector(device:internalStateUpdated:)]) {
+ [delegate performSelector:@selector(device:internalStateUpdated:) withObject:self withObject:[self _internalProperties]];
+ }
+ }];
}
#pragma mark - Time Synchronization
@@ -760,6 +755,8 @@
[self _setupSubscriptionWithReason:@"delegate is set and subscription is needed"];
}
}
+
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
}
- (void)invalidate
@@ -983,7 +980,7 @@
}];
/* END DRAGONS */
- [self _notifyPrivateInternalPropertiesDelegateOfChanges];
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
}
}
@@ -1185,7 +1182,7 @@
std::lock_guard lock(_descriptionLock);
_lastSubscriptionFailureTimeForDescription = _lastSubscriptionFailureTime;
}
- [self _notifyPrivateInternalPropertiesDelegateOfChanges];
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
deviceUsesThread = [self _deviceUsesThread];
// If a previous resubscription failed, remove the item from the subscription pool.
@@ -1236,7 +1233,7 @@
_lastSubscriptionAttemptWaitForDescription = lastSubscriptionAttemptWait;
}
- [self _notifyPrivateInternalPropertiesDelegateOfChanges];
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
}
- (void)_doHandleSubscriptionReset:(NSNumber * _Nullable)retryDelay
@@ -1252,7 +1249,7 @@
std::lock_guard lock(_descriptionLock);
_lastSubscriptionFailureTimeForDescription = _lastSubscriptionFailureTime;
}
- [self _notifyPrivateInternalPropertiesDelegateOfChanges];
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
// if there is no delegate then also do not retry
if (![self _delegateExists]) {
@@ -1310,6 +1307,7 @@
// For non-Thread-enabled devices, just call the resubscription block after the specified time
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, resubscriptionDelayNs), self.queue, resubscriptionBlock);
}
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
}
- (void)_reattemptSubscriptionNowIfNeededWithReason:(NSString *)reason
@@ -1507,7 +1505,7 @@
std::lock_guard lock(_descriptionLock);
_mostRecentReportTimeForDescription = [mostRecentReportTimes lastObject];
}
- [self _notifyPrivateInternalPropertiesDelegateOfChanges];
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
}
#endif
@@ -1566,7 +1564,6 @@
std::lock_guard lock(_descriptionLock);
_mostRecentReportTimeForDescription = [_mostRecentReportTimes lastObject];
}
- [self _notifyPrivateInternalPropertiesDelegateOfChanges];
// Calculate running average and update multiplier - need at least 2 items to calculate intervals
if (_mostRecentReportTimes.count > 2) {
@@ -1613,6 +1610,8 @@
}
}
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
+
// Do not schedule persistence if device is reporting excessively
if ([self _deviceIsReportingExcessively]) {
return;
@@ -1637,7 +1636,6 @@
std::lock_guard lock(_descriptionLock);
_mostRecentReportTimeForDescription = nil;
}
- [self _notifyPrivateInternalPropertiesDelegateOfChanges];
_deviceReportingExcessivelyStartTime = nil;
_reportToPersistenceDelayCurrentMultiplier = 1;
@@ -1646,6 +1644,8 @@
if ([self _dataStoreExists]) {
[self _persistClusterData];
}
+
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
}
- (void)setStorageBehaviorConfiguration:(MTRDeviceStorageBehaviorConfiguration *)storageBehaviorConfiguration
@@ -1699,6 +1699,8 @@
}
}];
#endif
+
+ [self _notifyDelegateOfPrivateInternalPropertiesChanges];
}
- (BOOL)_interestedPaths:(NSArray * _Nullable)interestedPaths includesAttributePath:(MTRAttributePath *)attributePath
diff --git a/src/darwin/Framework/CHIP/MTRDevice_Internal.h b/src/darwin/Framework/CHIP/MTRDevice_Internal.h
index c3b6b60..baa3439 100644
--- a/src/darwin/Framework/CHIP/MTRDevice_Internal.h
+++ b/src/darwin/Framework/CHIP/MTRDevice_Internal.h
@@ -225,6 +225,10 @@
// Concrete to XPC internal state property dictionary keys
static NSString * const kMTRDeviceInternalPropertyKeyVendorID = @"MTRDeviceInternalStateKeyVendorID";
static NSString * const kMTRDeviceInternalPropertyKeyProductID = @"MTRDeviceInternalStateKeyProductID";
-// TODO: more internal properties
+static NSString * const kMTRDeviceInternalPropertyNetworkFeatures = @"MTRDeviceInternalPropertyNetworkFeatures";
+static NSString * const kMTRDeviceInternalPropertyDeviceState = @"MTRDeviceInternalPropertyDeviceState";
+static NSString * const kMTRDeviceInternalPropertyLastSubscriptionAttemptWait = @"kMTRDeviceInternalPropertyLastSubscriptionAttemptWait";
+static NSString * const kMTRDeviceInternalPropertyMostRecentReportTime = @"MTRDeviceInternalPropertyMostRecentReportTime";
+static NSString * const kMTRDeviceInternalPropertyLastSubscriptionFailureTime = @"MTRDeviceInternalPropertyLastSubscriptionFailureTime";
NS_ASSUME_NONNULL_END
diff --git a/src/darwin/Framework/CHIP/MTRDevice_XPC.mm b/src/darwin/Framework/CHIP/MTRDevice_XPC.mm
index 7267eb3..5279933 100644
--- a/src/darwin/Framework/CHIP/MTRDevice_XPC.mm
+++ b/src/darwin/Framework/CHIP/MTRDevice_XPC.mm
@@ -103,32 +103,35 @@
- (NSString *)description
{
- // TODO: Figure out whether, and if so how, to log: VID, PID, WiFi, Thread,
- // internalDeviceState (do we even have such a thing here?), last
- // subscription attempt wait (does that apply to us?) queued work (do we
- // have any?), last report, last subscription failure (does that apply to us?).
- return [NSString
- stringWithFormat:@"<%@: %p, node: %016llX-%016llX (%llu), VID: %@, PID: %@, controller: %@>", NSStringFromClass(self.class), self, _deviceController.compressedFabricID.unsignedLongLongValue, _nodeID.unsignedLongLongValue, _nodeID.unsignedLongLongValue, [self _vid], [self _pid], _deviceController.uniqueIdentifier];
-}
+ NSString * wifi;
+ NSString * thread;
+ NSNumber * networkFeatures = [self._internalState objectForKey:kMTRDeviceInternalPropertyNetworkFeatures];
-- (nullable NSNumber *)_internalStateNumberOrNilForKey:(NSString *)key
-{
- if ([_internalState[key] isKindOfClass:NSNumber.class]) {
- NSNumber * number = _internalState[key];
- return number;
+ if (networkFeatures == nil) {
+ wifi = @"NO";
+ thread = @"NO";
} else {
- return nil;
+ wifi = YES_NO(networkFeatures.unsignedLongLongValue & MTRNetworkCommissioningFeatureWiFiNetworkInterface);
+ thread = YES_NO(networkFeatures.unsignedLongLongValue & MTRNetworkCommissioningFeatureThreadNetworkInterface);
}
-}
-- (nullable NSNumber *)_vid
-{
- return [self _internalStateNumberOrNilForKey:kMTRDeviceInternalPropertyKeyVendorID];
-}
+ // TODO: Add these to the description
+ // MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyDeviceState, _internalDeviceStateForDescription, properties);
+ // MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionAttemptWait, _lastSubscriptionAttemptWaitForDescription, properties);
+ // MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyMostRecentReportTime, _mostRecentReportTimeForDescription, properties);
+ // MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionFailureTime, _lastSubscriptionFailureTimeForDescription, properties);
-- (nullable NSNumber *)_pid
-{
- return [self _internalStateNumberOrNilForKey:kMTRDeviceInternalPropertyKeyProductID];
+ return [NSString
+ stringWithFormat:@"<%@: %p, node: %016llX-%016llX (%llu), VID: %@, PID: %@, WiFi: %@, Thread: %@, controller: %@>",
+ NSStringFromClass(self.class), self,
+ _deviceController.compressedFabricID.unsignedLongLongValue,
+ _nodeID.unsignedLongLongValue,
+ _nodeID.unsignedLongLongValue,
+ [self._internalState objectForKey:kMTRDeviceInternalPropertyKeyVendorID],
+ [self._internalState objectForKey:kMTRDeviceInternalPropertyKeyProductID],
+ wifi,
+ thread,
+ _deviceController.uniqueIdentifier];
}
#pragma mark - Client Callbacks (MTRDeviceDelegate)
@@ -187,6 +190,12 @@
}];
}
+- (oneway void)device:(NSNumber *)nodeID internalStateUpdated:(NSDictionary *)dictionary
+{
+ [self _setInternalState:dictionary];
+ MTR_LOG("%@ internal state updated", self);
+}
+
#pragma mark - Remote Commands
MTR_DEVICE_SIMPLE_REMOTE_XPC_GETTER(state, MTRDeviceState, MTRDeviceStateUnknown, getStateWithReply)
diff --git a/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCClientProtocol.h b/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCClientProtocol.h
index b26b6d8..cfa59db 100644
--- a/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCClientProtocol.h
+++ b/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCClientProtocol.h
@@ -27,9 +27,6 @@
- (oneway void)deviceBecameActive:(NSNumber *)nodeID;
- (oneway void)deviceCachePrimed:(NSNumber *)nodeID;
- (oneway void)deviceConfigurationChanged:(NSNumber *)nodeID;
-
-@optional
-// temporarily optional to avoid lockstep needs
- (oneway void)device:(NSNumber *)nodeID internalStateUpdated:(NSDictionary *)dictionary;
@end
diff --git a/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h b/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h
index 1ebdea5..52a5d22 100644
--- a/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h
+++ b/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h
@@ -70,9 +70,6 @@
//- (oneway void)deviceController:(NSUUID *)controller removeServerEndpoint:(MTRServerEndpoint *)endpoint;
- (oneway void)deviceController:(NSUUID *)controller shutdownDeviceController:(NSUUID *)controller;
-
-@optional
-// register / unregister temporarily optional to avoid lockstep needs
- (oneway void)deviceController:(NSUUID *)controller registerNodeID:(NSNumber *)nodeID;
- (oneway void)deviceController:(NSUUID *)controller unregisterNodeID:(NSNumber *)nodeID;