Skip to content

Commit

Permalink
[Darwin] Internal state plumbing for the _XPC classes (#35962)
Browse files Browse the repository at this point in the history
* Updating this

* Restyled by clang-format

* Removing bad rebase

* Update src/darwin/Framework/CHIP/MTRDevice_XPC.mm

* Fixing format

* Fixing format

* Restyled by clang-format

* Fixing

* Restyled by clang-format

* fixing bad merge

* fixing bad merge

* Apply suggestions from code review

* Remove unnecessary MTRDevice_Concrete changes.

---------

Co-authored-by: Justin Wood <[email protected]>
Co-authored-by: Restyled.io <[email protected]>
Co-authored-by: Boris Zbarsky <[email protected]>
  • Loading branch information
4 people authored Oct 29, 2024
1 parent ee71833 commit 0f5f31d
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 65 deletions.
2 changes: 1 addition & 1 deletion src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ - (NSUInteger)_iterateDelegateInfoWithBlock:(void (^_Nullable)(MTRDeviceControll
}
}

- (void)_callDelegatesWithBlock:(void (^_Nullable)(id<MTRDeviceControllerDelegate> delegate))block logString:(const char *)logString;
- (void)_callDelegatesWithBlock:(void (^_Nullable)(id<MTRDeviceControllerDelegate> delegate))block logString:(const char *)logString
{
NSUInteger delegatesCalled = [self _iterateDelegateInfoWithBlock:^(MTRDeviceControllerDelegateInfo * delegateInfo) {
id<MTRDeviceControllerDelegate> strongDelegate = delegateInfo.delegate;
Expand Down
69 changes: 66 additions & 3 deletions src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ @interface MTRDeviceController_XPC ()
NSString * const MTRDeviceControllerRegistrationControllerContextKey = @"MTRDeviceControllerRegistrationControllerContext";
NSString * const MTRDeviceControllerRegistrationNodeIDsKey = @"MTRDeviceControllerRegistrationNodeIDs";
NSString * const MTRDeviceControllerRegistrationNodeIDKey = @"MTRDeviceControllerRegistrationNodeID";
NSString * const MTRDeviceControllerRegistrationControllerNodeIDKey = @"MTRDeviceControllerRegistrationControllerNodeID";
NSString * const MTRDeviceControllerRegistrationControllerIsRunningKey = @"MTRDeviceControllerRegistrationControllerIsRunning";
NSString * const MTRDeviceControllerRegistrationDeviceInternalStateKey = @"MTRDeviceControllerRegistrationDeviceInternalState";

// #define MTR_HAVE_MACH_SERVICE_NAME_CONSTRUCTOR

Expand Down Expand Up @@ -90,6 +93,8 @@ - (void)removeDevice:(MTRDevice *)device
}

#pragma mark - XPC
@synthesize controllerNodeID = _controllerNodeID;

+ (NSMutableSet *)_allowedClasses
{
static NSArray * sBaseAllowedClasses = @[
Expand Down Expand Up @@ -167,6 +172,13 @@ - (NSXPCInterface *)_interfaceForClientProtocol
argumentIndex:1
ofReply:NO];

allowedClasses = [MTRDeviceController_XPC _allowedClasses];

[interface setClasses:allowedClasses
forSelector:@selector(controller:controllerConfigurationUpdated:)
argumentIndex:1
ofReply:NO];

return interface;
}

Expand Down Expand Up @@ -346,9 +358,6 @@ - (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)

// Not Supported via XPC
// - (oneway void)deviceController:(NSUUID *)controller setupCommissioningSessionWithPayload:(MTRSetupPayload *)payload newNodeID:(NSNumber *)newNodeID withReply:(void(^)(BOOL success, NSError * _Nullable error))reply;
// - (oneway void)deviceController:(NSUUID *)controller setupCommissioningSessionWithDiscoveredDevice:(MTRCommissionableBrowserResult *)discoveredDevice payload:(MTRSetupPayload *)payload newNodeID:(NSNumber *)newNodeID withReply:(void(^)(BOOL success, NSError * _Nullable error))reply;
Expand Down Expand Up @@ -424,6 +433,60 @@ - (oneway void)device:(NSNumber *)nodeID internalStateUpdated:(NSDictionary *)di

#pragma mark - MTRDeviceController Protocol Client

- (oneway void)controller:(NSUUID *)controller controllerConfigurationUpdated:(NSDictionary *)configuration
{
// Reuse the same format as config dictionary, and add values for internal states
// @{
// MTRDeviceControllerRegistrationControllerContextKey: @{
// MTRDeviceControllerRegistrationControllerNodeIDKey: controllerNodeID
// }
// MTRDeviceControllerRegistrationNodeIDsKey: @[
// @{
// MTRDeviceControllerRegistrationNodeIDKey: nodeID,
// MTRDeviceControllerRegistrationDeviceInternalStateKey: deviceInternalStateDictionary
// }
// ]
// }

NSDictionary * controllerContext = MTR_SAFE_CAST(configuration[MTRDeviceControllerRegistrationControllerContextKey], NSDictionary);
NSNumber * controllerNodeID = MTR_SAFE_CAST(controllerContext[MTRDeviceControllerRegistrationControllerNodeIDKey], NSNumber);
if (controllerContext && controllerNodeID) {
_controllerNodeID = controllerContext[MTRDeviceControllerRegistrationControllerNodeIDKey];
}

NSArray * deviceInfoList = MTR_SAFE_CAST(configuration[MTRDeviceControllerRegistrationNodeIDsKey], NSArray);

MTR_LOG("Received controllerConfigurationUpdated: controllerNode ID %@ deviceInfoList %@", self.controllerNodeID, deviceInfoList);

for (NSDictionary * deviceInfo in deviceInfoList) {
if (!MTR_SAFE_CAST(deviceInfo, NSDictionary)) {
MTR_LOG_ERROR(" - Missing or malformed device Info");
continue;
}

NSNumber * nodeID = MTR_SAFE_CAST(deviceInfo[MTRDeviceControllerRegistrationNodeIDKey], NSNumber);
if (!nodeID) {
MTR_LOG_ERROR(" - Missing or malformed nodeID");
continue;
}

NSDictionary * deviceInternalState = MTR_SAFE_CAST(deviceInfo[MTRDeviceControllerRegistrationDeviceInternalStateKey], NSDictionary);
if (!deviceInternalState) {
MTR_LOG_ERROR(" - Missing or malformed deviceInternalState");
continue;
}

auto * device = static_cast<MTRDevice_XPC *>([self deviceForNodeID:nodeID]);
[device device:nodeID internalStateUpdated:deviceInternalState];
}
}

- (BOOL)isRunning
{
// For XPC controller, always return yes
return YES;
}

// Not Supported via XPC
//- (oneway void)controller:(NSUUID *)controller statusUpdate:(MTRCommissioningStatus)status {
// }
Expand Down
34 changes: 25 additions & 9 deletions src/darwin/Framework/CHIP/MTRDevice_Concrete.mm
Original file line number Diff line number Diff line change
Expand Up @@ -475,15 +475,26 @@ - (NSString *)description
- (NSDictionary *)_internalProperties
{
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);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyKeyVendorID, _vid, properties);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyKeyProductID, _pid, properties);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyNetworkFeatures, _allNetworkFeatures, properties);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyMostRecentReportTime, _mostRecentReportTimeForDescription, properties);
}

