]>
Commit | Line | Data |
---|---|---|
81345200 A |
1 | /* |
2 | * Copyright (C) 2013 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | |
12 | * | |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #import "config.h" | |
27 | #import "RemoteInspector.h" | |
28 | ||
29 | #if ENABLE(REMOTE_INSPECTOR) | |
30 | ||
31 | #import "InitializeThreading.h" | |
32 | #import "RemoteInspectorConstants.h" | |
33 | #import "RemoteInspectorDebuggable.h" | |
34 | #import "RemoteInspectorDebuggableConnection.h" | |
35 | #import <Foundation/Foundation.h> | |
36 | #import <notify.h> | |
37 | #import <wtf/Assertions.h> | |
38 | #import <wtf/NeverDestroyed.h> | |
39 | #import <wtf/text/WTFString.h> | |
40 | #import <xpc/xpc.h> | |
41 | ||
42 | #if PLATFORM(IOS) | |
43 | #import <wtf/ios/WebCoreThread.h> | |
44 | #endif | |
45 | ||
46 | namespace Inspector { | |
47 | ||
48 | static void dispatchAsyncOnQueueSafeForAnyDebuggable(void (^block)()) | |
49 | { | |
50 | #if PLATFORM(IOS) | |
51 | if (WebCoreWebThreadIsEnabled && WebCoreWebThreadIsEnabled()) { | |
52 | WebCoreWebThreadRun(block); | |
53 | return; | |
54 | } | |
55 | #endif | |
56 | ||
57 | dispatch_async(dispatch_get_main_queue(), block); | |
58 | } | |
59 | ||
60 | bool RemoteInspector::startEnabled = true; | |
61 | ||
62 | void RemoteInspector::startDisabled() | |
63 | { | |
64 | RemoteInspector::startEnabled = false; | |
65 | } | |
66 | ||
67 | RemoteInspector& RemoteInspector::shared() | |
68 | { | |
69 | static NeverDestroyed<RemoteInspector> shared; | |
70 | ||
71 | static dispatch_once_t once; | |
72 | dispatch_once(&once, ^{ | |
73 | JSC::initializeThreading(); | |
74 | if (RemoteInspector::startEnabled) | |
75 | shared.get().start(); | |
76 | }); | |
77 | ||
78 | return shared; | |
79 | } | |
80 | ||
81 | RemoteInspector::RemoteInspector() | |
82 | : m_xpcQueue(dispatch_queue_create("com.apple.JavaScriptCore.remote-inspector-xpc", DISPATCH_QUEUE_SERIAL)) | |
83 | , m_nextAvailableIdentifier(1) | |
84 | , m_notifyToken(0) | |
85 | , m_enabled(false) | |
86 | , m_hasActiveDebugSession(false) | |
87 | , m_pushScheduled(false) | |
88 | , m_parentProcessIdentifier(0) | |
89 | , m_shouldSendParentProcessInformation(false) | |
90 | { | |
91 | } | |
92 | ||
93 | unsigned RemoteInspector::nextAvailableIdentifier() | |
94 | { | |
95 | unsigned nextValidIdentifier; | |
96 | do { | |
97 | nextValidIdentifier = m_nextAvailableIdentifier++; | |
98 | } while (!nextValidIdentifier || nextValidIdentifier == std::numeric_limits<unsigned>::max() || m_debuggableMap.contains(nextValidIdentifier)); | |
99 | return nextValidIdentifier; | |
100 | } | |
101 | ||
102 | void RemoteInspector::registerDebuggable(RemoteInspectorDebuggable* debuggable) | |
103 | { | |
104 | std::lock_guard<std::mutex> lock(m_mutex); | |
105 | ||
106 | unsigned identifier = nextAvailableIdentifier(); | |
107 | debuggable->setIdentifier(identifier); | |
108 | ||
109 | auto result = m_debuggableMap.set(identifier, std::make_pair(debuggable, debuggable->info())); | |
110 | ASSERT_UNUSED(result, result.isNewEntry); | |
111 | ||
112 | if (debuggable->remoteDebuggingAllowed()) | |
113 | pushListingSoon(); | |
114 | } | |
115 | ||
116 | void RemoteInspector::unregisterDebuggable(RemoteInspectorDebuggable* debuggable) | |
117 | { | |
118 | std::lock_guard<std::mutex> lock(m_mutex); | |
119 | ||
120 | unsigned identifier = debuggable->identifier(); | |
121 | if (!identifier) | |
122 | return; | |
123 | ||
124 | bool wasRemoved = m_debuggableMap.remove(identifier); | |
125 | ASSERT_UNUSED(wasRemoved, wasRemoved); | |
126 | ||
127 | if (RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.take(identifier)) | |
128 | connection->closeFromDebuggable(); | |
129 | ||
130 | if (debuggable->remoteDebuggingAllowed()) | |
131 | pushListingSoon(); | |
132 | } | |
133 | ||
134 | void RemoteInspector::updateDebuggable(RemoteInspectorDebuggable* debuggable) | |
135 | { | |
136 | std::lock_guard<std::mutex> lock(m_mutex); | |
137 | ||
138 | unsigned identifier = debuggable->identifier(); | |
139 | if (!identifier) | |
140 | return; | |
141 | ||
142 | auto result = m_debuggableMap.set(identifier, std::make_pair(debuggable, debuggable->info())); | |
143 | ASSERT_UNUSED(result, !result.isNewEntry); | |
144 | ||
145 | pushListingSoon(); | |
146 | } | |
147 | ||
148 | void RemoteInspector::sendMessageToRemoteFrontend(unsigned identifier, const String& message) | |
149 | { | |
150 | std::lock_guard<std::mutex> lock(m_mutex); | |
151 | ||
152 | if (!m_xpcConnection) | |
153 | return; | |
154 | ||
155 | RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.get(identifier); | |
156 | if (!connection) | |
157 | return; | |
158 | ||
159 | NSDictionary *userInfo = @{ | |
160 | WIRRawDataKey: [static_cast<NSString *>(message) dataUsingEncoding:NSUTF8StringEncoding], | |
161 | WIRConnectionIdentifierKey: connection->connectionIdentifier(), | |
162 | WIRDestinationKey: connection->destination() | |
163 | }; | |
164 | ||
165 | m_xpcConnection->sendMessage(WIRRawDataMessage, userInfo); | |
166 | } | |
167 | ||
168 | void RemoteInspector::setupFailed(unsigned identifier) | |
169 | { | |
170 | std::lock_guard<std::mutex> lock(m_mutex); | |
171 | ||
172 | m_connectionMap.remove(identifier); | |
173 | ||
174 | updateHasActiveDebugSession(); | |
175 | ||
176 | pushListingSoon(); | |
177 | } | |
178 | ||
179 | void RemoteInspector::start() | |
180 | { | |
181 | std::lock_guard<std::mutex> lock(m_mutex); | |
182 | ||
183 | if (m_enabled) | |
184 | return; | |
185 | ||
186 | m_enabled = true; | |
187 | ||
188 | notify_register_dispatch(WIRServiceAvailableNotification, &m_notifyToken, m_xpcQueue, ^(int) { | |
189 | RemoteInspector::shared().setupXPCConnectionIfNeeded(); | |
190 | }); | |
191 | ||
192 | notify_post(WIRServiceAvailabilityCheckNotification); | |
193 | } | |
194 | ||
195 | void RemoteInspector::stop() | |
196 | { | |
197 | std::lock_guard<std::mutex> lock(m_mutex); | |
198 | ||
199 | stopInternal(StopSource::API); | |
200 | } | |
201 | ||
202 | void RemoteInspector::stopInternal(StopSource source) | |
203 | { | |
204 | if (!m_enabled) | |
205 | return; | |
206 | ||
207 | m_enabled = false; | |
208 | ||
209 | m_pushScheduled = false; | |
210 | ||
211 | for (auto it = m_connectionMap.begin(), end = m_connectionMap.end(); it != end; ++it) | |
212 | it->value->close(); | |
213 | m_connectionMap.clear(); | |
214 | ||
215 | updateHasActiveDebugSession(); | |
216 | ||
217 | if (m_xpcConnection) { | |
218 | switch (source) { | |
219 | case StopSource::API: | |
220 | m_xpcConnection->close(); | |
221 | break; | |
222 | case StopSource::XPCMessage: | |
223 | m_xpcConnection->closeFromMessage(); | |
224 | break; | |
225 | } | |
226 | ||
227 | m_xpcConnection = nullptr; | |
228 | } | |
229 | ||
230 | notify_cancel(m_notifyToken); | |
231 | } | |
232 | ||
233 | void RemoteInspector::setupXPCConnectionIfNeeded() | |
234 | { | |
235 | std::lock_guard<std::mutex> lock(m_mutex); | |
236 | ||
237 | if (m_xpcConnection) | |
238 | return; | |
239 | ||
240 | xpc_connection_t connection = xpc_connection_create_mach_service(WIRXPCMachPortName, m_xpcQueue, 0); | |
241 | if (!connection) | |
242 | return; | |
243 | ||
244 | m_xpcConnection = adoptRef(new RemoteInspectorXPCConnection(connection, m_xpcQueue, this)); | |
245 | m_xpcConnection->sendMessage(@"syn", nil); // Send a simple message to initialize the XPC connection. | |
246 | xpc_release(connection); | |
247 | ||
248 | pushListingSoon(); | |
249 | } | |
250 | ||
251 | #pragma mark - Proxy Application Information | |
252 | ||
253 | void RemoteInspector::setParentProcessInformation(pid_t pid, RetainPtr<CFDataRef> auditData) | |
254 | { | |
255 | std::lock_guard<std::mutex> lock(m_mutex); | |
256 | ||
257 | if (m_parentProcessIdentifier || m_parentProcessAuditData) | |
258 | return; | |
259 | ||
260 | m_parentProcessIdentifier = pid; | |
261 | m_parentProcessAuditData = auditData; | |
262 | ||
263 | if (m_shouldSendParentProcessInformation) | |
264 | receivedProxyApplicationSetupMessage(nil); | |
265 | } | |
266 | ||
267 | #pragma mark - RemoteInspectorXPCConnection::Client | |
268 | ||
269 | void RemoteInspector::xpcConnectionReceivedMessage(RemoteInspectorXPCConnection*, NSString *messageName, NSDictionary *userInfo) | |
270 | { | |
271 | std::lock_guard<std::mutex> lock(m_mutex); | |
272 | ||
273 | if ([messageName isEqualToString:WIRPermissionDenied]) { | |
274 | stopInternal(StopSource::XPCMessage); | |
275 | return; | |
276 | } | |
277 | ||
278 | if ([messageName isEqualToString:WIRSocketDataMessage]) | |
279 | receivedDataMessage(userInfo); | |
280 | else if ([messageName isEqualToString:WIRSocketSetupMessage]) | |
281 | receivedSetupMessage(userInfo); | |
282 | else if ([messageName isEqualToString:WIRWebPageCloseMessage]) | |
283 | receivedDidCloseMessage(userInfo); | |
284 | else if ([messageName isEqualToString:WIRApplicationGetListingMessage]) | |
285 | receivedGetListingMessage(userInfo); | |
286 | else if ([messageName isEqualToString:WIRIndicateMessage]) | |
287 | receivedIndicateMessage(userInfo); | |
288 | else if ([messageName isEqualToString:WIRProxyApplicationSetupMessage]) | |
289 | receivedProxyApplicationSetupMessage(userInfo); | |
290 | else if ([messageName isEqualToString:WIRConnectionDiedMessage]) | |
291 | receivedConnectionDiedMessage(userInfo); | |
292 | else | |
293 | NSLog(@"Unrecognized RemoteInspector XPC Message: %@", messageName); | |
294 | } | |
295 | ||
296 | void RemoteInspector::xpcConnectionFailed(RemoteInspectorXPCConnection* connection) | |
297 | { | |
298 | std::lock_guard<std::mutex> lock(m_mutex); | |
299 | ||
300 | ASSERT(connection == m_xpcConnection); | |
301 | if (connection != m_xpcConnection) | |
302 | return; | |
303 | ||
304 | m_pushScheduled = false; | |
305 | ||
306 | for (auto it = m_connectionMap.begin(), end = m_connectionMap.end(); it != end; ++it) | |
307 | it->value->close(); | |
308 | m_connectionMap.clear(); | |
309 | ||
310 | updateHasActiveDebugSession(); | |
311 | ||
312 | // The connection will close itself. | |
313 | m_xpcConnection = nullptr; | |
314 | } | |
315 | ||
316 | void RemoteInspector::xpcConnectionUnhandledMessage(RemoteInspectorXPCConnection*, xpc_object_t) | |
317 | { | |
318 | // Intentionally ignored. | |
319 | } | |
320 | ||
321 | #pragma mark - Listings | |
322 | ||
323 | NSDictionary *RemoteInspector::listingForDebuggable(const RemoteInspectorDebuggableInfo& debuggableInfo) const | |
324 | { | |
325 | NSMutableDictionary *debuggableDetails = [NSMutableDictionary dictionary]; | |
326 | ||
327 | [debuggableDetails setObject:@(debuggableInfo.identifier) forKey:WIRPageIdentifierKey]; | |
328 | ||
329 | switch (debuggableInfo.type) { | |
330 | case RemoteInspectorDebuggable::JavaScript: { | |
331 | NSString *name = debuggableInfo.name; | |
332 | [debuggableDetails setObject:name forKey:WIRTitleKey]; | |
333 | [debuggableDetails setObject:WIRTypeJavaScript forKey:WIRTypeKey]; | |
334 | break; | |
335 | } | |
336 | case RemoteInspectorDebuggable::Web: { | |
337 | NSString *url = debuggableInfo.url; | |
338 | NSString *title = debuggableInfo.name; | |
339 | [debuggableDetails setObject:url forKey:WIRURLKey]; | |
340 | [debuggableDetails setObject:title forKey:WIRTitleKey]; | |
341 | [debuggableDetails setObject:WIRTypeWeb forKey:WIRTypeKey]; | |
342 | break; | |
343 | } | |
344 | default: | |
345 | ASSERT_NOT_REACHED(); | |
346 | break; | |
347 | } | |
348 | ||
349 | if (RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.get(debuggableInfo.identifier)) | |
350 | [debuggableDetails setObject:connection->connectionIdentifier() forKey:WIRConnectionIdentifierKey]; | |
351 | ||
352 | if (debuggableInfo.hasLocalDebugger) | |
353 | [debuggableDetails setObject:@YES forKey:WIRHasLocalDebuggerKey]; | |
354 | ||
355 | return debuggableDetails; | |
356 | } | |
357 | ||
358 | void RemoteInspector::pushListingNow() | |
359 | { | |
360 | ASSERT(m_xpcConnection); | |
361 | if (!m_xpcConnection) | |
362 | return; | |
363 | ||
364 | m_pushScheduled = false; | |
365 | ||
366 | RetainPtr<NSMutableDictionary> response = adoptNS([[NSMutableDictionary alloc] init]); | |
367 | for (auto it = m_debuggableMap.begin(), end = m_debuggableMap.end(); it != end; ++it) { | |
368 | const RemoteInspectorDebuggableInfo& debuggableInfo = it->value.second; | |
369 | if (debuggableInfo.remoteDebuggingAllowed) { | |
370 | NSDictionary *details = listingForDebuggable(debuggableInfo); | |
371 | [response setObject:details forKey:[NSString stringWithFormat:@"%u", debuggableInfo.identifier]]; | |
372 | } | |
373 | } | |
374 | ||
375 | RetainPtr<NSMutableDictionary> outgoing = adoptNS([[NSMutableDictionary alloc] init]); | |
376 | [outgoing setObject:response.get() forKey:WIRListingKey]; | |
377 | ||
378 | m_xpcConnection->sendMessage(WIRListingMessage, outgoing.get()); | |
379 | } | |
380 | ||
381 | void RemoteInspector::pushListingSoon() | |
382 | { | |
383 | if (!m_xpcConnection) | |
384 | return; | |
385 | ||
386 | if (m_pushScheduled) | |
387 | return; | |
388 | ||
389 | m_pushScheduled = true; | |
390 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
391 | std::lock_guard<std::mutex> lock(m_mutex); | |
392 | if (m_pushScheduled) | |
393 | pushListingNow(); | |
394 | }); | |
395 | } | |
396 | ||
397 | #pragma mark - Active Debugger Sessions | |
398 | ||
399 | void RemoteInspector::updateHasActiveDebugSession() | |
400 | { | |
401 | bool hasActiveDebuggerSession = !m_connectionMap.isEmpty(); | |
402 | if (hasActiveDebuggerSession == m_hasActiveDebugSession) | |
403 | return; | |
404 | ||
405 | m_hasActiveDebugSession = hasActiveDebuggerSession; | |
406 | ||
407 | // FIXME: Expose some way to access this state in an embedder. | |
408 | // Legacy iOS WebKit 1 had a notification. This will need to be smarter with WebKit2. | |
409 | } | |
410 | ||
411 | #pragma mark - Received XPC Messages | |
412 | ||
413 | void RemoteInspector::receivedSetupMessage(NSDictionary *userInfo) | |
414 | { | |
415 | NSNumber *pageId = [userInfo objectForKey:WIRPageIdentifierKey]; | |
416 | if (!pageId) | |
417 | return; | |
418 | ||
419 | NSString *connectionIdentifier = [userInfo objectForKey:WIRConnectionIdentifierKey]; | |
420 | if (!connectionIdentifier) | |
421 | return; | |
422 | ||
423 | NSString *sender = [userInfo objectForKey:WIRSenderKey]; | |
424 | if (!sender) | |
425 | return; | |
426 | ||
427 | unsigned identifier = [pageId unsignedIntValue]; | |
428 | if (m_connectionMap.contains(identifier)) | |
429 | return; | |
430 | ||
431 | auto it = m_debuggableMap.find(identifier); | |
432 | if (it == m_debuggableMap.end()) | |
433 | return; | |
434 | ||
435 | // Attempt to create a connection. This may fail if the page already has an inspector or if it disallows inspection. | |
436 | RemoteInspectorDebuggable* debuggable = it->value.first; | |
437 | RemoteInspectorDebuggableInfo debuggableInfo = it->value.second; | |
438 | RefPtr<RemoteInspectorDebuggableConnection> connection = adoptRef(new RemoteInspectorDebuggableConnection(debuggable, connectionIdentifier, sender, debuggableInfo.type)); | |
439 | if (!connection->setup()) { | |
440 | connection->close(); | |
441 | return; | |
442 | } | |
443 | ||
444 | m_connectionMap.set(identifier, connection.release()); | |
445 | ||
446 | updateHasActiveDebugSession(); | |
447 | ||
448 | pushListingSoon(); | |
449 | } | |
450 | ||
451 | void RemoteInspector::receivedDataMessage(NSDictionary *userInfo) | |
452 | { | |
453 | NSNumber *pageId = [userInfo objectForKey:WIRPageIdentifierKey]; | |
454 | if (!pageId) | |
455 | return; | |
456 | ||
457 | unsigned pageIdentifier = [pageId unsignedIntValue]; | |
458 | RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.get(pageIdentifier); | |
459 | if (!connection) | |
460 | return; | |
461 | ||
462 | NSData *data = [userInfo objectForKey:WIRSocketDataKey]; | |
463 | RetainPtr<NSString> message = adoptNS([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); | |
464 | connection->sendMessageToBackend(message.get()); | |
465 | } | |
466 | ||
467 | void RemoteInspector::receivedDidCloseMessage(NSDictionary *userInfo) | |
468 | { | |
469 | NSNumber *pageId = [userInfo objectForKey:WIRPageIdentifierKey]; | |
470 | if (!pageId) | |
471 | return; | |
472 | ||
473 | NSString *connectionIdentifier = [userInfo objectForKey:WIRConnectionIdentifierKey]; | |
474 | if (!connectionIdentifier) | |
475 | return; | |
476 | ||
477 | unsigned identifier = [pageId unsignedIntValue]; | |
478 | RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.get(identifier); | |
479 | if (!connection) | |
480 | return; | |
481 | ||
482 | if (![connectionIdentifier isEqualToString:connection->connectionIdentifier()]) | |
483 | return; | |
484 | ||
485 | connection->close(); | |
486 | m_connectionMap.remove(identifier); | |
487 | ||
488 | updateHasActiveDebugSession(); | |
489 | ||
490 | pushListingSoon(); | |
491 | } | |
492 | ||
493 | void RemoteInspector::receivedGetListingMessage(NSDictionary *) | |
494 | { | |
495 | pushListingNow(); | |
496 | } | |
497 | ||
498 | void RemoteInspector::receivedIndicateMessage(NSDictionary *userInfo) | |
499 | { | |
500 | NSNumber *pageId = [userInfo objectForKey:WIRPageIdentifierKey]; | |
501 | if (!pageId) | |
502 | return; | |
503 | ||
504 | unsigned identifier = [pageId unsignedIntValue]; | |
505 | BOOL indicateEnabled = [[userInfo objectForKey:WIRIndicateEnabledKey] boolValue]; | |
506 | ||
507 | dispatchAsyncOnQueueSafeForAnyDebuggable(^{ | |
508 | RemoteInspectorDebuggable* debuggable = nullptr; | |
509 | { | |
510 | std::lock_guard<std::mutex> lock(m_mutex); | |
511 | ||
512 | auto it = m_debuggableMap.find(identifier); | |
513 | if (it == m_debuggableMap.end()) | |
514 | return; | |
515 | ||
516 | debuggable = it->value.first; | |
517 | } | |
518 | debuggable->setIndicating(indicateEnabled); | |
519 | }); | |
520 | } | |
521 | ||
522 | void RemoteInspector::receivedProxyApplicationSetupMessage(NSDictionary *) | |
523 | { | |
524 | ASSERT(m_xpcConnection); | |
525 | if (!m_xpcConnection) | |
526 | return; | |
527 | ||
528 | if (!m_parentProcessIdentifier || !m_parentProcessAuditData) { | |
529 | // We are a proxy application without parent process information. | |
530 | // Wait a bit for the information, but give up after a second. | |
531 | m_shouldSendParentProcessInformation = true; | |
532 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
533 | std::lock_guard<std::mutex> lock(m_mutex); | |
534 | if (m_shouldSendParentProcessInformation) | |
535 | stopInternal(StopSource::XPCMessage); | |
536 | }); | |
537 | return; | |
538 | } | |
539 | ||
540 | m_shouldSendParentProcessInformation = false; | |
541 | ||
542 | m_xpcConnection->sendMessage(WIRProxyApplicationSetupResponseMessage, @{ | |
543 | WIRProxyApplicationParentPIDKey: @(m_parentProcessIdentifier), | |
544 | WIRProxyApplicationParentAuditDataKey: (NSData *)m_parentProcessAuditData.get(), | |
545 | }); | |
546 | } | |
547 | ||
548 | void RemoteInspector::receivedConnectionDiedMessage(NSDictionary *userInfo) | |
549 | { | |
550 | NSString *connectionIdentifier = [userInfo objectForKey:WIRConnectionIdentifierKey]; | |
551 | if (!connectionIdentifier) | |
552 | return; | |
553 | ||
554 | auto it = m_connectionMap.begin(); | |
555 | auto end = m_connectionMap.end(); | |
556 | for (; it != end; ++it) { | |
557 | if ([connectionIdentifier isEqualToString:it->value->connectionIdentifier()]) | |
558 | break; | |
559 | } | |
560 | ||
561 | if (it == end) | |
562 | return; | |
563 | ||
564 | RefPtr<RemoteInspectorDebuggableConnection> connection = it->value; | |
565 | connection->close(); | |
566 | m_connectionMap.remove(it); | |
567 | ||
568 | updateHasActiveDebugSession(); | |
569 | } | |
570 | ||
571 | } // namespace Inspector | |
572 | ||
573 | #endif // ENABLE(REMOTE_INSPECTOR) |