19
19
#import " MTRDefines_Internal.h"
20
20
#import " MTRDeviceController_Internal.h"
21
21
#import " MTRDevice_XPC.h"
22
+ #import " MTRDevice_XPC_Internal.h"
22
23
#import " MTRLogging_Internal.h"
23
24
#import " MTRXPCClientProtocol.h"
24
25
#import " MTRXPCServerProtocol.h"
33
34
34
35
@interface MTRDeviceController_XPC ()
35
36
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;
37
41
38
42
@end
39
43
@@ -48,7 +52,15 @@ - (NSXPCInterface *)_interfaceForServerProtocol
48
52
NSXPCInterface * interface = [NSXPCInterface interfaceWithProtocol: @protocol (MTRXPCServerProtocol)];
49
53
50
54
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 ],
52
64
]];
53
65
54
66
[interface setClasses: allowedClasses
@@ -62,7 +74,14 @@ - (NSXPCInterface *)_interfaceForClientProtocol
62
74
{
63
75
NSXPCInterface * interface = [NSXPCInterface interfaceWithProtocol: @protocol (MTRXPCClientProtocol)];
64
76
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 ],
66
85
]];
67
86
[interface setClasses: allowedClasses
68
87
forSelector: @selector (device:receivedAttributeReport: )
@@ -83,6 +102,114 @@ - (NSXPCInterface *)_interfaceForClientProtocol
83
102
return [self .uniqueIdentifier UUIDString ];
84
103
}
85
104
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
+
86
213
- (nullable instancetype )initWithParameters : (MTRDeviceControllerAbstractParameters *)parameters
87
214
error : (NSError * __autoreleasing *)error
88
215
{
@@ -110,30 +237,12 @@ - (nullable instancetype)initWithParameters:(MTRDeviceControllerAbstractParamete
110
237
return nil ;
111
238
}
112
239
113
- self.xpcConnection = connectionBlock ();
114
- self.uniqueIdentifier = UUID;
240
+ self.xpcParameters = xpcParameters;
115
241
self.chipWorkQueue = dispatch_queue_create (" MTRDeviceController_XPC_queue" , DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
116
242
self.nodeIDToDeviceMap = [NSMapTable strongToWeakObjectsMapTable ];
243
+ self.uniqueIdentifier = UUID;
117
244
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 ]) {
137
246
return nil ;
138
247
}
139
248
}
@@ -159,7 +268,7 @@ - (id)initWithUniqueIdentifier:(NSUUID *)UUID machServiceName:(NSString *)machSe
159
268
self.xpcConnection .exportedObject = self;
160
269
161
270
MTR_LOG (" %s: resuming new XPC connection" );
162
- [self .xpcConnection resume ];
271
+ [self .xpcConnection activate ];
163
272
} else {
164
273
MTR_LOG_ERROR (" Failed to set up XPC Connection" );
165
274
return nil ;
@@ -177,13 +286,7 @@ - (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(N
177
286
os_unfair_lock_assert_owner (self.deviceMapLock );
178
287
179
288
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];
187
290
MTR_LOG (" %s: returning XPC device for node id %@" , __PRETTY_FUNCTION__, nodeID);
188
291
return deviceToReturn;
189
292
}
@@ -255,6 +358,14 @@ - (oneway void)deviceConfigurationChanged:(NSNumber *)nodeID
255
358
[device deviceConfigurationChanged: nodeID];
256
359
}
257
360
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
+
258
369
#pragma mark - MTRDeviceController Protocol Client
259
370
260
371
// Not Supported via XPC
0 commit comments