{
std::lock_guard lock(_lock);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyDeviceInternalState, [NSNumber numberWithUnsignedInteger:_internalDeviceState], properties);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionAttemptWait, [NSNumber numberWithUnsignedInt:_lastSubscriptionAttemptWait], properties);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyLastSubscriptionFailureTime, _lastSubscriptionFailureTime, properties);

MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyDeviceState, @(_state), properties);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyDeviceCachePrimed, @(_deviceCachePrimed), properties);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyEstimatedStartTime, _estimatedStartTime, properties);
MTR_OPTIONAL_ATTRIBUTE(kMTRDeviceInternalPropertyEstimatedSubscriptionLatency, _estimatedSubscriptionLatency, properties);
}

return properties;
}
Expand Down Expand Up @@ -968,6 +979,7 @@ - (void)_callDelegateDeviceCachePrimed
[delegate deviceCachePrimed:self];
}
}];
[self _notifyDelegateOfPrivateInternalPropertiesChanges];
}

// assume lock is held
Expand Down Expand Up @@ -998,6 +1010,7 @@ - (void)_changeState:(MTRDeviceState)state
[self _callDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
[delegate device:self stateChanged:state];
}];
[self _notifyDelegateOfPrivateInternalPropertiesChanges];
} else {
MTR_LOG(
"%@ Not reporting reachability state change, since no change in state %lu => %lu", self, static_cast<unsigned long>(lastState), static_cast<unsigned long>(state));
Expand Down Expand Up @@ -1438,6 +1451,7 @@ - (void)_handleUnsolicitedMessageFromPublisher
[delegate deviceBecameActive:self];
}
}];
[self _notifyDelegateOfPrivateInternalPropertiesChanges];

