From bfb416b3467fb4cf4f534930556eb8bfb3bece1d Mon Sep 17 00:00:00 2001 From: Jeff Tung <100387939+jtung-apple@users.noreply.github.com> Date: Mon, 7 Oct 2024 23:40:46 -0700 Subject: [PATCH] [Darwin] Internal state plumbing for the _XPC classes --- .../Framework/CHIP/MTRDeviceController_XPC.mm | 33 ++++++++-- .../Framework/CHIP/MTRDevice_Concrete.mm | 66 +++++++++++++++---- .../Framework/CHIP/MTRDevice_Internal.h | 6 +- src/darwin/Framework/CHIP/MTRDevice_XPC.mm | 61 ++++++++++++++--- .../CHIP/XPC Protocol/MTRXPCServerProtocol.h | 9 +++ 5 files changed, 148 insertions(+), 27 deletions(-) diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm index 2945334b3bd1da..4ee1d110991fb4 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm @@ -44,6 +44,8 @@ @interface MTRDeviceController_XPC () @implementation MTRDeviceController_XPC +@synthesize controllerNodeID = _controllerNodeID; + + (NSMutableSet *)_allowedClasses { static NSArray * sBaseAllowedClasses = @[ @@ -95,6 +97,20 @@ - (NSXPCInterface *)_interfaceForServerProtocol argumentIndex:0 ofReply:YES]; + // registerNodeID: returns dictionary containing standard nsstring / nsnumber / nsdate objects. + allowedClasses = [MTRDeviceController_XPC _allowedClasses]; + [interface setClasses:allowedClasses + forSelector:@selector(deviceController:registerNodeID:reply:) + argumentIndex:0 + ofReply:YES]; + + // checkInWithContext: returns dictionary containing standard nsstring / nsnumber objects. + allowedClasses = [MTRDeviceController_XPC _allowedClasses]; + [interface setClasses:allowedClasses + forSelector:@selector(deviceController:checkInWithContext:reply:) + argumentIndex:0 + ofReply:YES]; + return interface; } @@ -202,9 +218,12 @@ - (BOOL)_setupXPCConnection MTR_LOG("%@ Activating new XPC connection", self); [self.xpcConnection activate]; - [[self.xpcConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + [[self.xpcConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { MTR_LOG_ERROR("Checkin error: %@", error); - }] deviceController:self.uniqueIdentifier checkInWithContext:[NSDictionary dictionary]]; + }] deviceController:self.uniqueIdentifier checkInWithContext:@{} reply:^(NSDictionary * _Nonnull controllerInfo) { + // Get the controller nodeID + ; + }]; // 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 @@ -214,10 +233,14 @@ - (BOOL)_setupXPCConnection MTR_LOG("%@ => Registering nodeID: %@", self, nodeID); mtr_weakify(self); - [[self.xpcConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + [[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]; + }] deviceController:self.uniqueIdentifier registerNodeID:nodeID reply:^(NSDictionary * _Nonnull internalState) { + mtr_strongify(self); + MTRDevice_XPC * device = (MTRDevice_XPC *) [self deviceForNodeID:nodeID]; + [device device:nodeID internalStateUpdated:internalState]; + }]; } MTR_LOG("%@ Done existing NodeID Registration", self); @@ -320,7 +343,7 @@ - (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(N #pragma mark - XPC Action Overrides MTR_DEVICECONTROLLER_SIMPLE_REMOTE_XPC_GETTER(isRunning, BOOL, NO, getIsRunningWithReply) -MTR_DEVICECONTROLLER_SIMPLE_REMOTE_XPC_GETTER(controllerNodeID, NSNumber *, nil, controllerNodeIDWithReply) +//MTR_DEVICECONTROLLER_SIMPLE_REMOTE_XPC_GETTER(controllerNodeID, NSNumber *, nil, controllerNodeIDWithReply) // Not Supported via XPC // - (oneway void)deviceController:(NSUUID *)controller setupCommissioningSessionWithPayload:(MTRSetupPayload *)payload newNodeID:(NSNumber *)newNodeID withReply:(void(^)(BOOL success, NSError * _Nullable error))reply; diff --git a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm index 5d6e47c8d9d781..e185531670e29a 100644 --- a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm +++ b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm @@ -350,6 +350,14 @@ @implementation MTRDevice_Concrete { NSDate * _Nullable _mostRecentReportTimeForDescription; // Copy of _lastSubscriptionFailureTime that is safe to use in description. NSDate * _Nullable _lastSubscriptionFailureTimeForDescription; + // Copy of _state that is safe to use in description. + MTRDeviceState _deviceStateForDescription; + // Copy of _deviceCachePrimed that is safe to use in description. + BOOL _deviceCachePrimedForDescription; + // Copy of _estimatedStartTime that is safe to use in description. + NSDate * _Nullable _estimatedStartTimeForDescription; + // Copy of _estimatedSubscriptionLatency that is safe to use in description. + NSNumber * _Nullable _estimatedSubscriptionLatencyForDescription; } // synthesize superclass property readwrite accessors @@ -473,11 +481,16 @@ - (NSDictionary *)_internalProperties 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(kMTRDeviceInternalPropertyDeviceInternalState, [NSNumber numberWithUnsignedInteger:_internalDeviceStateForDescription], properties); MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionAttemptWait, [NSNumber numberWithUnsignedInt:_lastSubscriptionAttemptWaitForDescription], properties); MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyMostRecentReportTime, _mostRecentReportTimeForDescription, properties); MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionFailureTime, _lastSubscriptionFailureTimeForDescription, properties); + MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyDeviceState, [NSNumber numberWithUnsignedInteger:_deviceStateForDescription], properties); + MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyDeviceCachePrimed, @(_deviceCachePrimedForDescription), properties); + MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyEstimatedStartTime, _estimatedStartTimeForDescription, properties); + MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyEstimatedSubscriptionLatency, _estimatedSubscriptionLatencyForDescription, properties); + return properties; } @@ -964,11 +977,15 @@ - (void)_changeState:(MTRDeviceState)state os_unfair_lock_assert_owner(&self->_lock); MTRDeviceState lastState = _state; _state = state; + { + std::lock_guard lock(_descriptionLock); + _deviceStateForDescription = _state; + } if (lastState != state) { if (state != MTRDeviceStateReachable) { MTR_LOG("%@ reachability state change %lu => %lu, set estimated start time to nil", self, static_cast(lastState), static_cast(state)); - _estimatedStartTime = nil; + [self _updateEstimatedStartTime:nil]; _estimatedStartTimeFromGeneralDiagnosticsUpTime = nil; } else { MTR_LOG( @@ -1025,6 +1042,15 @@ - (MTRInternalDeviceState)_getInternalState } #endif +- (void)_updateEstimatedSubscriptionLatency:(NSNumber *)estimatedSubscriptionLatency +{ + os_unfair_lock_assert_owner(&_lock); + _estimatedSubscriptionLatency = estimatedSubscriptionLatency; + + std::lock_guard lock(_descriptionLock); + _estimatedSubscriptionLatencyForDescription = estimatedSubscriptionLatency; +} + // First Time Sync happens 2 minutes after reachability (this can be changed in the future) #define MTR_DEVICE_TIME_UPDATE_INITIAL_WAIT_TIME_SEC (60 * 2) - (void)_handleSubscriptionEstablished @@ -1056,10 +1082,10 @@ - (void)_handleSubscriptionEstablished // way around. NSTimeInterval subscriptionLatency = -[initialSubscribeStart timeIntervalSinceNow]; if (_estimatedSubscriptionLatency == nil) { - _estimatedSubscriptionLatency = @(subscriptionLatency); + [self _updateEstimatedSubscriptionLatency:@(subscriptionLatency)]; } else { NSTimeInterval newSubscriptionLatencyEstimate = MTRDEVICE_SUBSCRIPTION_LATENCY_NEW_VALUE_WEIGHT * subscriptionLatency + (1 - MTRDEVICE_SUBSCRIPTION_LATENCY_NEW_VALUE_WEIGHT) * _estimatedSubscriptionLatency.doubleValue; - _estimatedSubscriptionLatency = @(newSubscriptionLatencyEstimate); + [self _updateEstimatedSubscriptionLatency:@(newSubscriptionLatencyEstimate)]; } [self _storePersistedDeviceData]; } @@ -1733,6 +1759,15 @@ - (void)setStorageBehaviorConfiguration:(MTRDeviceStorageBehaviorConfiguration * [self _resetStorageBehaviorState]; } +- (void)_updateDeviceCachePrimed:(BOOL)deviceCachePrimed +{ + os_unfair_lock_assert_owner(&_lock); + _deviceCachePrimed = deviceCachePrimed; + + std::lock_guard lock(_descriptionLock); + _deviceCachePrimedForDescription = deviceCachePrimed; +} + - (void)_handleReportEnd { MTR_LOG("%@ handling report end", self); @@ -1764,7 +1799,7 @@ - (void)_handleReportEnd if (!_deviceCachePrimed) { // This is the end of the priming sequence of data reports, so we have // all the data for the device now. - _deviceCachePrimed = YES; + [self _updateDeviceCachePrimed:YES]; [self _callDelegateDeviceCachePrimed]; } @@ -1954,6 +1989,15 @@ - (BOOL)_interestedPaths:(NSArray * _Nullable)interestedPaths includesEventPath: return filteredEvents; } +- (void)_updateEstimatedStartTime:(NSDate *)estimatedStartTime +{ + os_unfair_lock_assert_owner(&_lock); + _estimatedStartTime = estimatedStartTime; + + std::lock_guard lock(_descriptionLock); + _estimatedStartTimeForDescription = _estimatedStartTime; +} + - (void)_handleEventReport:(NSArray *> *)eventReport { std::lock_guard lock(_lock); @@ -1999,11 +2043,11 @@ - (void)_handleEventReport:(NSArray *> *)eventRepor // If UpTime was received, make use of it as mark of system start time MTR_LOG("%@ StartUp event: set estimated start time forward to %@", self, _estimatedStartTimeFromGeneralDiagnosticsUpTime); - _estimatedStartTime = _estimatedStartTimeFromGeneralDiagnosticsUpTime; + [self _updateEstimatedStartTime:_estimatedStartTimeFromGeneralDiagnosticsUpTime]; } else { // If UpTime was not received, reset estimated start time in case of reboot MTR_LOG("%@ StartUp event: set estimated start time to nil", self); - _estimatedStartTime = nil; + [self _updateEstimatedStartTime:nil]; } } @@ -2023,7 +2067,7 @@ - (void)_handleEventReport:(NSArray *> *)eventRepor NSTimeInterval eventTimeValue = eventTimeValueNumber.doubleValue; NSDate * potentialSystemStartTime = [NSDate dateWithTimeIntervalSinceNow:-eventTimeValue]; if (!_estimatedStartTime || ([potentialSystemStartTime compare:_estimatedStartTime] == NSOrderedAscending)) { - _estimatedStartTime = potentialSystemStartTime; + [self _updateEstimatedStartTime:potentialSystemStartTime]; } } @@ -3601,7 +3645,7 @@ - (NSArray *)_getAttributesToReportWithReportedValues:(NSArray %@", self, upTime, oldSystemStartTime, potentialSystemStartTime); - _estimatedStartTime = potentialSystemStartTime; + [self _updateEstimatedStartTime:potentialSystemStartTime]; } // Save estimate in the subscription resumption case, for when StartUp event uses it @@ -3693,7 +3737,7 @@ - (void)setPersistedClusterData:(NSDictionary *)data diff --git a/src/darwin/Framework/CHIP/MTRDevice_Internal.h b/src/darwin/Framework/CHIP/MTRDevice_Internal.h index 2cdcd66976099a..09a68303986756 100644 --- a/src/darwin/Framework/CHIP/MTRDevice_Internal.h +++ b/src/darwin/Framework/CHIP/MTRDevice_Internal.h @@ -220,9 +220,13 @@ static NSString * const sLastInitialSubscribeLatencyKey = @"lastInitialSubscribe static NSString * const kMTRDeviceInternalPropertyKeyVendorID = @"MTRDeviceInternalStateKeyVendorID"; static NSString * const kMTRDeviceInternalPropertyKeyProductID = @"MTRDeviceInternalStateKeyProductID"; static NSString * const kMTRDeviceInternalPropertyNetworkFeatures = @"MTRDeviceInternalPropertyNetworkFeatures"; -static NSString * const kMTRDeviceInternalPropertyDeviceState = @"MTRDeviceInternalPropertyDeviceState"; +static NSString * const kMTRDeviceInternalPropertyDeviceInternalState = @"MTRDeviceInternalPropertyDeviceInternalState"; static NSString * const kMTRDeviceInternalPropertyLastSubscriptionAttemptWait = @"kMTRDeviceInternalPropertyLastSubscriptionAttemptWait"; static NSString * const kMTRDeviceInternalPropertyMostRecentReportTime = @"MTRDeviceInternalPropertyMostRecentReportTime"; static NSString * const kMTRDeviceInternalPropertyLastSubscriptionFailureTime = @"MTRDeviceInternalPropertyLastSubscriptionFailureTime"; +static NSString * const kMTRDeviceInternalPropertyDeviceState = @"MTRDeviceInternalPropertyDeviceState"; +static NSString * const kMTRDeviceInternalPropertyDeviceCachePrimed = @"MTRDeviceInternalPropertyDeviceCachePrimed"; +static NSString * const kMTRDeviceInternalPropertyEstimatedStartTime = @"MTRDeviceInternalPropertyEstimatedStartTime"; +static NSString * const kMTRDeviceInternalPropertyEstimatedSubscriptionLatency = @"MTRDeviceInternalPropertyEstimatedSubscriptionLatency"; NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDevice_XPC.mm b/src/darwin/Framework/CHIP/MTRDevice_XPC.mm index 7806546768b4f2..fca23bd8985e6a 100644 --- a/src/darwin/Framework/CHIP/MTRDevice_XPC.mm +++ b/src/darwin/Framework/CHIP/MTRDevice_XPC.mm @@ -113,7 +113,7 @@ - (NSString *)description } // TODO: Add these to the description - // MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyDeviceState, _internalDeviceStateForDescription, properties); + // MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyDeviceInternalState, _internalDeviceStateForDescription, properties); // MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionAttemptWait, _lastSubscriptionAttemptWaitForDescription, properties); // MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyMostRecentReportTime, _mostRecentReportTimeForDescription, properties); // MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionFailureTime, _lastSubscriptionFailureTimeForDescription, properties); @@ -136,7 +136,7 @@ - (NSString *)description // required methods for MTRDeviceDelegates - (oneway void)device:(NSNumber *)nodeID stateChanged:(MTRDeviceState)state { - MTR_LOG("%s", __PRETTY_FUNCTION__); + MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__); [self _lockAndCallDelegatesWithBlock:^(id delegate) { [delegate device:self stateChanged:state]; }]; @@ -144,7 +144,7 @@ - (oneway void)device:(NSNumber *)nodeID stateChanged:(MTRDeviceState)state - (oneway void)device:(NSNumber *)nodeID receivedAttributeReport:(NSArray *> *)attributeReport { - MTR_LOG("%s", __PRETTY_FUNCTION__); + MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__); [self _lockAndCallDelegatesWithBlock:^(id delegate) { [delegate device:self receivedAttributeReport:attributeReport]; }]; @@ -152,7 +152,7 @@ - (oneway void)device:(NSNumber *)nodeID receivedAttributeReport:(NSArray *> *)eventReport { - MTR_LOG("%s", __PRETTY_FUNCTION__); + MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__); [self _lockAndCallDelegatesWithBlock:^(id delegate) { [delegate device:self receivedEventReport:eventReport]; }]; @@ -161,7 +161,7 @@ - (oneway void)device:(NSNumber *)nodeID receivedEventReport:(NSArray delegate) { if ([delegate respondsToSelector:@selector(deviceBecameActive:)]) { [delegate deviceBecameActive:self]; @@ -171,6 +171,7 @@ - (oneway void)deviceBecameActive:(NSNumber *)nodeID - (oneway void)deviceCachePrimed:(NSNumber *)nodeID { + MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__); [self _lockAndCallDelegatesWithBlock:^(id delegate) { if ([delegate respondsToSelector:@selector(deviceCachePrimed:)]) { [delegate deviceCachePrimed:self]; @@ -180,6 +181,7 @@ - (oneway void)deviceCachePrimed:(NSNumber *)nodeID - (oneway void)deviceConfigurationChanged:(NSNumber *)nodeID { + MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__); [self _lockAndCallDelegatesWithBlock:^(id delegate) { if ([delegate respondsToSelector:@selector(deviceConfigurationChanged:)]) { [delegate deviceConfigurationChanged:self]; @@ -189,16 +191,55 @@ - (oneway void)deviceConfigurationChanged:(NSNumber *)nodeID - (oneway void)device:(NSNumber *)nodeID internalStateUpdated:(NSDictionary *)dictionary { + MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__); + + // Save old state for comparison later + NSNumber *oldStateNumber = self._internalState[kMTRDeviceInternalPropertyDeviceState]; + NSNumber *newStateNumber = dictionary[kMTRDeviceInternalPropertyDeviceState]; [self _setInternalState:dictionary]; - MTR_LOG("%@ internal state updated", self); + + // Call delegate if state changed. State is considered changed if: + // 1) old state is nil but new state is not nil + // 2) old state is not nil but new state is nil + // 3) both old and new state are not nil, and they are not equal + if ((!oldStateNumber && newStateNumber) || + (oldStateNumber && !newStateNumber) || + (oldStateNumber && newStateNumber && ![newStateNumber isEqualToNumber:oldStateNumber])) { + MTRDeviceState state = static_cast(newStateNumber ? newStateNumber.unsignedIntegerValue : MTRDeviceStateUnknown); + [self _lockAndCallDelegatesWithBlock:^(id delegate) { + [delegate device:self stateChanged:state]; + }]; + } +} + +- (MTRDeviceState)state +{ + NSNumber *stateNumber = self._internalState[kMTRDeviceInternalPropertyDeviceState]; + return stateNumber ? static_cast(stateNumber.unsignedIntegerValue) : MTRDeviceStateUnknown; +} + +- (BOOL)deviceCachePrimed +{ + NSNumber *deviceCachePrimedNumber = self._internalState[kMTRDeviceInternalPropertyDeviceCachePrimed]; + return deviceCachePrimedNumber.boolValue; +} + +- (NSDate *)estimatedStartTime +{ + return self._internalState[kMTRDeviceInternalPropertyEstimatedStartTime]; +} + +- (NSNumber *)estimatedSubscriptionLatency +{ + return self._internalState[kMTRDeviceInternalPropertyEstimatedSubscriptionLatency]; } #pragma mark - Remote Commands -MTR_DEVICE_SIMPLE_REMOTE_XPC_GETTER(state, MTRDeviceState, MTRDeviceStateUnknown, getStateWithReply) -MTR_DEVICE_SIMPLE_REMOTE_XPC_GETTER(deviceCachePrimed, BOOL, NO, getDeviceCachePrimedWithReply) -MTR_DEVICE_SIMPLE_REMOTE_XPC_GETTER(estimatedStartTime, NSDate * _Nullable, nil, getEstimatedStartTimeWithReply) -MTR_DEVICE_SIMPLE_REMOTE_XPC_GETTER(estimatedSubscriptionLatency, NSNumber * _Nullable, nil, getEstimatedSubscriptionLatencyWithReply) +//MTR_DEVICE_SIMPLE_REMOTE_XPC_GETTER(state, MTRDeviceState, MTRDeviceStateUnknown, getStateWithReply) +//MTR_DEVICE_SIMPLE_REMOTE_XPC_GETTER(deviceCachePrimed, BOOL, NO, getDeviceCachePrimedWithReply) +//MTR_DEVICE_SIMPLE_REMOTE_XPC_GETTER(estimatedStartTime, NSDate * _Nullable, nil, getEstimatedStartTimeWithReply) +//MTR_DEVICE_SIMPLE_REMOTE_XPC_GETTER(estimatedSubscriptionLatency, NSNumber * _Nullable, nil, getEstimatedSubscriptionLatencyWithReply) typedef NSDictionary * _Nullable ReadAttributeResponseType; MTR_DEVICE_COMPLEX_REMOTE_XPC_GETTER(readAttributeWithEndpointID diff --git a/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h b/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h index bd7d0e6df0e99c..134c887cbc2f6f 100644 --- a/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h +++ b/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h @@ -60,14 +60,23 @@ MTR_NEWLY_AVAILABLE // - (oneway void)deviceController:(NSUUID *)controller removeServerEndpoint:(MTRServerEndpoint *)endpoint; - (oneway void)deviceController:(NSUUID *)controller shutdownDeviceController:(NSUUID *)controller; + +// TODO: replace once the the reply version is tested and integrated +// (also, should this be placed under MTRXPCServerProtocol_MTRDevice?) - (oneway void)deviceController:(NSUUID *)controller registerNodeID:(NSNumber *)nodeID; - (oneway void)deviceController:(NSUUID *)controller unregisterNodeID:(NSNumber *)nodeID; +// Register Node and get initial internal state +- (oneway void)deviceController:(NSUUID *)controller registerNodeID:(NSNumber *)nodeID reply:(void (^)(NSDictionary * internalState))reply; @end MTR_NEWLY_AVAILABLE @protocol MTRXPCServerProtocol +// TODO: remove once the the reply version is tested and integrated - (oneway void)deviceController:(NSUUID *)controller checkInWithContext:(NSDictionary *)context; + +// Check-in and get initial state +- (oneway void)deviceController:(NSUUID *)controller checkInWithContext:(NSDictionary *)context reply:(void (^)(NSDictionary * controllerInfo))reply; @end NS_ASSUME_NONNULL_END