Skip to content

Commit f89d5b9

Browse files
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>
1 parent 513f241 commit f89d5b9

9 files changed

+270
-91
lines changed

src/darwin/Framework/CHIP/MTRDefines_Internal.h

+53
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,56 @@ typedef struct {} variable_hidden_by_mtr_hide;
111111
\
112112
return outValue; \
113113
}
114+
115+
#ifndef MTR_OPTIONAL_ATTRIBUTE
116+
#if __has_feature(objc_arc)
117+
#define MTR_OPTIONAL_ATTRIBUTE(ATTRIBUTE, VALUE, DICTIONARY) \
118+
{ \
119+
id valueToAdd = VALUE; \
120+
if (valueToAdd != nil) { \
121+
CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) (__bridge const void *) ATTRIBUTE, (const void *) valueToAdd); \
122+
} \
123+
}
124+
#else
125+
#define MTR_OPTIONAL_ATTRIBUTE(ATTRIBUTE, VALUE, DICTIONARY) \
126+
{ \
127+
id valueToAdd = VALUE; \
128+
if (valueToAdd != nil) { \
129+
CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) (const void *) ATTRIBUTE, (const void *) valueToAdd); \
130+
} \
131+
}
132+
#endif
133+
#endif
134+
135+
#ifndef MTR_OPTIONAL_COLLECTION_ATTRIBUTE
136+
#define MTR_OPTIONAL_COLLECTION_ATTRIBUTE(ATTRIBUTE, COLLECTION, DICTIONARY) \
137+
if ([COLLECTION count] > 0) { \
138+
CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) ATTRIBUTE, (const void *) COLLECTION); \
139+
}
140+
#endif
141+
142+
#ifndef MTR_OPTIONAL_NUMBER_ATTRIBUTE
143+
#define MTR_OPTIONAL_NUMBER_ATTRIBUTE(ATTRIBUTE, NUMBER, DICTIONARY) \
144+
if ([NUMBER intValue] != 0) { \
145+
CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) ATTRIBUTE, (const void *) NUMBER); \
146+
}
147+
#endif
148+
149+
#ifndef MTR_REMOVE_ATTRIBUTE
150+
#define MTR_REMOVE_ATTRIBUTE(ATTRIBUTE, DICTIONARY) \
151+
if (ATTRIBUTE != nil && DICTIONARY) { \
152+
CFDictionaryRemoveValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) ATTRIBUTE); \
153+
}
154+
#endif
155+
156+
#ifndef MTR_REQUIRED_ATTRIBUTE
157+
#define MTR_REQUIRED_ATTRIBUTE(ATTRIBUTE, VALUE, DICTIONARY) \
158+
{ \
159+
id valueToAdd = VALUE; \
160+
if (valueToAdd != nil) { \
161+
CFDictionarySetValue((CFMutableDictionaryRef) DICTIONARY, (CFStringRef) ATTRIBUTE, (const void *) valueToAdd); \
162+
} else { \
163+
MTR_LOG_ERROR("Warning, missing %@ to add to %s", ATTRIBUTE, #DICTIONARY); \
164+
} \
165+
}
166+
#endif

src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm

+7-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@
3434
static NSSet * GetXPCAllowedClasses()
3535
{
3636
static NSSet * const sXPCAllowedClasses = [NSSet setWithArray:@[
37-
[NSString class], [NSNumber class], [NSData class], [NSArray class], [NSDictionary class], [NSError class]
37+
[NSString class],
38+
[NSNumber class],
39+
[NSData class],
40+
[NSArray class],
41+
[NSDictionary class],
42+
[NSError class],
43+
[NSDate class],
3844
]];
3945
return sXPCAllowedClasses;
4046
}

src/darwin/Framework/CHIP/MTRDeviceController_XPC.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ MTR_TESTABLE
2727
- (id)initWithUniqueIdentifier:(NSUUID *)UUID machServiceName:(NSString *)machServiceName options:(NSXPCConnectionOptions)options
2828
#endif
2929

30-
@property(atomic, retain, readwrite)NSXPCConnection * xpcConnection;
30+
@property(nullable, atomic, retain, readwrite)NSXPCConnection * xpcConnection;
3131

3232
@end
3333

src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm

+143-32
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#import "MTRDefines_Internal.h"
2020
#import "MTRDeviceController_Internal.h"
2121
#import "MTRDevice_XPC.h"
22+
#import "MTRDevice_XPC_Internal.h"
2223
#import "MTRLogging_Internal.h"
2324
#import "MTRXPCClientProtocol.h"
2425
#import "MTRXPCServerProtocol.h"
@@ -33,7 +34,10 @@
3334

3435
@interface MTRDeviceController_XPC ()
3536

36-
@property (nonatomic, retain, readwrite) NSUUID * uniqueIdentifier;
37+
@property (nonatomic, readwrite, retain) NSUUID * uniqueIdentifier;
38+
@property (nonnull, atomic, readwrite, retain) MTRXPCDeviceControllerParameters * xpcParameters;
39+
@property (atomic, readwrite, assign) NSTimeInterval xpcRetryTimeInterval;
40+
@property (atomic, readwrite, assign) BOOL xpcConnectedOrConnecting;
3741

3842
@end
3943

@@ -48,7 +52,15 @@ - (NSXPCInterface *)_interfaceForServerProtocol
4852
NSXPCInterface * interface = [NSXPCInterface interfaceWithProtocol:@protocol(MTRXPCServerProtocol)];
4953

5054
NSSet * allowedClasses = [NSSet setWithArray:@[
51-
[NSString class], [NSNumber class], [NSData class], [NSArray class], [NSDictionary class], [NSError class], [MTRCommandPath class], [MTRAttributePath class]
55+
[NSString class],
56+
[NSNumber class],
57+
[NSData class],
58+
[NSArray class],
59+
[NSDictionary class],
60+
[NSError class],
61+
[MTRCommandPath class],
62+
[MTRAttributePath class],
63+
[NSDate class],
5264
]];
5365

5466
[interface setClasses:allowedClasses
@@ -62,7 +74,14 @@ - (NSXPCInterface *)_interfaceForClientProtocol
6274
{
6375
NSXPCInterface * interface = [NSXPCInterface interfaceWithProtocol:@protocol(MTRXPCClientProtocol)];
6476
NSSet * allowedClasses = [NSSet setWithArray:@[
65-
[NSString class], [NSNumber class], [NSData class], [NSArray class], [NSDictionary class], [NSError class], [MTRAttributePath class]
77+
[NSString class],
78+
[NSNumber class],
79+
[NSData class],
80+
[NSArray class],
81+
[NSDictionary class],
82+
[NSError class],
83+
[MTRAttributePath class],
84+
[NSDate class],
6685
]];
6786
[interface setClasses:allowedClasses
6887
forSelector:@selector(device:receivedAttributeReport:)
@@ -83,6 +102,114 @@ - (NSXPCInterface *)_interfaceForClientProtocol
83102
return [self.uniqueIdentifier UUIDString];
84103
}
85104

105+
- (void)_startXPCConnectionRetry
106+
{
107+
if (!self.xpcConnectedOrConnecting) {
108+
MTR_LOG("%@: XPC Connection retry - Starting retry for XPC Connection", self);
109+
self.xpcRetryTimeInterval = 0.5;
110+
mtr_weakify(self);
111+
112+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (self.xpcRetryTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
113+
mtr_strongify(self);
114+
[self _xpcConnectionRetry];
115+
});
116+
} else {
117+
MTR_LOG("%@: XPC Connection retry - Not starting retry for XPC Connection, already trying", self);
118+
}
119+
}
120+
121+
- (void)_xpcConnectionRetry
122+
{
123+
MTR_LOG("%@: XPC Connection retry - timer hit", self);
124+
if (!self.xpcConnectedOrConnecting) {
125+
if (![self _setupXPCConnection]) {
126+
#if 0 // FIXME: Not sure why this retry is not working, but I will fix this later
127+
MTR_LOG("%@: XPC Connection retry - Scheduling another retry", self);
128+
self.xpcRetryTimeInterval = self.xpcRetryTimeInterval >= 1 ? self.xpcRetryTimeInterval * 2 : 1;
129+
self.xpcRetryTimeInterval = MIN(60.0, self.xpcRetryTimeInterval);
130+
mtr_weakify(self);
131+
132+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.xpcRetryTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
133+
mtr_strongify(self);
134+
[self _xpcConnectionRetry];
135+
});
136+
#else
137+
MTR_LOG("%@: XPC Connection failed retry - bailing", self);
138+
#endif
139+
} else {
140+
MTR_LOG("%@: XPC Connection retry - connection attempt successful", self);
141+
}
142+
} else {
143+
MTR_LOG("%@: XPC Connection retry - Mid retry, or connected, stopping retry timer", self);
144+
}
145+
}
146+
147+
- (BOOL)_setupXPCConnection
148+
{
149+
self.xpcConnection = self.xpcParameters.xpcConnectionBlock();
150+
151+
MTR_LOG("%@ Set up XPC Connection: %@", self, self.xpcConnection);
152+
if (self.xpcConnection) {
153+
mtr_weakify(self);
154+
self.xpcConnection.remoteObjectInterface = [self _interfaceForServerProtocol];
155+
156+
self.xpcConnection.exportedInterface = [self _interfaceForClientProtocol];
157+
self.xpcConnection.exportedObject = self;
158+
159+
self.xpcConnection.interruptionHandler = ^{
160+
mtr_strongify(self);
161+
MTR_LOG_ERROR("XPC Connection for device controller interrupted: %@", self.xpcParameters.uniqueIdentifier);
162+
self.xpcConnectedOrConnecting = NO;
163+
self.xpcConnection = nil;
164+
[self _startXPCConnectionRetry];
165+
};
166+
167+
self.xpcConnection.invalidationHandler = ^{
168+
mtr_strongify(self);
169+
MTR_LOG_ERROR("XPC Connection for device controller invalidated: %@", self.xpcParameters.uniqueIdentifier);
170+
self.xpcConnectedOrConnecting = NO;
171+
self.xpcConnection = nil;
172+
[self _startXPCConnectionRetry];
173+
};
174+
175+
MTR_LOG("%@ Activating new XPC connection", self);
176+
[self.xpcConnection activate];
177+
178+
[[self.xpcConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
179+
MTR_LOG_ERROR("Checkin error: %@", error);
180+
}] deviceController:self.uniqueIdentifier checkInWithContext:[NSDictionary dictionary]];
181+
182+
// FIXME: Trying to kick all the MTRDevices attached to this controller to re-establish connections
183+
// This state needs to be stored properly and re-established at connnection time
184+
185+
MTR_LOG("%@ Starting existing NodeID Registration", self);
186+
for (NSNumber * nodeID in [self.nodeIDToDeviceMap keyEnumerator]) {
187+
MTR_LOG("%@ => Registering nodeID: %@", self, nodeID);
188+
mtr_weakify(self);
189+
190+
[[self.xpcConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
191+
mtr_strongify(self);
192+
MTR_LOG_ERROR("%@ Registration error for device nodeID: %@ : %@", self, nodeID, error);
193+
}] deviceController:self.uniqueIdentifier registerNodeID:nodeID];
194+
}
195+
196+
__block BOOL barrierComplete = NO;
197+
198+
[self.xpcConnection scheduleSendBarrierBlock:^{
199+
barrierComplete = YES;
200+
MTR_LOG("%@: Barrier complete: %d", self, barrierComplete);
201+
}];
202+
203+
MTR_LOG("%@ Done existing NodeID Registration, barrierComplete: %d", self, barrierComplete);
204+
self.xpcConnectedOrConnecting = barrierComplete;
205+
} else {
206+
MTR_LOG_ERROR("%@ Failed to set up XPC Connection", self);
207+
self.xpcConnectedOrConnecting = NO;
208+
}
209+
210+
return (self.xpcConnectedOrConnecting);
211+
}
212+
86213
- (nullable instancetype)initWithParameters:(MTRDeviceControllerAbstractParameters *)parameters
87214
error:(NSError * __autoreleasing *)error
88215
{
@@ -110,30 +237,12 @@ - (nullable instancetype)initWithParameters:(MTRDeviceControllerAbstractParamete
110237
return nil;
111238
}
112239

113-
self.xpcConnection = connectionBlock();
114-
self.uniqueIdentifier = UUID;
240+
self.xpcParameters = xpcParameters;
115241
self.chipWorkQueue = dispatch_queue_create("MTRDeviceController_XPC_queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
116242
self.nodeIDToDeviceMap = [NSMapTable strongToWeakObjectsMapTable];
243+
self.uniqueIdentifier = UUID;
117244

118-
MTR_LOG("Set up XPC Connection: %@", self.xpcConnection);
119-
if (self.xpcConnection) {
120-
self.xpcConnection.remoteObjectInterface = [self _interfaceForServerProtocol];
121-
122-
self.xpcConnection.exportedInterface = [self _interfaceForClientProtocol];
123-
self.xpcConnection.exportedObject = self;
124-
125-
self.xpcConnection.interruptionHandler = ^{
126-
MTR_LOG_ERROR("XPC Connection for device controller interrupted: %@", UUID);
127-
};
128-
129-
self.xpcConnection.invalidationHandler = ^{
130-
MTR_LOG_ERROR("XPC Connection for device controller invalidated: %@", UUID);
131-
};
132-
133-
MTR_LOG("Activating new XPC connection");
134-
[self.xpcConnection activate];
135-
} else {
136-
MTR_LOG_ERROR("Failed to set up XPC Connection");
245+
if (![self _setupXPCConnection]) {
137246
return nil;
138247
}
139248
}
@@ -159,7 +268,7 @@ - (id)initWithUniqueIdentifier:(NSUUID *)UUID machServiceName:(NSString *)machSe
159268
self.xpcConnection.exportedObject = self;
160269

161270
MTR_LOG("%s: resuming new XPC connection");
162-
[self.xpcConnection resume];
271+
[self.xpcConnection activate];
163272
} else {
164273
MTR_LOG_ERROR("Failed to set up XPC Connection");
165274
return nil;
@@ -177,13 +286,7 @@ - (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(N
177286
os_unfair_lock_assert_owner(self.deviceMapLock);
178287

179288
MTRDevice * deviceToReturn = [[MTRDevice_XPC alloc] initWithNodeID:nodeID controller:self];
180-
// If we're not running, don't add the device to our map. That would
181-
// create a cycle that nothing would break. Just return the device,
182-
// which will be in exactly the state it would be in if it were created
183-
// while we were running and then we got shut down.
184-
if ([self isRunning]) {
185-
[self.nodeIDToDeviceMap setObject:deviceToReturn forKey:nodeID];
186-
}
289+
[self.nodeIDToDeviceMap setObject:deviceToReturn forKey:nodeID];
187290
MTR_LOG("%s: returning XPC device for node id %@", __PRETTY_FUNCTION__, nodeID);
188291
return deviceToReturn;
189292
}
@@ -255,6 +358,14 @@ - (oneway void)deviceConfigurationChanged:(NSNumber *)nodeID
255358
[device deviceConfigurationChanged:nodeID];
256359
}
257360

361+
- (oneway void)device:(NSNumber *)nodeID internalStateUpdated:(NSDictionary *)dictionary
362+
{
363+
MTRDevice_XPC * device = (MTRDevice_XPC *) [self deviceForNodeID:nodeID];
364+
MTR_LOG("Received internalStateUpdated: %@ found device: %@", nodeID, device);
365+
366+
[device device:nodeID internalStateUpdated:dictionary];
367+
}
368+
258369
#pragma mark - MTRDeviceController Protocol Client
259370

260371
// Not Supported via XPC

0 commit comments

Comments
 (0)