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;