Web Inspector: Heap: lazily create the agent
[WebKit-https.git] / Source / WebCore / inspector / InspectorController.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "InspectorController.h"
34
35 #include "CommandLineAPIHost.h"
36 #include "CommonVM.h"
37 #include "DOMWindow.h"
38 #include "DOMWrapperWorld.h"
39 #include "Frame.h"
40 #include "GraphicsContext.h"
41 #include "InspectorApplicationCacheAgent.h"
42 #include "InspectorCPUProfilerAgent.h"
43 #include "InspectorCSSAgent.h"
44 #include "InspectorCanvasAgent.h"
45 #include "InspectorClient.h"
46 #include "InspectorDOMAgent.h"
47 #include "InspectorDOMDebuggerAgent.h"
48 #include "InspectorDOMStorageAgent.h"
49 #include "InspectorDatabaseAgent.h"
50 #include "InspectorFrontendClient.h"
51 #include "InspectorIndexedDBAgent.h"
52 #include "InspectorInstrumentation.h"
53 #include "InspectorLayerTreeAgent.h"
54 #include "InspectorMemoryAgent.h"
55 #include "InspectorPageAgent.h"
56 #include "InspectorTimelineAgent.h"
57 #include "InspectorWorkerAgent.h"
58 #include "InstrumentingAgents.h"
59 #include "JSDOMBindingSecurity.h"
60 #include "JSDOMWindow.h"
61 #include "JSDOMWindowCustom.h"
62 #include "JSExecState.h"
63 #include "Page.h"
64 #include "PageAuditAgent.h"
65 #include "PageConsoleAgent.h"
66 #include "PageDebuggerAgent.h"
67 #include "PageHeapAgent.h"
68 #include "PageNetworkAgent.h"
69 #include "PageRuntimeAgent.h"
70 #include "PageScriptDebugServer.h"
71 #include "Settings.h"
72 #include "WebInjectedScriptHost.h"
73 #include "WebInjectedScriptManager.h"
74 #include <JavaScriptCore/IdentifiersFactory.h>
75 #include <JavaScriptCore/InspectorAgent.h>
76 #include <JavaScriptCore/InspectorBackendDispatcher.h>
77 #include <JavaScriptCore/InspectorBackendDispatchers.h>
78 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
79 #include <JavaScriptCore/InspectorFrontendRouter.h>
80 #include <JavaScriptCore/InspectorScriptProfilerAgent.h>
81 #include <JavaScriptCore/JSLock.h>
82 #include <wtf/Stopwatch.h>
83
84 #if ENABLE(REMOTE_INSPECTOR)
85 #include "PageDebuggable.h"
86 #endif
87
88 namespace WebCore {
89
90 using namespace JSC;
91 using namespace Inspector;
92
93 InspectorController::InspectorController(Page& page, InspectorClient* inspectorClient)
94     : m_instrumentingAgents(InstrumentingAgents::create(*this))
95     , m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
96     , m_frontendRouter(FrontendRouter::create())
97     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
98     , m_overlay(std::make_unique<InspectorOverlay>(page, inspectorClient))
99     , m_executionStopwatch(Stopwatch::create())
100     , m_scriptDebugServer(page)
101     , m_page(page)
102     , m_inspectorClient(inspectorClient)
103 {
104     ASSERT_ARG(inspectorClient, inspectorClient);
105
106     auto pageContext = pageAgentContext();
107
108     auto inspectorAgentPtr = std::make_unique<InspectorAgent>(pageContext);
109     m_inspectorAgent = inspectorAgentPtr.get();
110     m_instrumentingAgents->setInspectorAgent(m_inspectorAgent);
111     m_agents.append(WTFMove(inspectorAgentPtr));
112
113     auto pageAgentPtr = std::make_unique<InspectorPageAgent>(pageContext, inspectorClient, m_overlay.get());
114     InspectorPageAgent* pageAgent = pageAgentPtr.get();
115     m_pageAgent = pageAgentPtr.get();
116     m_agents.append(WTFMove(pageAgentPtr));
117
118     auto runtimeAgent = std::make_unique<PageRuntimeAgent>(pageContext, pageAgent);
119     m_instrumentingAgents->setPageRuntimeAgent(runtimeAgent.get());
120     m_agents.append(WTFMove(runtimeAgent));
121
122     auto domAgentPtr = std::make_unique<InspectorDOMAgent>(pageContext, pageAgent, m_overlay.get());
123     m_domAgent = domAgentPtr.get();
124     m_agents.append(WTFMove(domAgentPtr));
125
126     auto databaseAgentPtr = std::make_unique<InspectorDatabaseAgent>(pageContext);
127     InspectorDatabaseAgent* databaseAgent = databaseAgentPtr.get();
128     m_agents.append(WTFMove(databaseAgentPtr));
129
130     auto domStorageAgentPtr = std::make_unique<InspectorDOMStorageAgent>(pageContext, m_pageAgent);
131     InspectorDOMStorageAgent* domStorageAgent = domStorageAgentPtr.get();
132     m_agents.append(WTFMove(domStorageAgentPtr));
133
134     auto scriptProfilerAgentPtr = std::make_unique<InspectorScriptProfilerAgent>(pageContext);
135     m_instrumentingAgents->setInspectorScriptProfilerAgent(scriptProfilerAgentPtr.get());
136     m_agents.append(WTFMove(scriptProfilerAgentPtr));
137
138     auto consoleAgentPtr = std::make_unique<PageConsoleAgent>(pageContext, m_domAgent);
139     WebConsoleAgent* consoleAgent = consoleAgentPtr.get();
140     m_instrumentingAgents->setWebConsoleAgent(consoleAgentPtr.get());
141     m_agents.append(WTFMove(consoleAgentPtr));
142
143     ASSERT(m_injectedScriptManager->commandLineAPIHost());
144     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost())
145         commandLineAPIHost->init(m_inspectorAgent, consoleAgent, domStorageAgent, databaseAgent);
146 }
147
148 InspectorController::~InspectorController()
149 {
150     m_instrumentingAgents->reset();
151     ASSERT(!m_inspectorClient);
152 }
153
154 PageAgentContext InspectorController::pageAgentContext()
155 {
156     AgentContext baseContext = {
157         *this,
158         *m_injectedScriptManager,
159         m_frontendRouter.get(),
160         m_backendDispatcher.get()
161     };
162
163     WebAgentContext webContext = {
164         baseContext,
165         m_instrumentingAgents.get()
166     };
167
168     PageAgentContext pageContext = {
169         webContext,
170         m_page
171     };
172
173     return pageContext;
174 }
175
176 void InspectorController::createLazyAgents()
177 {
178     if (m_didCreateLazyAgents)
179         return;
180
181     m_didCreateLazyAgents = true;
182
183     auto pageContext = pageAgentContext();
184
185     auto debuggerAgent = std::make_unique<PageDebuggerAgent>(pageContext, m_pageAgent);
186     auto debuggerAgentPtr = debuggerAgent.get();
187
188     m_agents.append(WTFMove(debuggerAgent));
189     m_agents.append(std::make_unique<PageNetworkAgent>(pageContext, m_pageAgent));
190     m_agents.append(std::make_unique<InspectorCSSAgent>(pageContext, m_domAgent));
191     m_agents.append(std::make_unique<InspectorDOMDebuggerAgent>(pageContext, m_domAgent, debuggerAgentPtr));
192     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(pageContext, m_pageAgent));
193     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
194     m_agents.append(std::make_unique<InspectorWorkerAgent>(pageContext));
195 #if ENABLE(INDEXED_DATABASE)
196     m_agents.append(std::make_unique<InspectorIndexedDBAgent>(pageContext, m_pageAgent));
197 #endif
198 #if ENABLE(RESOURCE_USAGE)
199     m_agents.append(std::make_unique<InspectorCPUProfilerAgent>(pageContext));
200     m_agents.append(std::make_unique<InspectorMemoryAgent>(pageContext));
201     m_agents.append(std::make_unique<PageHeapAgent>(pageContext));
202 #endif
203     m_agents.append(std::make_unique<PageAuditAgent>(pageContext));
204     m_agents.append(std::make_unique<InspectorCanvasAgent>(pageContext));
205     m_agents.append(std::make_unique<InspectorTimelineAgent>(pageContext));
206 }
207
208 void InspectorController::inspectedPageDestroyed()
209 {
210     // Clean up resources and disconnect local and remote frontends.
211     disconnectAllFrontends();
212
213     // Disconnect the client.
214     m_inspectorClient->inspectedPageDestroyed();
215     m_inspectorClient = nullptr;
216
217     m_agents.discardValues();
218 }
219
220 void InspectorController::setInspectorFrontendClient(InspectorFrontendClient* inspectorFrontendClient)
221 {
222     m_inspectorFrontendClient = inspectorFrontendClient;
223 }
224
225 bool InspectorController::hasLocalFrontend() const
226 {
227     return m_frontendRouter->hasLocalFrontend();
228 }
229
230 bool InspectorController::hasRemoteFrontend() const
231 {
232     return m_frontendRouter->hasRemoteFrontend();
233 }
234
235 unsigned InspectorController::inspectionLevel() const
236 {
237     return m_inspectorFrontendClient ? m_inspectorFrontendClient->inspectionLevel() : 0;
238 }
239
240 void InspectorController::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world)
241 {
242     if (&world != &mainThreadNormalWorld())
243         return;
244
245     if (frame.isMainFrame())
246         m_injectedScriptManager->discardInjectedScripts();
247
248     // If the page is supposed to serve as InspectorFrontend notify inspector frontend
249     // client that it's cleared so that the client can expose inspector bindings.
250     if (m_inspectorFrontendClient && frame.isMainFrame())
251         m_inspectorFrontendClient->windowObjectCleared();
252 }
253
254 void InspectorController::connectFrontend(Inspector::FrontendChannel& frontendChannel, bool isAutomaticInspection, bool immediatelyPause)
255 {
256     ASSERT(m_inspectorClient);
257
258     // If a frontend has connected enable the developer extras and keep them enabled.
259     m_page.settings().setDeveloperExtrasEnabled(true);
260
261     createLazyAgents();
262
263     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
264     m_isAutomaticInspection = isAutomaticInspection;
265     m_pauseAfterInitialization = immediatelyPause;
266
267     m_frontendRouter->connectFrontend(frontendChannel);
268
269     InspectorInstrumentation::frontendCreated();
270
271     if (connectedFirstFrontend) {
272         InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
273         m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get());
274     }
275
276     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
277
278 #if ENABLE(REMOTE_INSPECTOR)
279     if (hasLocalFrontend())
280         m_page.remoteInspectorInformationDidChange();
281 #endif
282 }
283
284 void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel)
285 {
286     m_frontendRouter->disconnectFrontend(frontendChannel);
287
288     m_isAutomaticInspection = false;
289     m_pauseAfterInitialization = false;
290
291     InspectorInstrumentation::frontendDeleted();
292
293     bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
294     if (disconnectedLastFrontend) {
295         // Notify agents first.
296         m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
297
298         // Clean up inspector resources.
299         m_injectedScriptManager->discardInjectedScripts();
300
301         // Unplug all instrumentations since they aren't needed now.
302         InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
303     }
304
305     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
306
307 #if ENABLE(REMOTE_INSPECTOR)
308     if (disconnectedLastFrontend)
309         m_page.remoteInspectorInformationDidChange();
310 #endif
311 }
312
313 void InspectorController::disconnectAllFrontends()
314 {
315     // If the local frontend page was destroyed, close the window.
316     if (m_inspectorFrontendClient)
317         m_inspectorFrontendClient->closeWindow();
318
319     // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow().
320     ASSERT(!m_inspectorFrontendClient);
321
322     if (!m_frontendRouter->hasFrontends())
323         return;
324
325     for (unsigned i = 0; i < m_frontendRouter->frontendCount(); ++i)
326         InspectorInstrumentation::frontendDeleted();
327
328     // Unplug all instrumentations to prevent further agent callbacks.
329     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
330
331     // Notify agents first, since they may need to use InspectorClient.
332     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
333
334     // Clean up inspector resources.
335     m_injectedScriptManager->disconnect();
336
337     // Disconnect any remaining remote frontends.
338     m_frontendRouter->disconnectAllFrontends();
339     m_isAutomaticInspection = false;
340     m_pauseAfterInitialization = false;
341
342     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
343
344 #if ENABLE(REMOTE_INSPECTOR)
345     m_page.remoteInspectorInformationDidChange();
346 #endif
347 }
348
349 void InspectorController::show()
350 {
351     ASSERT(!hasRemoteFrontend());
352
353     if (!enabled())
354         return;
355
356     if (m_frontendRouter->hasLocalFrontend())
357         m_inspectorClient->bringFrontendToFront();
358     else if (Inspector::FrontendChannel* frontendChannel = m_inspectorClient->openLocalFrontend(this))
359         connectFrontend(*frontendChannel);
360 }
361
362 void InspectorController::setIsUnderTest(bool value)
363 {
364     if (value == m_isUnderTest)
365         return;
366
367     m_isUnderTest = value;
368
369     // <rdar://problem/26768628> Try to catch suspicious scenarios where we may have a dangling frontend while running tests.
370     RELEASE_ASSERT(!m_isUnderTest || !m_frontendRouter->hasFrontends());
371 }
372
373 void InspectorController::evaluateForTestInFrontend(const String& script)
374 {
375     m_inspectorAgent->evaluateForTestInFrontend(script);
376 }
377
378 void InspectorController::drawHighlight(GraphicsContext& context) const
379 {
380     m_overlay->paint(context);
381 }
382
383 void InspectorController::getHighlight(Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem) const
384 {
385     m_overlay->getHighlight(highlight, coordinateSystem);
386 }
387
388 void InspectorController::inspect(Node* node)
389 {
390     if (!enabled())
391         return;
392
393     if (!hasRemoteFrontend())
394         show();
395
396     m_domAgent->inspect(node);
397 }
398
399 bool InspectorController::enabled() const
400 {
401     return developerExtrasEnabled();
402 }
403
404 Page& InspectorController::inspectedPage() const
405 {
406     return m_page;
407 }
408
409 void InspectorController::dispatchMessageFromFrontend(const String& message)
410 {
411     m_backendDispatcher->dispatch(message);
412 }
413
414 void InspectorController::hideHighlight()
415 {
416     ErrorString unused;
417     m_domAgent->hideHighlight(unused);
418 }
419
420 Node* InspectorController::highlightedNode() const
421 {
422     return m_overlay->highlightedNode();
423 }
424
425 void InspectorController::setIndicating(bool indicating)
426 {
427 #if !PLATFORM(IOS_FAMILY)
428     m_overlay->setIndicating(indicating);
429 #else
430     if (indicating)
431         m_inspectorClient->showInspectorIndication();
432     else
433         m_inspectorClient->hideInspectorIndication();
434 #endif
435 }
436
437 bool InspectorController::developerExtrasEnabled() const
438 {
439     return m_page.settings().developerExtrasEnabled();
440 }
441
442 bool InspectorController::canAccessInspectedScriptState(JSC::ExecState* scriptState) const
443 {
444     JSLockHolder lock(scriptState);
445
446     JSDOMWindow* inspectedWindow = toJSDOMWindow(scriptState->vm(), scriptState->lexicalGlobalObject());
447     if (!inspectedWindow)
448         return false;
449
450     return BindingSecurity::shouldAllowAccessToDOMWindow(scriptState, inspectedWindow->wrapped(), DoNotReportSecurityError);
451 }
452
453 InspectorFunctionCallHandler InspectorController::functionCallHandler() const
454 {
455     return WebCore::functionCallHandlerFromAnyThread;
456 }
457
458 InspectorEvaluateHandler InspectorController::evaluateHandler() const
459 {
460     return WebCore::evaluateHandlerFromAnyThread;
461 }
462
463 void InspectorController::frontendInitialized()
464 {
465     if (m_pauseAfterInitialization) {
466         m_pauseAfterInitialization = false;
467         if (PageDebuggerAgent* debuggerAgent = m_instrumentingAgents->pageDebuggerAgent()) {
468             ErrorString ignored;
469             debuggerAgent->pause(ignored);
470         }
471     }
472
473 #if ENABLE(REMOTE_INSPECTOR)
474     if (m_isAutomaticInspection)
475         m_page.inspectorDebuggable().unpauseForInitializedInspector();
476 #endif
477 }
478
479 Ref<Stopwatch> InspectorController::executionStopwatch()
480 {
481     return m_executionStopwatch.copyRef();
482 }
483
484 PageScriptDebugServer& InspectorController::scriptDebugServer()
485 {
486     return m_scriptDebugServer;
487 }
488
489 JSC::VM& InspectorController::vm()
490 {
491     return commonVM();
492 }
493
494 void InspectorController::didComposite(Frame& frame)
495 {
496     InspectorInstrumentation::didComposite(frame);
497 }
498
499 } // namespace WebCore