// in case this is called during exponential back off of subscription
// reestablishment, this starts the attempt right away
Expand Down Expand Up @@ -2423,7 +2437,9 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
mtr_strongify(self);
VerifyOrReturn(self);

[self _markDeviceAsUnreachableIfNeverSubscribed];
if (!HaveSubscriptionEstablishedRightNow(self->_internalDeviceState)) {
[self _markDeviceAsUnreachableIfNeverSubscribed];
}
});
}

Expand Down
6 changes: 5 additions & 1 deletion src/darwin/Framework/CHIP/MTRDevice_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,13 @@ static NSString * const kTestStorageUserDefaultEnabledKey = @"enableTestStorage"
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
103 changes: 61 additions & 42 deletions src/darwin/Framework/CHIP/MTRDevice_XPC.mm
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#import "MTRSetupPayload.h"
#import "MTRTimeUtils.h"
#import "MTRUnfairLock.h"
#import "MTRUtilities.h"
#import "NSDataSpanConversion.h"
#import "NSStringSpanConversion.h"

Expand Down Expand Up @@ -113,22 +114,21 @@ - (NSString *)description
}

// 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);

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];
return [NSString stringWithFormat:@"<%@: %p, node: %016llX-%016llX (%llu), VID: %@, PID: %@, WiFi: %@, Thread: %@, controller: %@ state: %lu>",
NSStringFromClass(self.class), self,
_deviceController.compressedFabricID.unsignedLongLongValue,
_nodeID.unsignedLongLongValue,
_nodeID.unsignedLongLongValue,
[self vendorID],
[self productID],
wifi,
thread,
_deviceController.uniqueIdentifier,
(unsigned long) self.state];
}

- (nullable NSNumber *)vendorID
Expand All @@ -146,19 +146,12 @@ - (nullable NSNumber *)productID
// required methods for MTRDeviceDelegates
- (oneway void)device:(NSNumber *)nodeID stateChanged:(MTRDeviceState)state
{
if (!MTR_SAFE_CAST(nodeID, NSNumber)) {
MTR_LOG_ERROR("%@ invalid device:stateChanged: nodeID: %@", self, nodeID);
return;
}

MTR_LOG("%s", __PRETTY_FUNCTION__);
[self _lockAndCallDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
[delegate device:self stateChanged:state];
}];
// Not needed, since internal will get this
}

- (oneway void)device:(NSNumber *)nodeID receivedAttributeReport:(NSArray<MTRDeviceResponseValueDictionary> *)attributeReport
{
MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__);
if (!MTR_SAFE_CAST(nodeID, NSNumber)) {
MTR_LOG_ERROR("%@ invalid device:receivedAttributeReport: nodeID: %@", self, nodeID);
return;
Expand All @@ -169,14 +162,14 @@ - (oneway void)device:(NSNumber *)nodeID receivedAttributeReport:(NSArray<MTRDev
return;
}

MTR_LOG("%s", __PRETTY_FUNCTION__);
[self _lockAndCallDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
[delegate device:self receivedAttributeReport:attributeReport];
}];
}

