Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / content / browser / devtools / render_frame_devtools_agent_host.cc
blob9d09b9829ecee8965f0f648057d5e2cb0c269bc1
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
7 #include "base/basictypes.h"
8 #include "base/lazy_instance.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/child_process_security_policy_impl.h"
11 #include "content/browser/devtools/devtools_frame_trace_recorder.h"
12 #include "content/browser/devtools/protocol/devtools_protocol_handler.h"
13 #include "content/browser/devtools/protocol/dom_handler.h"
14 #include "content/browser/devtools/protocol/emulation_handler.h"
15 #include "content/browser/devtools/protocol/input_handler.h"
16 #include "content/browser/devtools/protocol/inspector_handler.h"
17 #include "content/browser/devtools/protocol/network_handler.h"
18 #include "content/browser/devtools/protocol/page_handler.h"
19 #include "content/browser/devtools/protocol/power_handler.h"
20 #include "content/browser/devtools/protocol/service_worker_handler.h"
21 #include "content/browser/devtools/protocol/tracing_handler.h"
22 #include "content/browser/frame_host/render_frame_host_impl.h"
23 #include "content/browser/renderer_host/render_process_host_impl.h"
24 #include "content/browser/renderer_host/render_view_host_impl.h"
25 #include "content/browser/site_instance_impl.h"
26 #include "content/browser/web_contents/web_contents_impl.h"
27 #include "content/common/view_messages.h"
28 #include "content/public/browser/browser_context.h"
29 #include "content/public/browser/content_browser_client.h"
30 #include "content/public/browser/render_widget_host_iterator.h"
31 #include "content/public/browser/web_contents_delegate.h"
33 #if defined(OS_ANDROID)
34 #include "content/browser/power_save_blocker_impl.h"
35 #include "content/public/browser/render_widget_host_view.h"
36 #endif
38 namespace content {
40 typedef std::vector<RenderFrameDevToolsAgentHost*> Instances;
42 namespace {
43 base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
45 static RenderFrameDevToolsAgentHost* FindAgentHost(RenderFrameHost* host) {
46 if (g_instances == NULL)
47 return NULL;
48 for (Instances::iterator it = g_instances.Get().begin();
49 it != g_instances.Get().end(); ++it) {
50 if ((*it)->HasRenderFrameHost(host))
51 return *it;
53 return NULL;
56 // Returns RenderFrameDevToolsAgentHost attached to any of RenderFrameHost
57 // instances associated with |web_contents|
58 static RenderFrameDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
59 if (g_instances == NULL)
60 return NULL;
61 for (Instances::iterator it = g_instances.Get().begin();
62 it != g_instances.Get().end(); ++it) {
63 if ((*it)->GetWebContents() == web_contents)
64 return *it;
66 return NULL;
69 bool ShouldCreateDevToolsFor(RenderFrameHost* rfh) {
70 return rfh->IsCrossProcessSubframe() || !rfh->GetParent();
73 } // namespace
75 scoped_refptr<DevToolsAgentHost>
76 DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
77 RenderFrameDevToolsAgentHost* result = FindAgentHost(web_contents);
78 if (!result)
79 result = new RenderFrameDevToolsAgentHost(web_contents->GetMainFrame());
80 return result;
83 // static
84 scoped_refptr<DevToolsAgentHost> RenderFrameDevToolsAgentHost::GetOrCreateFor(
85 RenderFrameHost* host) {
86 RenderFrameDevToolsAgentHost* result = FindAgentHost(host);
87 if (!result)
88 result = new RenderFrameDevToolsAgentHost(host);
89 return result;
92 // static
93 void RenderFrameDevToolsAgentHost::AppendAgentHostForFrameIfApplicable(
94 DevToolsAgentHost::List* result,
95 RenderFrameHost* host) {
96 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(host);
97 if (!rfh->IsRenderFrameLive())
98 return;
99 if (ShouldCreateDevToolsFor(rfh))
100 result->push_back(RenderFrameDevToolsAgentHost::GetOrCreateFor(rfh));
103 // static
104 bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
105 return FindAgentHost(web_contents) != NULL;
108 // static
109 bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
110 RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
111 return agent_host && agent_host->IsAttached();
114 //static
115 void RenderFrameDevToolsAgentHost::AddAllAgentHosts(
116 DevToolsAgentHost::List* result) {
117 base::Callback<void(RenderFrameHost*)> callback = base::Bind(
118 RenderFrameDevToolsAgentHost::AppendAgentHostForFrameIfApplicable,
119 base::Unretained(result));
120 for (const auto& wc : WebContentsImpl::GetAllWebContents())
121 wc->ForEachFrame(callback);
124 // static
125 void RenderFrameDevToolsAgentHost::OnCancelPendingNavigation(
126 RenderFrameHost* pending,
127 RenderFrameHost* current) {
128 RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(pending);
129 if (!agent_host)
130 return;
131 agent_host->ReattachToRenderFrameHost(current);
134 RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(RenderFrameHost* rfh)
135 : render_frame_host_(NULL),
136 dom_handler_(new devtools::dom::DOMHandler()),
137 input_handler_(new devtools::input::InputHandler()),
138 inspector_handler_(new devtools::inspector::InspectorHandler()),
139 network_handler_(new devtools::network::NetworkHandler()),
140 page_handler_(nullptr),
141 power_handler_(new devtools::power::PowerHandler()),
142 service_worker_handler_(
143 new devtools::service_worker::ServiceWorkerHandler()),
144 tracing_handler_(new devtools::tracing::TracingHandler(
145 devtools::tracing::TracingHandler::Renderer)),
146 emulation_handler_(nullptr),
147 frame_trace_recorder_(nullptr),
148 reattaching_(false) {
149 DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
150 dispatcher->SetDOMHandler(dom_handler_.get());
151 dispatcher->SetInputHandler(input_handler_.get());
152 dispatcher->SetInspectorHandler(inspector_handler_.get());
153 dispatcher->SetNetworkHandler(network_handler_.get());
154 dispatcher->SetPowerHandler(power_handler_.get());
155 dispatcher->SetServiceWorkerHandler(service_worker_handler_.get());
156 dispatcher->SetTracingHandler(tracing_handler_.get());
158 if (!rfh->GetParent()) {
159 page_handler_.reset(new devtools::page::PageHandler());
160 emulation_handler_.reset(
161 new devtools::emulation::EmulationHandler(page_handler_.get()));
162 dispatcher->SetPageHandler(page_handler_.get());
163 dispatcher->SetEmulationHandler(emulation_handler_.get());
166 SetRenderFrameHost(rfh);
167 g_instances.Get().push_back(this);
168 AddRef(); // Balanced in RenderFrameHostDestroyed.
171 BrowserContext* RenderFrameDevToolsAgentHost::GetBrowserContext() {
172 WebContents* contents = web_contents();
173 return contents ? contents->GetBrowserContext() : nullptr;
176 WebContents* RenderFrameDevToolsAgentHost::GetWebContents() {
177 return web_contents();
180 void RenderFrameDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
181 if (!render_frame_host_)
182 return;
183 msg->set_routing_id(render_frame_host_->GetRoutingID());
184 render_frame_host_->Send(msg);
187 void RenderFrameDevToolsAgentHost::OnClientAttached(bool reattached) {
188 if (!render_frame_host_)
189 return;
191 InnerOnClientAttached();
193 // TODO(kaznacheev): Move this call back to DevToolsManager when
194 // extensions::ProcessManager no longer relies on this notification.
195 if (!reattaching_)
196 DevToolsAgentHostImpl::NotifyCallbacks(this, true);
199 void RenderFrameDevToolsAgentHost::InnerOnClientAttached() {
200 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
201 render_frame_host_->GetProcess()->GetID());
203 #if defined(OS_ANDROID)
204 power_save_blocker_.reset(static_cast<PowerSaveBlockerImpl*>(
205 PowerSaveBlocker::Create(
206 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
207 PowerSaveBlocker::kReasonOther, "DevTools").release()));
208 power_save_blocker_->InitDisplaySleepBlocker(
209 WebContents::FromRenderFrameHost(render_frame_host_));
210 #endif
212 frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder());
215 void RenderFrameDevToolsAgentHost::OnClientDetached() {
216 #if defined(OS_ANDROID)
217 power_save_blocker_.reset();
218 #endif
219 if (emulation_handler_)
220 emulation_handler_->Detached();
221 if (page_handler_)
222 page_handler_->Detached();
223 power_handler_->Detached();
224 service_worker_handler_->Detached();
225 tracing_handler_->Detached();
226 ClientDetachedFromRenderer();
228 // TODO(kaznacheev): Move this call back to DevToolsManager when
229 // extensions::ProcessManager no longer relies on this notification.
230 if (!reattaching_)
231 DevToolsAgentHostImpl::NotifyCallbacks(this, false);
234 void RenderFrameDevToolsAgentHost::ClientDetachedFromRenderer() {
235 if (!render_frame_host_)
236 return;
238 InnerClientDetachedFromRenderer();
241 void RenderFrameDevToolsAgentHost::InnerClientDetachedFromRenderer() {
242 bool process_has_agents = false;
243 RenderProcessHost* render_process_host = render_frame_host_->GetProcess();
244 for (Instances::iterator it = g_instances.Get().begin();
245 it != g_instances.Get().end(); ++it) {
246 if (*it == this || !(*it)->IsAttached())
247 continue;
248 RenderFrameHost* rfh = (*it)->render_frame_host_;
249 if (rfh && rfh->GetProcess() == render_process_host)
250 process_has_agents = true;
253 // We are the last to disconnect from the renderer -> revoke permissions.
254 if (!process_has_agents) {
255 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
256 render_process_host->GetID());
258 frame_trace_recorder_.reset();
261 RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() {
262 Instances::iterator it = std::find(g_instances.Get().begin(),
263 g_instances.Get().end(),
264 this);
265 if (it != g_instances.Get().end())
266 g_instances.Get().erase(it);
269 // TODO(creis): Consider removing this in favor of RenderFrameHostChanged.
270 void RenderFrameDevToolsAgentHost::AboutToNavigateRenderFrame(
271 RenderFrameHost* old_host,
272 RenderFrameHost* new_host) {
273 if (render_frame_host_ != old_host)
274 return;
276 // TODO(creis): This will need to be updated for --site-per-process, since
277 // RenderViewHost is going away and navigations could happen in any frame.
278 if (render_frame_host_ == new_host) {
279 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
280 render_frame_host_->GetRenderViewHost());
281 if (rvh->render_view_termination_status() ==
282 base::TERMINATION_STATUS_STILL_RUNNING)
283 return;
285 ReattachToRenderFrameHost(new_host);
288 void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
289 RenderFrameHost* old_host,
290 RenderFrameHost* new_host) {
291 if (old_host == render_frame_host_ && new_host != render_frame_host_) {
292 // AboutToNavigateRenderFrame was not called for renderer-initiated
293 // navigation.
294 ReattachToRenderFrameHost(new_host);
298 void
299 RenderFrameDevToolsAgentHost::ReattachToRenderFrameHost(RenderFrameHost* rfh) {
300 if (!ShouldCreateDevToolsFor(rfh)) {
301 DestroyOnRenderFrameGone();
302 // |this| may be deleted at this point.
303 return;
306 DCHECK(!reattaching_);
307 reattaching_ = true;
308 DisconnectRenderFrameHost();
309 ConnectRenderFrameHost(rfh);
310 reattaching_ = false;
313 void RenderFrameDevToolsAgentHost::FrameDeleted(RenderFrameHost* rfh) {
314 if (rfh != render_frame_host_)
315 return;
316 DestroyOnRenderFrameGone();
317 // |this| may be deleted at this point.
320 void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() {
321 DCHECK(render_frame_host_);
322 scoped_refptr<RenderFrameDevToolsAgentHost> protect(this);
323 if (IsAttached())
324 OnClientDetached();
325 HostClosed();
326 ClearRenderFrameHost();
327 Release();
330 void RenderFrameDevToolsAgentHost::RenderProcessGone(
331 base::TerminationStatus status) {
332 switch(status) {
333 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
334 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
335 case base::TERMINATION_STATUS_PROCESS_CRASHED:
336 #if defined(OS_ANDROID)
337 case base::TERMINATION_STATUS_OOM_PROTECTED:
338 #endif
339 RenderFrameCrashed();
340 break;
341 default:
342 break;
346 bool RenderFrameDevToolsAgentHost::OnMessageReceived(
347 const IPC::Message& message) {
348 if (!render_frame_host_)
349 return false;
350 if (message.type() == ViewHostMsg_SwapCompositorFrame::ID)
351 OnSwapCompositorFrame(message);
352 return false;
355 bool RenderFrameDevToolsAgentHost::OnMessageReceived(
356 const IPC::Message& message,
357 RenderFrameHost* render_frame_host) {
358 if (!render_frame_host_ || render_frame_host != render_frame_host_)
359 return false;
361 bool handled = true;
362 IPC_BEGIN_MESSAGE_MAP(RenderFrameDevToolsAgentHost, message)
363 IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
364 OnDispatchOnInspectorFrontend)
365 IPC_MESSAGE_UNHANDLED(handled = false)
366 IPC_END_MESSAGE_MAP()
367 return handled;
370 void RenderFrameDevToolsAgentHost::DidAttachInterstitialPage() {
371 if (page_handler_)
372 page_handler_->DidAttachInterstitialPage();
374 if (!render_frame_host_)
375 return;
376 // The rvh set in AboutToNavigateRenderFrame turned out to be interstitial.
377 // Connect back to the real one.
378 WebContents* web_contents =
379 WebContents::FromRenderFrameHost(render_frame_host_);
380 if (!web_contents)
381 return;
382 DisconnectRenderFrameHost();
383 ConnectRenderFrameHost(web_contents->GetMainFrame());
386 void RenderFrameDevToolsAgentHost::DidDetachInterstitialPage() {
387 if (page_handler_)
388 page_handler_->DidDetachInterstitialPage();
391 void RenderFrameDevToolsAgentHost::DidCommitProvisionalLoadForFrame(
392 RenderFrameHost* render_frame_host,
393 const GURL& url,
394 ui::PageTransition transition_type) {
395 service_worker_handler_->UpdateHosts();
398 void RenderFrameDevToolsAgentHost::SetRenderFrameHost(RenderFrameHost* rfh) {
399 DCHECK(ShouldCreateDevToolsFor(rfh));
400 DCHECK(!render_frame_host_);
401 render_frame_host_ = static_cast<RenderFrameHostImpl*>(rfh);
402 DCHECK(render_frame_host_);
404 WebContentsObserver::Observe(WebContents::FromRenderFrameHost(rfh));
405 dom_handler_->SetRenderFrameHost(render_frame_host_);
406 input_handler_->SetRenderWidgetHost(
407 render_frame_host_->GetRenderWidgetHost());
408 network_handler_->SetRenderFrameHost(render_frame_host_);
409 service_worker_handler_->SetRenderFrameHost(render_frame_host_);
411 if (emulation_handler_)
412 emulation_handler_->SetRenderFrameHost(render_frame_host_);
413 if (page_handler_)
414 page_handler_->SetRenderFrameHost(render_frame_host_);
417 void RenderFrameDevToolsAgentHost::ClearRenderFrameHost() {
418 DCHECK(render_frame_host_);
419 render_frame_host_ = nullptr;
420 dom_handler_->SetRenderFrameHost(nullptr);
421 if (emulation_handler_)
422 emulation_handler_->SetRenderFrameHost(nullptr);
423 input_handler_->SetRenderWidgetHost(nullptr);
424 network_handler_->SetRenderFrameHost(nullptr);
425 if (page_handler_)
426 page_handler_->SetRenderFrameHost(nullptr);
427 service_worker_handler_->SetRenderFrameHost(nullptr);
430 void RenderFrameDevToolsAgentHost::DisconnectWebContents() {
431 DisconnectRenderFrameHost();
434 void RenderFrameDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
435 ConnectRenderFrameHost(wc->GetMainFrame());
438 DevToolsAgentHost::Type RenderFrameDevToolsAgentHost::GetType() {
439 return IsChildFrame() ? TYPE_FRAME : TYPE_WEB_CONTENTS;
442 std::string RenderFrameDevToolsAgentHost::GetTitle() {
443 if (IsChildFrame())
444 return GetURL().spec();
445 if (WebContents* web_contents = GetWebContents())
446 return base::UTF16ToUTF8(web_contents->GetTitle());
447 return "";
450 GURL RenderFrameDevToolsAgentHost::GetURL() {
451 WebContents* web_contents = GetWebContents();
452 if (web_contents && !IsChildFrame())
453 return web_contents->GetVisibleURL();
454 return render_frame_host_ ?
455 render_frame_host_->GetLastCommittedURL() : GURL();
458 bool RenderFrameDevToolsAgentHost::Activate() {
459 if (render_frame_host_) {
460 render_frame_host_->GetRenderViewHost()->GetDelegate()->Activate();
461 return true;
463 return false;
466 bool RenderFrameDevToolsAgentHost::Close() {
467 if (render_frame_host_) {
468 render_frame_host_->GetRenderViewHost()->ClosePage();
469 return true;
471 return false;
474 void RenderFrameDevToolsAgentHost::ConnectRenderFrameHost(
475 RenderFrameHost* rfh) {
476 SetRenderFrameHost(rfh);
477 if (IsAttached())
478 Reattach();
481 void RenderFrameDevToolsAgentHost::DisconnectRenderFrameHost() {
482 ClientDetachedFromRenderer();
483 ClearRenderFrameHost();
486 void RenderFrameDevToolsAgentHost::RenderFrameCrashed() {
487 inspector_handler_->TargetCrashed();
490 void RenderFrameDevToolsAgentHost::OnSwapCompositorFrame(
491 const IPC::Message& message) {
492 ViewHostMsg_SwapCompositorFrame::Param param;
493 if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
494 return;
495 if (page_handler_)
496 page_handler_->OnSwapCompositorFrame(get<1>(param).metadata);
497 if (frame_trace_recorder_) {
498 frame_trace_recorder_->OnSwapCompositorFrame(
499 render_frame_host_, get<1>(param).metadata);
503 void RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame(
504 const cc::CompositorFrameMetadata& frame_metadata) {
505 if (!render_frame_host_)
506 return;
507 if (page_handler_)
508 page_handler_->OnSwapCompositorFrame(frame_metadata);
509 if (frame_trace_recorder_) {
510 frame_trace_recorder_->OnSwapCompositorFrame(
511 render_frame_host_, frame_metadata);
515 bool RenderFrameDevToolsAgentHost::HasRenderFrameHost(
516 RenderFrameHost* host) {
517 return host == render_frame_host_;
520 void RenderFrameDevToolsAgentHost::OnDispatchOnInspectorFrontend(
521 const DevToolsMessageChunk& message) {
522 if (!IsAttached() || !render_frame_host_)
523 return;
524 ProcessChunkedMessageFromAgent(message);
527 bool RenderFrameDevToolsAgentHost::IsChildFrame() {
528 return render_frame_host_ && render_frame_host_->GetParent();
531 } // namespace content