]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - inspector/remote/RemoteInspector.mm
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / inspector / remote / RemoteInspector.mm
... / ...
CommitLineData
1/*
2 * Copyright (C) 2013, 2014 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 <dispatch/dispatch.h>
37#import <notify.h>
38#import <wtf/Assertions.h>
39#import <wtf/MainThread.h>
40#import <wtf/NeverDestroyed.h>
41#import <wtf/spi/darwin/XPCSPI.h>
42#import <wtf/text/WTFString.h>
43
44#if __has_include(<sandbox/private.h>)
45#import <sandbox/private.h>
46#else
47enum sandbox_filter_type {
48 SANDBOX_FILTER_GLOBAL_NAME = 2,
49};
50#endif
51
52extern "C" int sandbox_check(pid_t, const char *operation, enum sandbox_filter_type, ...);
53extern "C" const enum sandbox_filter_type SANDBOX_CHECK_NO_REPORT;
54
55namespace Inspector {
56
57static bool canAccessWebInspectorMachPort()
58{
59 return sandbox_check(getpid(), "mach-lookup", static_cast<enum sandbox_filter_type>(SANDBOX_FILTER_GLOBAL_NAME | SANDBOX_CHECK_NO_REPORT), WIRXPCMachPortName) == 0;
60}
61
62static bool globalAutomaticInspectionState()
63{
64 int token = 0;
65 if (notify_register_check(WIRAutomaticInspectionEnabledState, &token) != NOTIFY_STATUS_OK)
66 return false;
67
68 uint64_t automaticInspectionEnabled = 0;
69 notify_get_state(token, &automaticInspectionEnabled);
70 return automaticInspectionEnabled == 1;
71}
72
73bool RemoteInspector::startEnabled = true;
74
75void RemoteInspector::startDisabled()
76{
77 RemoteInspector::startEnabled = false;
78}
79
80RemoteInspector& RemoteInspector::singleton()
81{
82 static NeverDestroyed<RemoteInspector> shared;
83
84 static dispatch_once_t once;
85 dispatch_once(&once, ^{
86 if (canAccessWebInspectorMachPort()) {
87 dispatch_block_t initialize = ^{
88 WTF::initializeMainThread();
89 JSC::initializeThreading();
90 if (RemoteInspector::startEnabled)
91 shared.get().start();
92 };
93
94 if ([NSThread isMainThread])
95 initialize();
96 else {
97 // FIXME: This means that we may miss an auto-attach to a JSContext created on a non-main thread.
98 // The main thread initialization is required for certain WTF values that need to be initialized
99 // on the "real" main thread. We should investigate a better way to handle this.
100 dispatch_async(dispatch_get_main_queue(), initialize);
101 }
102 }
103 });
104
105 return shared;
106}
107
108RemoteInspector::RemoteInspector()
109 : m_xpcQueue(dispatch_queue_create("com.apple.JavaScriptCore.remote-inspector-xpc", DISPATCH_QUEUE_SERIAL))
110 , m_nextAvailableIdentifier(1)
111 , m_notifyToken(0)
112 , m_enabled(false)
113 , m_hasActiveDebugSession(false)
114 , m_pushScheduled(false)
115 , m_parentProcessIdentifier(0)
116 , m_shouldSendParentProcessInformation(false)
117 , m_automaticInspectionEnabled(false)
118 , m_automaticInspectionPaused(false)
119 , m_automaticInspectionCandidateIdentifier(0)
120{
121}
122
123unsigned RemoteInspector::nextAvailableIdentifier()
124{
125 unsigned nextValidIdentifier;
126 do {
127 nextValidIdentifier = m_nextAvailableIdentifier++;
128 } while (!nextValidIdentifier || nextValidIdentifier == std::numeric_limits<unsigned>::max() || m_debuggableMap.contains(nextValidIdentifier));
129 return nextValidIdentifier;
130}
131
132void RemoteInspector::registerDebuggable(RemoteInspectorDebuggable* debuggable)
133{
134 std::lock_guard<std::mutex> lock(m_mutex);
135
136 unsigned identifier = nextAvailableIdentifier();
137 debuggable->setIdentifier(identifier);
138
139 auto result = m_debuggableMap.set(identifier, std::make_pair(debuggable, debuggable->info()));
140 ASSERT_UNUSED(result, result.isNewEntry);
141
142 if (debuggable->remoteDebuggingAllowed())
143 pushListingSoon();
144}
145
146void RemoteInspector::unregisterDebuggable(RemoteInspectorDebuggable* debuggable)
147{
148 std::lock_guard<std::mutex> lock(m_mutex);
149
150 unsigned identifier = debuggable->identifier();
151 if (!identifier)
152 return;
153
154 bool wasRemoved = m_debuggableMap.remove(identifier);
155 ASSERT_UNUSED(wasRemoved, wasRemoved);
156
157 if (RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.take(identifier))
158 connection->closeFromDebuggable();
159
160 if (debuggable->remoteDebuggingAllowed())
161 pushListingSoon();
162}
163
164void RemoteInspector::updateDebuggable(RemoteInspectorDebuggable* debuggable)
165{
166 std::lock_guard<std::mutex> lock(m_mutex);
167
168 unsigned identifier = debuggable->identifier();
169 if (!identifier)
170 return;
171
172 auto result = m_debuggableMap.set(identifier, std::make_pair(debuggable, debuggable->info()));
173 ASSERT_UNUSED(result, !result.isNewEntry);
174
175 pushListingSoon();
176}
177
178void RemoteInspector::updateDebuggableAutomaticInspectCandidate(RemoteInspectorDebuggable* debuggable)
179{
180 {
181 std::lock_guard<std::mutex> lock(m_mutex);
182
183 unsigned identifier = debuggable->identifier();
184 if (!identifier)
185 return;
186
187 auto result = m_debuggableMap.set(identifier, std::make_pair(debuggable, debuggable->info()));
188 ASSERT_UNUSED(result, !result.isNewEntry);
189
190 // Don't allow automatic inspection unless it is allowed or we are stopped.
191 if (!m_automaticInspectionEnabled || !m_enabled) {
192 pushListingSoon();
193 return;
194 }
195
196 // FIXME: We should handle multiple debuggables trying to pause at the same time on different threads.
197 // To make this work we will need to change m_automaticInspectionCandidateIdentifier to be a per-thread value.
198 // Multiple attempts on the same thread should not be possible because our nested run loop is in a special RWI mode.
199 if (m_automaticInspectionPaused) {
200 LOG_ERROR("Skipping Automatic Inspection Candidate with pageId(%u) because we are already paused waiting for pageId(%u)", identifier, m_automaticInspectionCandidateIdentifier);
201 pushListingSoon();
202 return;
203 }
204
205 m_automaticInspectionPaused = true;
206 m_automaticInspectionCandidateIdentifier = identifier;
207
208 // If we are pausing before we have connected to webinspectord the candidate message will be sent as soon as the connection is established.
209 if (m_xpcConnection) {
210 pushListingNow();
211 sendAutomaticInspectionCandidateMessage();
212 }
213
214 // In case debuggers fail to respond, or we cannot connect to webinspectord, automatically continue after a short period of time.
215 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.8 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
216 std::lock_guard<std::mutex> lock(m_mutex);
217 if (m_automaticInspectionCandidateIdentifier == identifier) {
218 LOG_ERROR("Skipping Automatic Inspection Candidate with pageId(%u) because we failed to receive a response in time.", m_automaticInspectionCandidateIdentifier);
219 m_automaticInspectionPaused = false;
220 }
221 });
222 }
223
224 debuggable->pauseWaitingForAutomaticInspection();
225
226 {
227 std::lock_guard<std::mutex> lock(m_mutex);
228
229 ASSERT(m_automaticInspectionCandidateIdentifier);
230 m_automaticInspectionCandidateIdentifier = 0;
231 }
232}
233
234void RemoteInspector::sendAutomaticInspectionCandidateMessage()
235{
236 ASSERT(m_enabled);
237 ASSERT(m_automaticInspectionEnabled);
238 ASSERT(m_automaticInspectionPaused);
239 ASSERT(m_automaticInspectionCandidateIdentifier);
240 ASSERT(m_xpcConnection);
241
242 NSDictionary *details = @{WIRPageIdentifierKey: @(m_automaticInspectionCandidateIdentifier)};
243 m_xpcConnection->sendMessage(WIRAutomaticInspectionCandidateMessage, details);
244}
245
246void RemoteInspector::sendMessageToRemoteFrontend(unsigned identifier, const String& message)
247{
248 std::lock_guard<std::mutex> lock(m_mutex);
249
250 if (!m_xpcConnection)
251 return;
252
253 RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.get(identifier);
254 if (!connection)
255 return;
256
257 NSDictionary *userInfo = @{
258 WIRRawDataKey: [static_cast<NSString *>(message) dataUsingEncoding:NSUTF8StringEncoding],
259 WIRConnectionIdentifierKey: connection->connectionIdentifier(),
260 WIRDestinationKey: connection->destination()
261 };
262
263 m_xpcConnection->sendMessage(WIRRawDataMessage, userInfo);
264}
265
266void RemoteInspector::setupFailed(unsigned identifier)
267{
268 std::lock_guard<std::mutex> lock(m_mutex);
269
270 m_connectionMap.remove(identifier);
271
272 updateHasActiveDebugSession();
273
274 if (identifier == m_automaticInspectionCandidateIdentifier)
275 m_automaticInspectionPaused = false;
276
277 pushListingSoon();
278}
279
280void RemoteInspector::setupCompleted(unsigned identifier)
281{
282 std::lock_guard<std::mutex> lock(m_mutex);
283
284 if (identifier == m_automaticInspectionCandidateIdentifier)
285 m_automaticInspectionPaused = false;
286}
287
288bool RemoteInspector::waitingForAutomaticInspection(unsigned)
289{
290 // We don't take the lock to check this because we assume it will be checked repeatedly.
291 return m_automaticInspectionPaused;
292}
293
294void RemoteInspector::start()
295{
296 std::lock_guard<std::mutex> lock(m_mutex);
297
298 if (m_enabled)
299 return;
300
301 m_enabled = true;
302
303 // Load the initial automatic inspection state when first started, so we know it before we have even connected to webinspectord.
304 static dispatch_once_t once;
305 dispatch_once(&once, ^{
306 m_automaticInspectionEnabled = globalAutomaticInspectionState();
307 });
308
309 notify_register_dispatch(WIRServiceAvailableNotification, &m_notifyToken, m_xpcQueue, ^(int) {
310 RemoteInspector::singleton().setupXPCConnectionIfNeeded();
311 });
312
313 notify_post(WIRServiceAvailabilityCheckNotification);
314}
315
316void RemoteInspector::stop()
317{
318 std::lock_guard<std::mutex> lock(m_mutex);
319
320 stopInternal(StopSource::API);
321}
322
323void RemoteInspector::stopInternal(StopSource source)
324{
325 if (!m_enabled)
326 return;
327
328 m_enabled = false;
329
330 m_pushScheduled = false;
331
332 for (auto it = m_connectionMap.begin(), end = m_connectionMap.end(); it != end; ++it)
333 it->value->close();
334 m_connectionMap.clear();
335
336 updateHasActiveDebugSession();
337
338 m_automaticInspectionPaused = false;
339
340 if (m_xpcConnection) {
341 switch (source) {
342 case StopSource::API:
343 m_xpcConnection->close();
344 break;
345 case StopSource::XPCMessage:
346 m_xpcConnection->closeFromMessage();
347 break;
348 }
349
350 m_xpcConnection = nullptr;
351 }
352
353 notify_cancel(m_notifyToken);
354}
355
356void RemoteInspector::setupXPCConnectionIfNeeded()
357{
358 std::lock_guard<std::mutex> lock(m_mutex);
359
360 if (m_xpcConnection)
361 return;
362
363 xpc_connection_t connection = xpc_connection_create_mach_service(WIRXPCMachPortName, m_xpcQueue, 0);
364 if (!connection)
365 return;
366
367 m_xpcConnection = adoptRef(new RemoteInspectorXPCConnection(connection, m_xpcQueue, this));
368 m_xpcConnection->sendMessage(@"syn", nil); // Send a simple message to initialize the XPC connection.
369 xpc_release(connection);
370
371 if (m_automaticInspectionCandidateIdentifier) {
372 // We already have a debuggable waiting to be automatically inspected.
373 pushListingNow();
374 sendAutomaticInspectionCandidateMessage();
375 } else
376 pushListingSoon();
377}
378
379#pragma mark - Proxy Application Information
380
381void RemoteInspector::setParentProcessInformation(pid_t pid, RetainPtr<CFDataRef> auditData)
382{
383 std::lock_guard<std::mutex> lock(m_mutex);
384
385 if (m_parentProcessIdentifier || m_parentProcessAuditData)
386 return;
387
388 m_parentProcessIdentifier = pid;
389 m_parentProcessAuditData = auditData;
390
391 if (m_shouldSendParentProcessInformation)
392 receivedProxyApplicationSetupMessage(nil);
393}
394
395#pragma mark - RemoteInspectorXPCConnection::Client
396
397void RemoteInspector::xpcConnectionReceivedMessage(RemoteInspectorXPCConnection*, NSString *messageName, NSDictionary *userInfo)
398{
399 std::lock_guard<std::mutex> lock(m_mutex);
400
401 if ([messageName isEqualToString:WIRPermissionDenied]) {
402 stopInternal(StopSource::XPCMessage);
403 return;
404 }
405
406 if ([messageName isEqualToString:WIRSocketDataMessage])
407 receivedDataMessage(userInfo);
408 else if ([messageName isEqualToString:WIRSocketSetupMessage])
409 receivedSetupMessage(userInfo);
410 else if ([messageName isEqualToString:WIRWebPageCloseMessage])
411 receivedDidCloseMessage(userInfo);
412 else if ([messageName isEqualToString:WIRApplicationGetListingMessage])
413 receivedGetListingMessage(userInfo);
414 else if ([messageName isEqualToString:WIRIndicateMessage])
415 receivedIndicateMessage(userInfo);
416 else if ([messageName isEqualToString:WIRProxyApplicationSetupMessage])
417 receivedProxyApplicationSetupMessage(userInfo);
418 else if ([messageName isEqualToString:WIRConnectionDiedMessage])
419 receivedConnectionDiedMessage(userInfo);
420 else if ([messageName isEqualToString:WIRAutomaticInspectionConfigurationMessage])
421 receivedAutomaticInspectionConfigurationMessage(userInfo);
422 else if ([messageName isEqualToString:WIRAutomaticInspectionRejectMessage])
423 receivedAutomaticInspectionRejectMessage(userInfo);
424 else
425 NSLog(@"Unrecognized RemoteInspector XPC Message: %@", messageName);
426}
427
428void RemoteInspector::xpcConnectionFailed(RemoteInspectorXPCConnection* connection)
429{
430 std::lock_guard<std::mutex> lock(m_mutex);
431
432 ASSERT(connection == m_xpcConnection);
433 if (connection != m_xpcConnection)
434 return;
435
436 m_pushScheduled = false;
437
438 for (auto it = m_connectionMap.begin(), end = m_connectionMap.end(); it != end; ++it)
439 it->value->close();
440 m_connectionMap.clear();
441
442 updateHasActiveDebugSession();
443
444 m_automaticInspectionPaused = false;
445
446 // The connection will close itself.
447 m_xpcConnection = nullptr;
448}
449
450void RemoteInspector::xpcConnectionUnhandledMessage(RemoteInspectorXPCConnection*, xpc_object_t)
451{
452 // Intentionally ignored.
453}
454
455#pragma mark - Listings
456
457NSDictionary *RemoteInspector::listingForDebuggable(const RemoteInspectorDebuggableInfo& debuggableInfo) const
458{
459 NSMutableDictionary *debuggableDetails = [NSMutableDictionary dictionary];
460
461 [debuggableDetails setObject:@(debuggableInfo.identifier) forKey:WIRPageIdentifierKey];
462
463 switch (debuggableInfo.type) {
464 case RemoteInspectorDebuggable::JavaScript: {
465 NSString *name = debuggableInfo.name;
466 [debuggableDetails setObject:name forKey:WIRTitleKey];
467 [debuggableDetails setObject:WIRTypeJavaScript forKey:WIRTypeKey];
468 break;
469 }
470 case RemoteInspectorDebuggable::Web: {
471 NSString *url = debuggableInfo.url;
472 NSString *title = debuggableInfo.name;
473 [debuggableDetails setObject:url forKey:WIRURLKey];
474 [debuggableDetails setObject:title forKey:WIRTitleKey];
475 [debuggableDetails setObject:WIRTypeWeb forKey:WIRTypeKey];
476 break;
477 }
478 default:
479 ASSERT_NOT_REACHED();
480 break;
481 }
482
483 if (RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.get(debuggableInfo.identifier))
484 [debuggableDetails setObject:connection->connectionIdentifier() forKey:WIRConnectionIdentifierKey];
485
486 if (debuggableInfo.hasLocalDebugger)
487 [debuggableDetails setObject:@YES forKey:WIRHasLocalDebuggerKey];
488
489 return debuggableDetails;
490}
491
492void RemoteInspector::pushListingNow()
493{
494 ASSERT(m_xpcConnection);
495 if (!m_xpcConnection)
496 return;
497
498 m_pushScheduled = false;
499
500 RetainPtr<NSMutableDictionary> response = adoptNS([[NSMutableDictionary alloc] init]);
501 for (auto it = m_debuggableMap.begin(), end = m_debuggableMap.end(); it != end; ++it) {
502 const RemoteInspectorDebuggableInfo& debuggableInfo = it->value.second;
503 if (debuggableInfo.remoteDebuggingAllowed) {
504 NSDictionary *details = listingForDebuggable(debuggableInfo);
505 [response setObject:details forKey:[NSString stringWithFormat:@"%u", debuggableInfo.identifier]];
506 }
507 }
508
509 RetainPtr<NSMutableDictionary> outgoing = adoptNS([[NSMutableDictionary alloc] init]);
510 [outgoing setObject:response.get() forKey:WIRListingKey];
511
512 m_xpcConnection->sendMessage(WIRListingMessage, outgoing.get());
513}
514
515void RemoteInspector::pushListingSoon()
516{
517 if (!m_xpcConnection)
518 return;
519
520 if (m_pushScheduled)
521 return;
522
523 m_pushScheduled = true;
524 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
525 std::lock_guard<std::mutex> lock(m_mutex);
526 if (m_pushScheduled)
527 pushListingNow();
528 });
529}
530
531#pragma mark - Active Debugger Sessions
532
533void RemoteInspector::updateHasActiveDebugSession()
534{
535 bool hasActiveDebuggerSession = !m_connectionMap.isEmpty();
536 if (hasActiveDebuggerSession == m_hasActiveDebugSession)
537 return;
538
539 m_hasActiveDebugSession = hasActiveDebuggerSession;
540
541 // FIXME: Expose some way to access this state in an embedder.
542 // Legacy iOS WebKit 1 had a notification. This will need to be smarter with WebKit2.
543}
544
545
546#pragma mark - Received XPC Messages
547
548void RemoteInspector::receivedSetupMessage(NSDictionary *userInfo)
549{
550 NSNumber *pageId = [userInfo objectForKey:WIRPageIdentifierKey];
551 if (!pageId)
552 return;
553
554 NSString *connectionIdentifier = [userInfo objectForKey:WIRConnectionIdentifierKey];
555 if (!connectionIdentifier)
556 return;
557
558 NSString *sender = [userInfo objectForKey:WIRSenderKey];
559 if (!sender)
560 return;
561
562 unsigned identifier = [pageId unsignedIntValue];
563 if (m_connectionMap.contains(identifier))
564 return;
565
566 auto it = m_debuggableMap.find(identifier);
567 if (it == m_debuggableMap.end())
568 return;
569
570 // Attempt to create a connection. This may fail if the page already has an inspector or if it disallows inspection.
571 RemoteInspectorDebuggable* debuggable = it->value.first;
572 RemoteInspectorDebuggableInfo debuggableInfo = it->value.second;
573 RefPtr<RemoteInspectorDebuggableConnection> connection = adoptRef(new RemoteInspectorDebuggableConnection(debuggable, connectionIdentifier, sender, debuggableInfo.type));
574 bool isAutomaticInspection = m_automaticInspectionCandidateIdentifier == debuggable->identifier();
575
576 bool automaticallyPause = false;
577 NSNumber *automaticallyPauseObject = [userInfo objectForKey:WIRAutomaticallyPause];
578 if ([automaticallyPauseObject isKindOfClass:[NSNumber class]])
579 automaticallyPause = [automaticallyPauseObject boolValue];
580
581 if (!connection->setup(isAutomaticInspection, automaticallyPause)) {
582 connection->close();
583 return;
584 }
585
586 m_connectionMap.set(identifier, connection.release());
587
588 updateHasActiveDebugSession();
589
590 pushListingSoon();
591}
592
593void RemoteInspector::receivedDataMessage(NSDictionary *userInfo)
594{
595 NSNumber *pageId = [userInfo objectForKey:WIRPageIdentifierKey];
596 if (!pageId)
597 return;
598
599 unsigned pageIdentifier = [pageId unsignedIntValue];
600 RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.get(pageIdentifier);
601 if (!connection)
602 return;
603
604 NSData *data = [userInfo objectForKey:WIRSocketDataKey];
605 RetainPtr<NSString> message = adoptNS([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
606 connection->sendMessageToBackend(message.get());
607}
608
609void RemoteInspector::receivedDidCloseMessage(NSDictionary *userInfo)
610{
611 NSNumber *pageId = [userInfo objectForKey:WIRPageIdentifierKey];
612 if (!pageId)
613 return;
614
615 NSString *connectionIdentifier = [userInfo objectForKey:WIRConnectionIdentifierKey];
616 if (!connectionIdentifier)
617 return;
618
619 unsigned identifier = [pageId unsignedIntValue];
620 RefPtr<RemoteInspectorDebuggableConnection> connection = m_connectionMap.get(identifier);
621 if (!connection)
622 return;
623
624 if (![connectionIdentifier isEqualToString:connection->connectionIdentifier()])
625 return;
626
627 connection->close();
628 m_connectionMap.remove(identifier);
629
630 updateHasActiveDebugSession();
631
632 pushListingSoon();
633}
634
635void RemoteInspector::receivedGetListingMessage(NSDictionary *)
636{
637 pushListingNow();
638}
639
640void RemoteInspector::receivedIndicateMessage(NSDictionary *userInfo)
641{
642 NSNumber *pageId = [userInfo objectForKey:WIRPageIdentifierKey];
643 if (!pageId)
644 return;
645
646 unsigned identifier = [pageId unsignedIntValue];
647 BOOL indicateEnabled = [[userInfo objectForKey:WIRIndicateEnabledKey] boolValue];
648
649 callOnWebThreadOrDispatchAsyncOnMainThread(^{
650 RemoteInspectorDebuggable* debuggable = nullptr;
651 {
652 std::lock_guard<std::mutex> lock(m_mutex);
653
654 auto it = m_debuggableMap.find(identifier);
655 if (it == m_debuggableMap.end())
656 return;
657
658 debuggable = it->value.first;
659 }
660 debuggable->setIndicating(indicateEnabled);
661 });
662}
663
664void RemoteInspector::receivedProxyApplicationSetupMessage(NSDictionary *)
665{
666 ASSERT(m_xpcConnection);
667 if (!m_xpcConnection)
668 return;
669
670 if (!m_parentProcessIdentifier || !m_parentProcessAuditData) {
671 // We are a proxy application without parent process information.
672 // Wait a bit for the information, but give up after a second.
673 m_shouldSendParentProcessInformation = true;
674 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
675 std::lock_guard<std::mutex> lock(m_mutex);
676 if (m_shouldSendParentProcessInformation)
677 stopInternal(StopSource::XPCMessage);
678 });
679 return;
680 }
681
682 m_shouldSendParentProcessInformation = false;
683
684 m_xpcConnection->sendMessage(WIRProxyApplicationSetupResponseMessage, @{
685 WIRProxyApplicationParentPIDKey: @(m_parentProcessIdentifier),
686 WIRProxyApplicationParentAuditDataKey: (NSData *)m_parentProcessAuditData.get(),
687 });
688}
689
690void RemoteInspector::receivedConnectionDiedMessage(NSDictionary *userInfo)
691{
692 NSString *connectionIdentifier = [userInfo objectForKey:WIRConnectionIdentifierKey];
693 if (!connectionIdentifier)
694 return;
695
696 auto it = m_connectionMap.begin();
697 auto end = m_connectionMap.end();
698 for (; it != end; ++it) {
699 if ([connectionIdentifier isEqualToString:it->value->connectionIdentifier()])
700 break;
701 }
702
703 if (it == end)
704 return;
705
706 RefPtr<RemoteInspectorDebuggableConnection> connection = it->value;
707 connection->close();
708 m_connectionMap.remove(it);
709
710 updateHasActiveDebugSession();
711}
712
713void RemoteInspector::receivedAutomaticInspectionConfigurationMessage(NSDictionary *userInfo)
714{
715 m_automaticInspectionEnabled = [[userInfo objectForKey:WIRAutomaticInspectionEnabledKey] boolValue];
716
717 if (!m_automaticInspectionEnabled && m_automaticInspectionPaused)
718 m_automaticInspectionPaused = false;
719}
720
721void RemoteInspector::receivedAutomaticInspectionRejectMessage(NSDictionary *userInfo)
722{
723 unsigned rejectionIdentifier = [[userInfo objectForKey:WIRPageIdentifierKey] unsignedIntValue];
724
725 ASSERT(rejectionIdentifier == m_automaticInspectionCandidateIdentifier);
726 if (rejectionIdentifier == m_automaticInspectionCandidateIdentifier)
727 m_automaticInspectionPaused = false;
728}
729
730} // namespace Inspector
731
732#endif // ENABLE(REMOTE_INSPECTOR)