- (oneway void)device:(NSNumber *)nodeID receivedEventReport:(NSArray<MTRDeviceResponseValueDictionary> *)eventReport
{
MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__);
if (!MTR_SAFE_CAST(nodeID, NSNumber)) {
MTR_LOG_ERROR("%@ invalid device:receivedEventReport: nodeID: %@", self, nodeID);
return;
Expand All @@ -187,7 +180,6 @@ - (oneway void)device:(NSNumber *)nodeID receivedEventReport:(NSArray<MTRDeviceR
return;
}

MTR_LOG("%s", __PRETTY_FUNCTION__);
[self _lockAndCallDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
[delegate device:self receivedEventReport:eventReport];
}];
Expand All @@ -196,12 +188,12 @@ - (oneway void)device:(NSNumber *)nodeID receivedEventReport:(NSArray<MTRDeviceR
// optional methods for MTRDeviceDelegates - check for implementation before calling
- (oneway void)deviceBecameActive:(NSNumber *)nodeID
{
MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__);
if (!MTR_SAFE_CAST(nodeID, NSNumber)) {
MTR_LOG_ERROR("%@ invalid deviceBecameActive: nodeID: %@", self, nodeID);
return;
}

MTR_LOG("%s", __PRETTY_FUNCTION__);
[self _lockAndCallDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
if ([delegate respondsToSelector:@selector(deviceBecameActive:)]) {
[delegate deviceBecameActive:self];
Expand All @@ -211,20 +203,12 @@ - (oneway void)deviceBecameActive:(NSNumber *)nodeID

- (oneway void)deviceCachePrimed:(NSNumber *)nodeID
{
if (!MTR_SAFE_CAST(nodeID, NSNumber)) {
MTR_LOG_ERROR("%@ invalid deviceCachePrimed: nodeID: %@", self, nodeID);
return;
}

[self _lockAndCallDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
if ([delegate respondsToSelector:@selector(deviceCachePrimed:)]) {
[delegate deviceCachePrimed:self];
}
}];
// Not needed since this is a state update now
}

- (oneway void)deviceConfigurationChanged:(NSNumber *)nodeID
{
MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__);
if (!MTR_SAFE_CAST(nodeID, NSNumber)) {
MTR_LOG_ERROR("%@ invalid deviceConfigurationChanged: nodeID: %@", self, nodeID);
return;
Expand Down Expand Up @@ -264,6 +248,7 @@ - (BOOL)_internalState:(NSDictionary *)dictionary hasValidValuesForKeys:(const N

- (oneway void)device:(NSNumber *)nodeID internalStateUpdated:(NSDictionary *)dictionary
{
MTR_LOG("%@ %s", self, __PRETTY_FUNCTION__);
if (!MTR_SAFE_CAST(nodeID, NSNumber)) {
MTR_LOG_ERROR("%@ invalid device:internalStateUpdated: nodeID: %@", self, nodeID);
return;
Expand All @@ -274,22 +259,56 @@ - (oneway void)device:(NSNumber *)nodeID internalStateUpdated:(NSDictionary *)di
return;
}

NSNumber * oldStateNumber = MTR_SAFE_CAST(self._internalState[kMTRDeviceInternalPropertyDeviceState], NSNumber);
NSNumber * newStateNumber = MTR_SAFE_CAST(dictionary[kMTRDeviceInternalPropertyDeviceState], NSNumber);

VerifyOrReturn([self _internalState:dictionary hasValidValuesForKeys:requiredInternalStateKeys valueRequired:YES]);
VerifyOrReturn([self _internalState:dictionary hasValidValuesForKeys:optionalInternalStateKeys valueRequired:NO]);

[self _setInternalState:dictionary];
MTR_LOG("%@ internal state updated", self);

if (!MTREqualObjects(oldStateNumber, newStateNumber)) {
MTRDeviceState state = self.state;
[self _lockAndCallDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
[delegate device:self stateChanged:state];
}];
}

NSNumber * oldPrimedState = MTR_SAFE_CAST(self._internalState[kMTRDeviceInternalPropertyDeviceCachePrimed], NSNumber);
NSNumber * newPrimedState = MTR_SAFE_CAST(dictionary[kMTRDeviceInternalPropertyDeviceCachePrimed], NSNumber);

if (!MTREqualObjects(oldPrimedState, newPrimedState)) {
[self _lockAndCallDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
if ([delegate respondsToSelector:@selector(deviceCachePrimed:)]) {
[delegate deviceCachePrimed:self];
}
}];
}
}

#pragma mark - Remote Commands
- (MTRDeviceState)state
{
NSNumber * stateNumber = MTR_SAFE_CAST(self._internalState[kMTRDeviceInternalPropertyDeviceState], NSNumber);
return stateNumber ? static_cast<MTRDeviceState>(stateNumber.unsignedIntegerValue) : MTRDeviceStateUnknown;
}

- (BOOL)deviceCachePrimed
{
NSNumber * deviceCachePrimedNumber = MTR_SAFE_CAST(self._internalState[kMTRDeviceInternalPropertyDeviceCachePrimed], NSNumber);
return deviceCachePrimedNumber.boolValue;
}

- (nullable NSDate *)estimatedStartTime
{
return MTR_SAFE_CAST(self._internalState[kMTRDeviceInternalPropertyEstimatedStartTime], NSDate);
}

// TODO: Figure out how to validate the return values for the various
// MTR_DEVICE_*_XPC macros below.
- (nullable NSNumber *)estimatedSubscriptionLatency
{
return MTR_SAFE_CAST(self._internalState[kMTRDeviceInternalPropertyEstimatedSubscriptionLatency], NSNumber);
}

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)
#pragma mark - Remote Commands

typedef NSDictionary<NSString *, id> * _Nullable ReadAttributeResponseType;
MTR_DEVICE_COMPLEX_REMOTE_XPC_GETTER(readAttributeWithEndpointID
Expand Down
Loading

0 comments on commit 0f5f31d

Please sign in to comment.