Revert of [DevTools] Migrate DevToolsTracingHandler to generated handler. (patchset...
[chromium-blink-merge.git] / content / browser / devtools / render_view_devtools_agent_host.cc
blob2aafc38c0246dd4f8877bf3af661b32664050d75
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.h"
12 #include "content/browser/devtools/devtools_protocol.h"
13 #include "content/browser/devtools/devtools_protocol_constants.h"
14 #include "content/browser/devtools/devtools_tracing_handler.h"
15 #include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
16 #include "content/browser/renderer_host/render_process_host_impl.h"
17 #include "content/browser/renderer_host/render_view_host_impl.h"
18 #include "content/browser/site_instance_impl.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/common/devtools_messages.h"
21 #include "content/common/view_messages.h"
22 #include "content/public/browser/content_browser_client.h"
23 #include "content/public/browser/devtools_manager_delegate.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/render_widget_host_iterator.h"
27 #include "content/public/browser/web_contents_delegate.h"
29 #if defined(OS_ANDROID)
30 #include "content/browser/power_save_blocker_impl.h"
31 #include "content/public/browser/render_widget_host_view.h"
32 #endif
34 namespace content {
36 typedef std::vector<RenderViewDevToolsAgentHost*> Instances;
38 namespace {
39 base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
41 //Returns RenderViewDevToolsAgentHost attached to any of RenderViewHost
42 //instances associated with |web_contents|
43 static RenderViewDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
44 if (g_instances == NULL)
45 return NULL;
46 for (Instances::iterator it = g_instances.Get().begin();
47 it != g_instances.Get().end(); ++it) {
48 if ((*it)->GetWebContents() == web_contents)
49 return *it;
51 return NULL;
54 } // namespace
56 scoped_refptr<DevToolsAgentHost>
57 DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
58 RenderViewDevToolsAgentHost* result = FindAgentHost(web_contents);
59 if (!result)
60 result = new RenderViewDevToolsAgentHost(web_contents->GetRenderViewHost());
61 return result;
64 // static
65 bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
66 return FindAgentHost(web_contents) != NULL;
69 // static
70 bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
71 RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
72 return agent_host && agent_host->IsAttached();
75 //static
76 std::vector<WebContents*> DevToolsAgentHostImpl::GetInspectableWebContents() {
77 std::set<WebContents*> set;
78 scoped_ptr<RenderWidgetHostIterator> widgets(
79 RenderWidgetHost::GetRenderWidgetHosts());
80 while (RenderWidgetHost* widget = widgets->GetNextHost()) {
81 // Ignore processes that don't have a connection, such as crashed contents.
82 if (!widget->GetProcess()->HasConnection())
83 continue;
84 if (!widget->IsRenderView())
85 continue;
87 RenderViewHost* rvh = RenderViewHost::From(widget);
88 WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
89 if (web_contents)
90 set.insert(web_contents);
92 std::vector<WebContents*> result(set.size());
93 std::copy(set.begin(), set.end(), result.begin());
94 return result;
97 // static
98 void RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
99 RenderViewHost* pending,
100 RenderViewHost* current) {
101 WebContents* web_contents = WebContents::FromRenderViewHost(pending);
102 RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
103 if (!agent_host)
104 return;
105 agent_host->DisconnectRenderViewHost();
106 agent_host->ConnectRenderViewHost(current);
109 RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost(RenderViewHost* rvh)
110 : render_view_host_(NULL),
111 dom_handler_(new devtools::dom::DOMHandler()),
112 input_handler_(new devtools::input::InputHandler()),
113 network_handler_(new devtools::network::NetworkHandler()),
114 page_handler_(new devtools::page::PageHandler()),
115 power_handler_(new devtools::power::PowerHandler()),
116 handler_impl_(new DevToolsProtocolHandlerImpl()),
117 tracing_handler_(
118 new DevToolsTracingHandler(DevToolsTracingHandler::Renderer)),
119 reattaching_(false) {
120 handler_impl_->SetDOMHandler(dom_handler_.get());
121 handler_impl_->SetInputHandler(input_handler_.get());
122 handler_impl_->SetNetworkHandler(network_handler_.get());
123 handler_impl_->SetPageHandler(page_handler_.get());
124 handler_impl_->SetPowerHandler(power_handler_.get());
125 SetRenderViewHost(rvh);
126 DevToolsProtocol::Notifier notifier(base::Bind(
127 &RenderViewDevToolsAgentHost::DispatchOnInspectorFrontend,
128 base::Unretained(this)));
129 handler_impl_->SetNotifier(notifier);
130 tracing_handler_->SetNotifier(notifier);
131 g_instances.Get().push_back(this);
132 AddRef(); // Balanced in RenderViewHostDestroyed.
133 DevToolsManager::GetInstance()->AgentHostChanged(this);
136 WebContents* RenderViewDevToolsAgentHost::GetWebContents() {
137 return web_contents();
140 void RenderViewDevToolsAgentHost::DispatchProtocolMessage(
141 const std::string& message) {
142 std::string error_message;
144 scoped_ptr<base::DictionaryValue> message_dict(
145 DevToolsProtocol::ParseMessage(message, &error_message));
146 scoped_refptr<DevToolsProtocol::Command> command =
147 DevToolsProtocol::ParseCommand(message_dict.get(), &error_message);
149 if (command.get()) {
150 scoped_refptr<DevToolsProtocol::Response> overridden_response;
152 DevToolsManagerDelegate* delegate =
153 DevToolsManager::GetInstance()->delegate();
154 if (delegate) {
155 scoped_ptr<base::DictionaryValue> overridden_response_value(
156 delegate->HandleCommand(this, message_dict.get()));
157 if (overridden_response_value)
158 overridden_response = DevToolsProtocol::ParseResponse(
159 overridden_response_value.get());
161 if (!overridden_response.get())
162 overridden_response = tracing_handler_->HandleCommand(command);
163 if (!overridden_response.get())
164 overridden_response = handler_impl_->HandleCommand(command);
165 if (overridden_response.get()) {
166 if (!overridden_response->is_async_promise())
167 DispatchOnInspectorFrontend(overridden_response->Serialize());
168 return;
172 IPCDevToolsAgentHost::DispatchProtocolMessage(message);
175 void RenderViewDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
176 if (!render_view_host_)
177 return;
178 msg->set_routing_id(render_view_host_->GetRoutingID());
179 render_view_host_->Send(msg);
182 void RenderViewDevToolsAgentHost::OnClientAttached() {
183 if (!render_view_host_)
184 return;
186 InnerOnClientAttached();
188 // TODO(kaznacheev): Move this call back to DevToolsManager when
189 // extensions::ProcessManager no longer relies on this notification.
190 if (!reattaching_)
191 DevToolsAgentHostImpl::NotifyCallbacks(this, true);
194 void RenderViewDevToolsAgentHost::InnerOnClientAttached() {
195 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
196 render_view_host_->GetProcess()->GetID());
198 #if defined(OS_ANDROID)
199 power_save_blocker_.reset(
200 static_cast<PowerSaveBlockerImpl*>(
201 PowerSaveBlocker::Create(
202 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
203 "DevTools").release()));
204 if (render_view_host_->GetView()) {
205 power_save_blocker_.get()->
206 InitDisplaySleepBlocker(render_view_host_->GetView()->GetNativeView());
208 #endif
211 void RenderViewDevToolsAgentHost::OnClientDetached() {
212 #if defined(OS_ANDROID)
213 power_save_blocker_.reset();
214 #endif
215 tracing_handler_->OnClientDetached();
216 page_handler_->Detached();
217 power_handler_->Detached();
218 ClientDetachedFromRenderer();
220 // TODO(kaznacheev): Move this call back to DevToolsManager when
221 // extensions::ProcessManager no longer relies on this notification.
222 if (!reattaching_)
223 DevToolsAgentHostImpl::NotifyCallbacks(this, false);
226 void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() {
227 if (!render_view_host_)
228 return;
230 InnerClientDetachedFromRenderer();
233 void RenderViewDevToolsAgentHost::InnerClientDetachedFromRenderer() {
234 bool process_has_agents = false;
235 RenderProcessHost* render_process_host = render_view_host_->GetProcess();
236 for (Instances::iterator it = g_instances.Get().begin();
237 it != g_instances.Get().end(); ++it) {
238 if (*it == this || !(*it)->IsAttached())
239 continue;
240 RenderViewHost* rvh = (*it)->render_view_host_;
241 if (rvh && rvh->GetProcess() == render_process_host)
242 process_has_agents = true;
245 // We are the last to disconnect from the renderer -> revoke permissions.
246 if (!process_has_agents) {
247 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
248 render_process_host->GetID());
252 RenderViewDevToolsAgentHost::~RenderViewDevToolsAgentHost() {
253 Instances::iterator it = std::find(g_instances.Get().begin(),
254 g_instances.Get().end(),
255 this);
256 if (it != g_instances.Get().end())
257 g_instances.Get().erase(it);
260 void RenderViewDevToolsAgentHost::AboutToNavigateRenderView(
261 RenderViewHost* dest_rvh) {
262 if (!render_view_host_)
263 return;
265 if (render_view_host_ == dest_rvh &&
266 render_view_host_->render_view_termination_status() ==
267 base::TERMINATION_STATUS_STILL_RUNNING)
268 return;
269 ReattachToRenderViewHost(dest_rvh);
272 void RenderViewDevToolsAgentHost::RenderViewHostChanged(
273 RenderViewHost* old_host,
274 RenderViewHost* new_host) {
275 if (new_host != render_view_host_) {
276 // AboutToNavigateRenderView was not called for renderer-initiated
277 // navigation.
278 ReattachToRenderViewHost(new_host);
282 void
283 RenderViewDevToolsAgentHost::ReattachToRenderViewHost(RenderViewHost* rvh) {
284 DCHECK(!reattaching_);
285 reattaching_ = true;
286 DisconnectRenderViewHost();
287 ConnectRenderViewHost(rvh);
288 reattaching_ = false;
291 void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) {
292 if (rvh != render_view_host_)
293 return;
295 DCHECK(render_view_host_);
296 scoped_refptr<RenderViewDevToolsAgentHost> protect(this);
297 HostClosed();
298 ClearRenderViewHost();
299 DevToolsManager::GetInstance()->AgentHostChanged(this);
300 Release();
303 void RenderViewDevToolsAgentHost::RenderProcessGone(
304 base::TerminationStatus status) {
305 switch(status) {
306 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
307 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
308 case base::TERMINATION_STATUS_PROCESS_CRASHED:
309 #if defined(OS_ANDROID)
310 case base::TERMINATION_STATUS_OOM_PROTECTED:
311 #endif
312 RenderViewCrashed();
313 break;
314 default:
315 break;
319 bool RenderViewDevToolsAgentHost::OnMessageReceived(
320 const IPC::Message& message,
321 RenderFrameHost* render_frame_host) {
322 return DispatchIPCMessage(message);
325 bool RenderViewDevToolsAgentHost::OnMessageReceived(
326 const IPC::Message& message) {
327 return DispatchIPCMessage(message);
330 void RenderViewDevToolsAgentHost::DidAttachInterstitialPage() {
331 page_handler_->DidAttachInterstitialPage();
333 if (!render_view_host_)
334 return;
335 // The rvh set in AboutToNavigateRenderView turned out to be interstitial.
336 // Connect back to the real one.
337 WebContents* web_contents =
338 WebContents::FromRenderViewHost(render_view_host_);
339 if (!web_contents)
340 return;
341 DisconnectRenderViewHost();
342 ConnectRenderViewHost(web_contents->GetRenderViewHost());
345 void RenderViewDevToolsAgentHost::DidDetachInterstitialPage() {
346 page_handler_->DidDetachInterstitialPage();
349 void RenderViewDevToolsAgentHost::TitleWasSet(
350 NavigationEntry* entry, bool explicit_set) {
351 DevToolsManager::GetInstance()->AgentHostChanged(this);
354 void RenderViewDevToolsAgentHost::NavigationEntryCommitted(
355 const LoadCommittedDetails& load_details) {
356 DevToolsManager::GetInstance()->AgentHostChanged(this);
359 void RenderViewDevToolsAgentHost::Observe(int type,
360 const NotificationSource& source,
361 const NotificationDetails& details) {
362 if (type == content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
363 bool visible = *Details<bool>(details).ptr();
364 page_handler_->OnVisibilityChanged(visible);
368 void RenderViewDevToolsAgentHost::SetRenderViewHost(RenderViewHost* rvh) {
369 DCHECK(!render_view_host_);
370 render_view_host_ = static_cast<RenderViewHostImpl*>(rvh);
372 WebContentsObserver::Observe(WebContents::FromRenderViewHost(rvh));
373 dom_handler_->SetRenderViewHost(render_view_host_);
374 input_handler_->SetRenderViewHost(render_view_host_);
375 network_handler_->SetRenderViewHost(render_view_host_);
376 page_handler_->SetRenderViewHost(render_view_host_);
378 registrar_.Add(
379 this,
380 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
381 content::Source<RenderWidgetHost>(render_view_host_));
384 void RenderViewDevToolsAgentHost::ClearRenderViewHost() {
385 DCHECK(render_view_host_);
386 registrar_.Remove(
387 this,
388 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
389 content::Source<RenderWidgetHost>(render_view_host_));
390 render_view_host_ = nullptr;
391 dom_handler_->SetRenderViewHost(nullptr);
392 input_handler_->SetRenderViewHost(nullptr);
393 network_handler_->SetRenderViewHost(nullptr);
394 page_handler_->SetRenderViewHost(nullptr);
397 void RenderViewDevToolsAgentHost::DisconnectWebContents() {
398 DisconnectRenderViewHost();
401 void RenderViewDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
402 ConnectRenderViewHost(wc->GetRenderViewHost());
405 DevToolsAgentHost::Type RenderViewDevToolsAgentHost::GetType() {
406 return TYPE_WEB_CONTENTS;
409 std::string RenderViewDevToolsAgentHost::GetTitle() {
410 if (WebContents* web_contents = GetWebContents())
411 return base::UTF16ToUTF8(web_contents->GetTitle());
412 return "";
415 GURL RenderViewDevToolsAgentHost::GetURL() {
416 if (WebContents* web_contents = GetWebContents())
417 return web_contents->GetVisibleURL();
418 return render_view_host_ ?
419 render_view_host_->GetMainFrame()->GetLastCommittedURL() : GURL();
422 bool RenderViewDevToolsAgentHost::Activate() {
423 if (render_view_host_) {
424 render_view_host_->GetDelegate()->Activate();
425 return true;
427 return false;
430 bool RenderViewDevToolsAgentHost::Close() {
431 if (render_view_host_) {
432 render_view_host_->ClosePage();
433 return true;
435 return false;
438 void RenderViewDevToolsAgentHost::ConnectRenderViewHost(RenderViewHost* rvh) {
439 SetRenderViewHost(rvh);
440 if (IsAttached())
441 Reattach(state_);
444 void RenderViewDevToolsAgentHost::DisconnectRenderViewHost() {
445 ClientDetachedFromRenderer();
446 ClearRenderViewHost();
449 void RenderViewDevToolsAgentHost::RenderViewCrashed() {
450 scoped_refptr<DevToolsProtocol::Notification> notification =
451 DevToolsProtocol::CreateNotification(
452 devtools::Inspector::targetCrashed::kName, NULL);
453 SendMessageToClient(notification->Serialize());
456 bool RenderViewDevToolsAgentHost::DispatchIPCMessage(
457 const IPC::Message& msg) {
458 if (!render_view_host_)
459 return false;
461 bool handled = true;
462 IPC_BEGIN_MESSAGE_MAP(RenderViewDevToolsAgentHost, msg)
463 IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
464 OnDispatchOnInspectorFrontend)
465 IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
466 OnSaveAgentRuntimeState)
467 IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame,
468 handled = false; OnSwapCompositorFrame(msg))
469 IPC_MESSAGE_UNHANDLED(handled = false)
470 IPC_END_MESSAGE_MAP()
471 return handled;
474 void RenderViewDevToolsAgentHost::OnSwapCompositorFrame(
475 const IPC::Message& message) {
476 ViewHostMsg_SwapCompositorFrame::Param param;
477 if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
478 return;
479 page_handler_->OnSwapCompositorFrame(param.b.metadata);
482 void RenderViewDevToolsAgentHost::SynchronousSwapCompositorFrame(
483 const cc::CompositorFrameMetadata& frame_metadata) {
484 if (!render_view_host_)
485 return;
486 page_handler_->OnSwapCompositorFrame(frame_metadata);
489 void RenderViewDevToolsAgentHost::OnSaveAgentRuntimeState(
490 const std::string& state) {
491 if (!render_view_host_)
492 return;
493 state_ = state;
496 void RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend(
497 const std::string& message,
498 uint32 total_size) {
499 if (!IsAttached() || !render_view_host_)
500 return;
501 ProcessChunkedMessageFromAgent(message, total_size);
504 void RenderViewDevToolsAgentHost::DispatchOnInspectorFrontend(
505 const std::string& message) {
506 if (!IsAttached() || !render_view_host_)
507 return;
508 SendMessageToClient(message);
511 } // namespace content