Change next_proto member type.
[chromium-blink-merge.git] / content / browser / devtools / render_view_devtools_agent_host.cc
blobebb0aefdd277308e176a4cde78d1436631af90d3
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_view_devtools_agent_host.h"
7 #include "base/basictypes.h"
8 #include "base/json/json_writer.h"
9 #include "base/lazy_instance.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/browser/child_process_security_policy_impl.h"
12 #include "content/browser/devtools/devtools_manager.h"
13 #include "content/browser/devtools/protocol/devtools_protocol_handler.h"
14 #include "content/browser/devtools/protocol/dom_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/tracing_handler.h"
21 #include "content/browser/renderer_host/render_process_host_impl.h"
22 #include "content/browser/renderer_host/render_view_host_impl.h"
23 #include "content/browser/site_instance_impl.h"
24 #include "content/browser/web_contents/web_contents_impl.h"
25 #include "content/common/devtools_messages.h"
26 #include "content/common/view_messages.h"
27 #include "content/public/browser/browser_context.h"
28 #include "content/public/browser/content_browser_client.h"
29 #include "content/public/browser/devtools_manager_delegate.h"
30 #include "content/public/browser/notification_service.h"
31 #include "content/public/browser/notification_types.h"
32 #include "content/public/browser/render_widget_host_iterator.h"
33 #include "content/public/browser/web_contents_delegate.h"
35 #if defined(OS_ANDROID)
36 #include "content/browser/power_save_blocker_impl.h"
37 #include "content/public/browser/render_widget_host_view.h"
38 #endif
40 namespace content {
42 typedef std::vector<RenderViewDevToolsAgentHost*> Instances;
44 namespace {
45 base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
47 //Returns RenderViewDevToolsAgentHost attached to any of RenderViewHost
48 //instances associated with |web_contents|
49 static RenderViewDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
50 if (g_instances == NULL)
51 return NULL;
52 for (Instances::iterator it = g_instances.Get().begin();
53 it != g_instances.Get().end(); ++it) {
54 if ((*it)->GetWebContents() == web_contents)
55 return *it;
57 return NULL;
60 } // namespace
62 scoped_refptr<DevToolsAgentHost>
63 DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
64 RenderViewDevToolsAgentHost* result = FindAgentHost(web_contents);
65 if (!result)
66 result = new RenderViewDevToolsAgentHost(web_contents->GetRenderViewHost());
67 return result;
70 // static
71 bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
72 return FindAgentHost(web_contents) != NULL;
75 // static
76 bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
77 RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
78 return agent_host && agent_host->IsAttached();
81 //static
82 std::vector<WebContents*> DevToolsAgentHostImpl::GetInspectableWebContents() {
83 std::set<WebContents*> set;
84 scoped_ptr<RenderWidgetHostIterator> widgets(
85 RenderWidgetHost::GetRenderWidgetHosts());
86 while (RenderWidgetHost* widget = widgets->GetNextHost()) {
87 // Ignore processes that don't have a connection, such as crashed contents.
88 if (!widget->GetProcess()->HasConnection())
89 continue;
90 if (!widget->IsRenderView())
91 continue;
93 RenderViewHost* rvh = RenderViewHost::From(widget);
94 WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
95 if (web_contents)
96 set.insert(web_contents);
98 std::vector<WebContents*> result(set.size());
99 std::copy(set.begin(), set.end(), result.begin());
100 return result;
103 // static
104 void RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
105 RenderViewHost* pending,
106 RenderViewHost* current) {
107 WebContents* web_contents = WebContents::FromRenderViewHost(pending);
108 RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
109 if (!agent_host)
110 return;
111 agent_host->DisconnectRenderViewHost();
112 agent_host->ConnectRenderViewHost(current);
115 RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost(RenderViewHost* rvh)
116 : render_view_host_(NULL),
117 dom_handler_(new devtools::dom::DOMHandler()),
118 input_handler_(new devtools::input::InputHandler()),
119 inspector_handler_(new devtools::inspector::InspectorHandler()),
120 network_handler_(new devtools::network::NetworkHandler()),
121 page_handler_(new devtools::page::PageHandler()),
122 power_handler_(new devtools::power::PowerHandler()),
123 tracing_handler_(new devtools::tracing::TracingHandler(
124 devtools::tracing::TracingHandler::Renderer)),
125 protocol_handler_(new DevToolsProtocolHandler(
126 false /* handle_generic_errors */,
127 base::Bind(&RenderViewDevToolsAgentHost::DispatchOnInspectorFrontend,
128 base::Unretained(this)))),
129 reattaching_(false) {
130 DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
131 dispatcher->SetDOMHandler(dom_handler_.get());
132 dispatcher->SetInputHandler(input_handler_.get());
133 dispatcher->SetInspectorHandler(inspector_handler_.get());
134 dispatcher->SetNetworkHandler(network_handler_.get());
135 dispatcher->SetPageHandler(page_handler_.get());
136 dispatcher->SetPowerHandler(power_handler_.get());
137 dispatcher->SetTracingHandler(tracing_handler_.get());
138 SetRenderViewHost(rvh);
139 g_instances.Get().push_back(this);
140 AddRef(); // Balanced in RenderViewHostDestroyed.
141 DevToolsManager::GetInstance()->AgentHostChanged(this);
144 BrowserContext* RenderViewDevToolsAgentHost::GetBrowserContext() {
145 WebContents* contents = web_contents();
146 return contents ? contents->GetBrowserContext() : nullptr;
149 WebContents* RenderViewDevToolsAgentHost::GetWebContents() {
150 return web_contents();
153 void RenderViewDevToolsAgentHost::DispatchProtocolMessage(
154 const std::string& message) {
156 scoped_ptr<base::DictionaryValue> command =
157 protocol_handler_->ParseCommand(message);
158 if (command) {
159 DevToolsManagerDelegate* delegate =
160 DevToolsManager::GetInstance()->delegate();
161 if (delegate) {
162 scoped_ptr<base::DictionaryValue> response(
163 delegate->HandleCommand(this, command.get()));
164 if (response) {
165 std::string json_response;
166 base::JSONWriter::Write(response.get(), &json_response);
167 DispatchOnInspectorFrontend(json_response);
168 return;
171 if (protocol_handler_->HandleCommand(command.Pass()))
172 return;
175 IPCDevToolsAgentHost::DispatchProtocolMessage(message);
178 void RenderViewDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
179 if (!render_view_host_)
180 return;
181 RenderFrameHost* main_frame_host = render_view_host_->GetMainFrame();
182 msg->set_routing_id(main_frame_host->GetRoutingID());
183 main_frame_host->Send(msg);
186 void RenderViewDevToolsAgentHost::OnClientAttached() {
187 if (!render_view_host_)
188 return;
190 InnerOnClientAttached();
192 // TODO(kaznacheev): Move this call back to DevToolsManager when
193 // extensions::ProcessManager no longer relies on this notification.
194 if (!reattaching_)
195 DevToolsAgentHostImpl::NotifyCallbacks(this, true);
198 void RenderViewDevToolsAgentHost::InnerOnClientAttached() {
199 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
200 render_view_host_->GetProcess()->GetID());
202 #if defined(OS_ANDROID)
203 power_save_blocker_.reset(
204 static_cast<PowerSaveBlockerImpl*>(
205 PowerSaveBlocker::Create(
206 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
207 "DevTools").release()));
208 if (render_view_host_->GetView()) {
209 power_save_blocker_.get()->
210 InitDisplaySleepBlocker(render_view_host_->GetView()->GetNativeView());
212 #endif
215 void RenderViewDevToolsAgentHost::OnClientDetached() {
216 #if defined(OS_ANDROID)
217 power_save_blocker_.reset();
218 #endif
219 page_handler_->Detached();
220 power_handler_->Detached();
221 tracing_handler_->Detached();
222 ClientDetachedFromRenderer();
224 // TODO(kaznacheev): Move this call back to DevToolsManager when
225 // extensions::ProcessManager no longer relies on this notification.
226 if (!reattaching_)
227 DevToolsAgentHostImpl::NotifyCallbacks(this, false);
230 void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() {
231 if (!render_view_host_)
232 return;
234 InnerClientDetachedFromRenderer();
237 void RenderViewDevToolsAgentHost::InnerClientDetachedFromRenderer() {
238 bool process_has_agents = false;
239 RenderProcessHost* render_process_host = render_view_host_->GetProcess();
240 for (Instances::iterator it = g_instances.Get().begin();
241 it != g_instances.Get().end(); ++it) {
242 if (*it == this || !(*it)->IsAttached())
243 continue;
244 RenderViewHost* rvh = (*it)->render_view_host_;
245 if (rvh && rvh->GetProcess() == render_process_host)
246 process_has_agents = true;
249 // We are the last to disconnect from the renderer -> revoke permissions.
250 if (!process_has_agents) {
251 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
252 render_process_host->GetID());
256 RenderViewDevToolsAgentHost::~RenderViewDevToolsAgentHost() {
257 Instances::iterator it = std::find(g_instances.Get().begin(),
258 g_instances.Get().end(),
259 this);
260 if (it != g_instances.Get().end())
261 g_instances.Get().erase(it);
264 // TODO(creis): Consider removing this in favor of RenderFrameHostChanged.
265 void RenderViewDevToolsAgentHost::AboutToNavigateRenderFrame(
266 RenderFrameHost* render_frame_host) {
267 if (!render_view_host_)
268 return;
270 // TODO(creis): This will need to be updated for --site-per-process, since
271 // RenderViewHost is going away and navigations could happen in any frame.
272 if (render_view_host_ == render_frame_host->GetRenderViewHost() &&
273 render_view_host_->render_view_termination_status() ==
274 base::TERMINATION_STATUS_STILL_RUNNING)
275 return;
276 ReattachToRenderViewHost(render_frame_host->GetRenderViewHost());
279 // TODO(creis): Move to RenderFrameHostChanged.
280 void RenderViewDevToolsAgentHost::RenderViewHostChanged(
281 RenderViewHost* old_host,
282 RenderViewHost* new_host) {
283 if (new_host != render_view_host_) {
284 // AboutToNavigateRenderFrame was not called for renderer-initiated
285 // navigation.
286 ReattachToRenderViewHost(new_host);
290 void
291 RenderViewDevToolsAgentHost::ReattachToRenderViewHost(RenderViewHost* rvh) {
292 DCHECK(!reattaching_);
293 reattaching_ = true;
294 DisconnectRenderViewHost();
295 ConnectRenderViewHost(rvh);
296 reattaching_ = false;
299 void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) {
300 if (rvh != render_view_host_)
301 return;
303 DCHECK(render_view_host_);
304 scoped_refptr<RenderViewDevToolsAgentHost> protect(this);
305 HostClosed();
306 ClearRenderViewHost();
307 DevToolsManager::GetInstance()->AgentHostChanged(this);
308 Release();
311 void RenderViewDevToolsAgentHost::RenderProcessGone(
312 base::TerminationStatus status) {
313 switch(status) {
314 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
315 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
316 case base::TERMINATION_STATUS_PROCESS_CRASHED:
317 #if defined(OS_ANDROID)
318 case base::TERMINATION_STATUS_OOM_PROTECTED:
319 #endif
320 RenderViewCrashed();
321 break;
322 default:
323 break;
327 bool RenderViewDevToolsAgentHost::OnMessageReceived(
328 const IPC::Message& message) {
329 if (!render_view_host_)
330 return false;
331 if (message.type() == ViewHostMsg_SwapCompositorFrame::ID)
332 OnSwapCompositorFrame(message);
333 return false;
336 bool RenderViewDevToolsAgentHost::OnMessageReceived(
337 const IPC::Message& message,
338 RenderFrameHost* render_frame_host) {
339 if (!render_view_host_)
340 return false;
341 if (render_frame_host != render_view_host_->GetMainFrame())
342 return false;
344 bool handled = true;
345 IPC_BEGIN_MESSAGE_MAP(RenderViewDevToolsAgentHost, message)
346 IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
347 OnDispatchOnInspectorFrontend)
348 IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
349 OnSaveAgentRuntimeState)
350 IPC_MESSAGE_UNHANDLED(handled = false)
351 IPC_END_MESSAGE_MAP()
352 return handled;
355 void RenderViewDevToolsAgentHost::DidAttachInterstitialPage() {
356 page_handler_->DidAttachInterstitialPage();
358 if (!render_view_host_)
359 return;
360 // The rvh set in AboutToNavigateRenderFrame turned out to be interstitial.
361 // Connect back to the real one.
362 WebContents* web_contents =
363 WebContents::FromRenderViewHost(render_view_host_);
364 if (!web_contents)
365 return;
366 DisconnectRenderViewHost();
367 ConnectRenderViewHost(web_contents->GetRenderViewHost());
370 void RenderViewDevToolsAgentHost::DidDetachInterstitialPage() {
371 page_handler_->DidDetachInterstitialPage();
374 void RenderViewDevToolsAgentHost::TitleWasSet(
375 NavigationEntry* entry, bool explicit_set) {
376 DevToolsManager::GetInstance()->AgentHostChanged(this);
379 void RenderViewDevToolsAgentHost::NavigationEntryCommitted(
380 const LoadCommittedDetails& load_details) {
381 DevToolsManager::GetInstance()->AgentHostChanged(this);
384 void RenderViewDevToolsAgentHost::Observe(int type,
385 const NotificationSource& source,
386 const NotificationDetails& details) {
387 if (type == content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
388 bool visible = *Details<bool>(details).ptr();
389 page_handler_->OnVisibilityChanged(visible);
393 void RenderViewDevToolsAgentHost::SetRenderViewHost(RenderViewHost* rvh) {
394 DCHECK(!render_view_host_);
395 render_view_host_ = static_cast<RenderViewHostImpl*>(rvh);
397 WebContentsObserver::Observe(WebContents::FromRenderViewHost(rvh));
398 dom_handler_->SetRenderViewHost(render_view_host_);
399 input_handler_->SetRenderViewHost(render_view_host_);
400 network_handler_->SetRenderViewHost(render_view_host_);
401 page_handler_->SetRenderViewHost(render_view_host_);
403 registrar_.Add(
404 this,
405 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
406 content::Source<RenderWidgetHost>(render_view_host_));
409 void RenderViewDevToolsAgentHost::ClearRenderViewHost() {
410 DCHECK(render_view_host_);
411 registrar_.Remove(
412 this,
413 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
414 content::Source<RenderWidgetHost>(render_view_host_));
415 render_view_host_ = nullptr;
416 dom_handler_->SetRenderViewHost(nullptr);
417 input_handler_->SetRenderViewHost(nullptr);
418 network_handler_->SetRenderViewHost(nullptr);
419 page_handler_->SetRenderViewHost(nullptr);
422 void RenderViewDevToolsAgentHost::DisconnectWebContents() {
423 DisconnectRenderViewHost();
426 void RenderViewDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
427 ConnectRenderViewHost(wc->GetRenderViewHost());
430 DevToolsAgentHost::Type RenderViewDevToolsAgentHost::GetType() {
431 return TYPE_WEB_CONTENTS;
434 std::string RenderViewDevToolsAgentHost::GetTitle() {
435 if (WebContents* web_contents = GetWebContents())
436 return base::UTF16ToUTF8(web_contents->GetTitle());
437 return "";
440 GURL RenderViewDevToolsAgentHost::GetURL() {
441 if (WebContents* web_contents = GetWebContents())
442 return web_contents->GetVisibleURL();
443 return render_view_host_ ?
444 render_view_host_->GetMainFrame()->GetLastCommittedURL() : GURL();
447 bool RenderViewDevToolsAgentHost::Activate() {
448 if (render_view_host_) {
449 render_view_host_->GetDelegate()->Activate();
450 return true;
452 return false;
455 bool RenderViewDevToolsAgentHost::Close() {
456 if (render_view_host_) {
457 render_view_host_->ClosePage();
458 return true;
460 return false;
463 void RenderViewDevToolsAgentHost::ConnectRenderViewHost(RenderViewHost* rvh) {
464 SetRenderViewHost(rvh);
465 if (IsAttached())
466 Reattach(state_);
469 void RenderViewDevToolsAgentHost::DisconnectRenderViewHost() {
470 ClientDetachedFromRenderer();
471 ClearRenderViewHost();
474 void RenderViewDevToolsAgentHost::RenderViewCrashed() {
475 inspector_handler_->TargetCrashed();
478 void RenderViewDevToolsAgentHost::OnSwapCompositorFrame(
479 const IPC::Message& message) {
480 ViewHostMsg_SwapCompositorFrame::Param param;
481 if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
482 return;
483 page_handler_->OnSwapCompositorFrame(param.b.metadata);
486 void RenderViewDevToolsAgentHost::SynchronousSwapCompositorFrame(
487 const cc::CompositorFrameMetadata& frame_metadata) {
488 if (!render_view_host_)
489 return;
490 page_handler_->OnSwapCompositorFrame(frame_metadata);
493 void RenderViewDevToolsAgentHost::OnSaveAgentRuntimeState(
494 const std::string& state) {
495 if (!render_view_host_)
496 return;
497 state_ = state;
500 void RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend(
501 const std::string& message,
502 uint32 total_size) {
503 if (!IsAttached() || !render_view_host_)
504 return;
505 ProcessChunkedMessageFromAgent(message, total_size);
508 void RenderViewDevToolsAgentHost::DispatchOnInspectorFrontend(
509 const std::string& message) {
510 if (!IsAttached() || !render_view_host_)
511 return;
512 SendMessageToClient(message);
515 } // namespace content