Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / devtools / render_view_devtools_agent_host.cc
blob12a05d55b746b29c5a929e1c78d99b299d944bfb
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/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_manager_impl.h"
12 #include "content/browser/devtools/devtools_power_handler.h"
13 #include "content/browser/devtools/devtools_protocol.h"
14 #include "content/browser/devtools/devtools_protocol_constants.h"
15 #include "content/browser/devtools/devtools_tracing_handler.h"
16 #include "content/browser/devtools/renderer_overrides_handler.h"
17 #include "content/browser/renderer_host/render_process_host_impl.h"
18 #include "content/browser/renderer_host/render_view_host_impl.h"
19 #include "content/browser/site_instance_impl.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/common/devtools_messages.h"
22 #include "content/common/view_messages.h"
23 #include "content/public/browser/content_browser_client.h"
24 #include "content/public/browser/devtools_manager_delegate.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/notification_types.h"
27 #include "content/public/browser/render_widget_host_iterator.h"
28 #include "content/public/browser/web_contents_delegate.h"
30 #if defined(OS_ANDROID)
31 #include "content/browser/power_save_blocker_impl.h"
32 #include "content/public/browser/render_widget_host_view.h"
33 #endif
35 namespace content {
37 typedef std::vector<RenderViewDevToolsAgentHost*> Instances;
39 namespace {
40 base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
42 //Returns RenderViewDevToolsAgentHost attached to any of RenderViewHost
43 //instances associated with |web_contents|
44 static RenderViewDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
45 if (g_instances == NULL)
46 return NULL;
47 for (Instances::iterator it = g_instances.Get().begin();
48 it != g_instances.Get().end(); ++it) {
49 if ((*it)->GetWebContents() == web_contents)
50 return *it;
52 return NULL;
55 } // namespace
57 scoped_refptr<DevToolsAgentHost>
58 DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
59 RenderViewDevToolsAgentHost* result = FindAgentHost(web_contents);
60 if (!result)
61 result = new RenderViewDevToolsAgentHost(web_contents->GetRenderViewHost());
62 return result;
65 // static
66 bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
67 return FindAgentHost(web_contents) != NULL;
70 // static
71 bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
72 RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
73 return agent_host && agent_host->IsAttached();
76 //static
77 std::vector<WebContents*> DevToolsAgentHostImpl::GetInspectableWebContents() {
78 std::set<WebContents*> set;
79 scoped_ptr<RenderWidgetHostIterator> widgets(
80 RenderWidgetHost::GetRenderWidgetHosts());
81 while (RenderWidgetHost* widget = widgets->GetNextHost()) {
82 // Ignore processes that don't have a connection, such as crashed contents.
83 if (!widget->GetProcess()->HasConnection())
84 continue;
85 if (!widget->IsRenderView())
86 continue;
88 RenderViewHost* rvh = RenderViewHost::From(widget);
89 WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
90 if (web_contents)
91 set.insert(web_contents);
93 std::vector<WebContents*> result(set.size());
94 std::copy(set.begin(), set.end(), result.begin());
95 return result;
98 // static
99 void RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
100 RenderViewHost* pending,
101 RenderViewHost* current) {
102 WebContents* web_contents = WebContents::FromRenderViewHost(pending);
103 RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
104 if (!agent_host)
105 return;
106 agent_host->DisconnectRenderViewHost();
107 agent_host->ConnectRenderViewHost(current);
110 RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost(RenderViewHost* rvh)
111 : render_view_host_(NULL),
112 overrides_handler_(new RendererOverridesHandler()),
113 tracing_handler_(
114 new DevToolsTracingHandler(DevToolsTracingHandler::Renderer)),
115 power_handler_(new DevToolsPowerHandler()),
116 reattaching_(false) {
117 SetRenderViewHost(rvh);
118 DevToolsProtocol::Notifier notifier(base::Bind(
119 &RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend,
120 base::Unretained(this)));
121 overrides_handler_->SetNotifier(notifier);
122 tracing_handler_->SetNotifier(notifier);
123 power_handler_->SetNotifier(notifier);
124 g_instances.Get().push_back(this);
125 AddRef(); // Balanced in RenderViewHostDestroyed.
128 WebContents* RenderViewDevToolsAgentHost::GetWebContents() {
129 return web_contents();
132 void RenderViewDevToolsAgentHost::DispatchProtocolMessage(
133 const std::string& message) {
134 std::string error_message;
136 scoped_ptr<base::DictionaryValue> message_dict(
137 DevToolsProtocol::ParseMessage(message, &error_message));
138 scoped_refptr<DevToolsProtocol::Command> command =
139 DevToolsProtocol::ParseCommand(message_dict.get(), &error_message);
141 if (command.get()) {
142 scoped_refptr<DevToolsProtocol::Response> overridden_response;
144 DevToolsManagerDelegate* delegate =
145 DevToolsManagerImpl::GetInstance()->delegate();
146 if (delegate) {
147 scoped_ptr<base::DictionaryValue> overridden_response_value(
148 delegate->HandleCommand(this, message_dict.get()));
149 if (overridden_response_value)
150 overridden_response = DevToolsProtocol::ParseResponse(
151 overridden_response_value.get());
153 if (!overridden_response.get())
154 overridden_response = overrides_handler_->HandleCommand(command);
155 if (!overridden_response.get())
156 overridden_response = tracing_handler_->HandleCommand(command);
157 if (!overridden_response.get())
158 overridden_response = power_handler_->HandleCommand(command);
159 if (overridden_response.get()) {
160 if (!overridden_response->is_async_promise())
161 OnDispatchOnInspectorFrontend(overridden_response->Serialize());
162 return;
166 IPCDevToolsAgentHost::DispatchProtocolMessage(message);
169 void RenderViewDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
170 if (!render_view_host_)
171 return;
172 msg->set_routing_id(render_view_host_->GetRoutingID());
173 render_view_host_->Send(msg);
176 void RenderViewDevToolsAgentHost::OnClientAttached() {
177 if (!render_view_host_)
178 return;
180 InnerOnClientAttached();
182 // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when
183 // extensions::ProcessManager no longer relies on this notification.
184 if (!reattaching_)
185 DevToolsAgentHostImpl::NotifyCallbacks(this, true);
188 void RenderViewDevToolsAgentHost::InnerOnClientAttached() {
189 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
190 render_view_host_->GetProcess()->GetID());
192 #if defined(OS_ANDROID)
193 power_save_blocker_.reset(
194 static_cast<PowerSaveBlockerImpl*>(
195 PowerSaveBlocker::Create(
196 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
197 "DevTools").release()));
198 if (render_view_host_->GetView()) {
199 power_save_blocker_.get()->
200 InitDisplaySleepBlocker(render_view_host_->GetView()->GetNativeView());
202 #endif
205 void RenderViewDevToolsAgentHost::OnClientDetached() {
206 #if defined(OS_ANDROID)
207 power_save_blocker_.reset();
208 #endif
209 overrides_handler_->OnClientDetached();
210 tracing_handler_->OnClientDetached();
211 power_handler_->OnClientDetached();
212 ClientDetachedFromRenderer();
214 // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when
215 // extensions::ProcessManager no longer relies on this notification.
216 if (!reattaching_)
217 DevToolsAgentHostImpl::NotifyCallbacks(this, false);
220 void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() {
221 if (!render_view_host_)
222 return;
224 InnerClientDetachedFromRenderer();
227 void RenderViewDevToolsAgentHost::InnerClientDetachedFromRenderer() {
228 bool process_has_agents = false;
229 RenderProcessHost* render_process_host = render_view_host_->GetProcess();
230 for (Instances::iterator it = g_instances.Get().begin();
231 it != g_instances.Get().end(); ++it) {
232 if (*it == this || !(*it)->IsAttached())
233 continue;
234 RenderViewHost* rvh = (*it)->render_view_host_;
235 if (rvh && rvh->GetProcess() == render_process_host)
236 process_has_agents = true;
239 // We are the last to disconnect from the renderer -> revoke permissions.
240 if (!process_has_agents) {
241 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
242 render_process_host->GetID());
246 RenderViewDevToolsAgentHost::~RenderViewDevToolsAgentHost() {
247 Instances::iterator it = std::find(g_instances.Get().begin(),
248 g_instances.Get().end(),
249 this);
250 if (it != g_instances.Get().end())
251 g_instances.Get().erase(it);
254 void RenderViewDevToolsAgentHost::AboutToNavigateRenderView(
255 RenderViewHost* dest_rvh) {
256 if (!render_view_host_)
257 return;
259 if (render_view_host_ == dest_rvh &&
260 render_view_host_->render_view_termination_status() ==
261 base::TERMINATION_STATUS_STILL_RUNNING)
262 return;
263 ReattachToRenderViewHost(dest_rvh);
266 void RenderViewDevToolsAgentHost::RenderViewHostChanged(
267 RenderViewHost* old_host,
268 RenderViewHost* new_host) {
269 if (new_host != render_view_host_) {
270 // AboutToNavigateRenderView was not called for renderer-initiated
271 // navigation.
272 ReattachToRenderViewHost(new_host);
276 void
277 RenderViewDevToolsAgentHost::ReattachToRenderViewHost(RenderViewHost* rvh) {
278 DCHECK(!reattaching_);
279 reattaching_ = true;
280 DisconnectRenderViewHost();
281 ConnectRenderViewHost(rvh);
282 reattaching_ = false;
285 void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) {
286 if (rvh != render_view_host_)
287 return;
289 DCHECK(render_view_host_);
290 scoped_refptr<RenderViewDevToolsAgentHost> protect(this);
291 HostClosed();
292 ClearRenderViewHost();
293 Release();
296 void RenderViewDevToolsAgentHost::RenderProcessGone(
297 base::TerminationStatus status) {
298 switch(status) {
299 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
300 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
301 case base::TERMINATION_STATUS_PROCESS_CRASHED:
302 #if defined(OS_ANDROID)
303 case base::TERMINATION_STATUS_OOM_PROTECTED:
304 #endif
305 RenderViewCrashed();
306 break;
307 default:
308 break;
312 bool RenderViewDevToolsAgentHost::OnMessageReceived(
313 const IPC::Message& message,
314 RenderFrameHost* render_frame_host) {
315 return DispatchIPCMessage(message);
318 bool RenderViewDevToolsAgentHost::OnMessageReceived(
319 const IPC::Message& message) {
320 return DispatchIPCMessage(message);
323 void RenderViewDevToolsAgentHost::DidAttachInterstitialPage() {
324 overrides_handler_->DidAttachInterstitialPage();
326 if (!render_view_host_)
327 return;
328 // The rvh set in AboutToNavigateRenderView turned out to be interstitial.
329 // Connect back to the real one.
330 WebContents* web_contents =
331 WebContents::FromRenderViewHost(render_view_host_);
332 if (!web_contents)
333 return;
334 DisconnectRenderViewHost();
335 ConnectRenderViewHost(web_contents->GetRenderViewHost());
338 void RenderViewDevToolsAgentHost::DidDetachInterstitialPage() {
339 overrides_handler_->DidDetachInterstitialPage();
342 void RenderViewDevToolsAgentHost::Observe(int type,
343 const NotificationSource& source,
344 const NotificationDetails& details) {
345 if (type == content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
346 bool visible = *Details<bool>(details).ptr();
347 overrides_handler_->OnVisibilityChanged(visible);
351 void RenderViewDevToolsAgentHost::SetRenderViewHost(RenderViewHost* rvh) {
352 DCHECK(!render_view_host_);
353 render_view_host_ = static_cast<RenderViewHostImpl*>(rvh);
355 WebContentsObserver::Observe(WebContents::FromRenderViewHost(rvh));
356 overrides_handler_->SetRenderViewHost(render_view_host_);
358 registrar_.Add(
359 this,
360 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
361 content::Source<RenderWidgetHost>(render_view_host_));
364 void RenderViewDevToolsAgentHost::ClearRenderViewHost() {
365 DCHECK(render_view_host_);
366 registrar_.Remove(
367 this,
368 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
369 content::Source<RenderWidgetHost>(render_view_host_));
370 render_view_host_ = NULL;
371 overrides_handler_->ClearRenderViewHost();
374 void RenderViewDevToolsAgentHost::DisconnectWebContents() {
375 DisconnectRenderViewHost();
378 void RenderViewDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
379 ConnectRenderViewHost(wc->GetRenderViewHost());
382 DevToolsAgentHost::Type RenderViewDevToolsAgentHost::GetType() {
383 return TYPE_WEB_CONTENTS;
386 std::string RenderViewDevToolsAgentHost::GetTitle() {
387 if (WebContents* web_contents = GetWebContents())
388 return base::UTF16ToUTF8(web_contents->GetTitle());
389 return "";
392 GURL RenderViewDevToolsAgentHost::GetURL() {
393 if (WebContents* web_contents = GetWebContents())
394 return web_contents->GetVisibleURL();
395 return render_view_host_ ?
396 render_view_host_->GetMainFrame()->GetLastCommittedURL() : GURL();
399 bool RenderViewDevToolsAgentHost::Activate() {
400 if (render_view_host_) {
401 render_view_host_->GetDelegate()->Activate();
402 return true;
404 return false;
407 bool RenderViewDevToolsAgentHost::Close() {
408 if (render_view_host_) {
409 render_view_host_->ClosePage();
410 return true;
412 return false;
415 void RenderViewDevToolsAgentHost::ConnectRenderViewHost(RenderViewHost* rvh) {
416 SetRenderViewHost(rvh);
417 if (IsAttached())
418 Reattach(state_);
421 void RenderViewDevToolsAgentHost::DisconnectRenderViewHost() {
422 ClientDetachedFromRenderer();
423 ClearRenderViewHost();
426 void RenderViewDevToolsAgentHost::RenderViewCrashed() {
427 scoped_refptr<DevToolsProtocol::Notification> notification =
428 DevToolsProtocol::CreateNotification(
429 devtools::Inspector::targetCrashed::kName, NULL);
430 SendMessageToClient(notification->Serialize());
433 bool RenderViewDevToolsAgentHost::DispatchIPCMessage(
434 const IPC::Message& msg) {
435 if (!render_view_host_)
436 return false;
438 bool handled = true;
439 IPC_BEGIN_MESSAGE_MAP(RenderViewDevToolsAgentHost, msg)
440 IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
441 OnDispatchOnInspectorFrontend)
442 IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
443 OnSaveAgentRuntimeState)
444 IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame,
445 handled = false; OnSwapCompositorFrame(msg))
446 IPC_MESSAGE_UNHANDLED(handled = false)
447 IPC_END_MESSAGE_MAP()
448 return handled;
451 void RenderViewDevToolsAgentHost::OnSwapCompositorFrame(
452 const IPC::Message& message) {
453 ViewHostMsg_SwapCompositorFrame::Param param;
454 if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
455 return;
456 overrides_handler_->OnSwapCompositorFrame(param.b.metadata);
459 void RenderViewDevToolsAgentHost::SynchronousSwapCompositorFrame(
460 const cc::CompositorFrameMetadata& frame_metadata) {
461 if (!render_view_host_)
462 return;
463 overrides_handler_->OnSwapCompositorFrame(frame_metadata);
466 void RenderViewDevToolsAgentHost::OnSaveAgentRuntimeState(
467 const std::string& state) {
468 if (!render_view_host_)
469 return;
470 state_ = state;
473 void RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend(
474 const std::string& message) {
475 if (!render_view_host_)
476 return;
478 scoped_refptr<DevToolsProtocol::Notification> notification =
479 DevToolsProtocol::ParseNotification(message);
481 if (notification.get()) {
482 tracing_handler_->HandleNotification(notification);
484 SendMessageToClient(message);
487 } // namespace content