Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / devtools / render_view_devtools_agent_host.cc
blobf3eaf3a76bf05ccd47592f950a5596f95f294fee
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 "content/browser/child_process_security_policy_impl.h"
10 #include "content/browser/devtools/devtools_manager_impl.h"
11 #include "content/browser/devtools/devtools_power_handler.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/renderer_overrides_handler.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/notification_service.h"
24 #include "content/public/browser/notification_types.h"
25 #include "content/public/browser/render_widget_host_iterator.h"
27 #if defined(OS_ANDROID)
28 #include "content/browser/power_save_blocker_impl.h"
29 #include "content/public/browser/render_widget_host_view.h"
30 #endif
32 namespace content {
34 typedef std::vector<RenderViewDevToolsAgentHost*> Instances;
36 namespace {
37 base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
39 //Returns RenderViewDevToolsAgentHost attached to any of RenderViewHost
40 //instances associated with |web_contents|
41 static RenderViewDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
42 if (g_instances == NULL)
43 return NULL;
44 RenderViewHostDelegate* delegate =
45 static_cast<WebContentsImpl*>(web_contents);
46 for (Instances::iterator it = g_instances.Get().begin();
47 it != g_instances.Get().end(); ++it) {
48 RenderViewHost* rvh = (*it)->render_view_host();
49 if (rvh && rvh->GetDelegate() == delegate)
50 return *it;
52 return NULL;
55 static RenderViewDevToolsAgentHost* FindAgentHost(RenderViewHost* rvh) {
56 if (g_instances == NULL)
57 return NULL;
58 for (Instances::iterator it = g_instances.Get().begin();
59 it != g_instances.Get().end(); ++it) {
60 if (rvh == (*it)->render_view_host())
61 return *it;
63 return NULL;
66 } // namespace
68 scoped_refptr<DevToolsAgentHost>
69 DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
70 RenderViewDevToolsAgentHost* result = FindAgentHost(web_contents);
71 if (!result)
72 result = new RenderViewDevToolsAgentHost(web_contents->GetRenderViewHost());
73 return result;
76 // static
77 scoped_refptr<DevToolsAgentHost>
78 DevToolsAgentHost::GetOrCreateFor(RenderViewHost* rvh) {
79 RenderViewDevToolsAgentHost* result = FindAgentHost(rvh);
80 if (!result)
81 result = new RenderViewDevToolsAgentHost(rvh);
82 return result;
85 // static
86 bool DevToolsAgentHost::HasFor(RenderViewHost* rvh) {
87 return FindAgentHost(rvh) != NULL;
90 // static
91 bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
92 if (g_instances == NULL)
93 return false;
94 DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
95 if (!devtools_manager)
96 return false;
97 RenderViewHostDelegate* delegate =
98 static_cast<WebContentsImpl*>(web_contents);
99 for (Instances::iterator it = g_instances.Get().begin();
100 it != g_instances.Get().end(); ++it) {
101 RenderViewHost* rvh = (*it)->render_view_host_;
102 if (rvh && rvh->GetDelegate() != delegate)
103 continue;
104 if ((*it)->IsAttached())
105 return true;
107 return false;
110 //static
111 std::vector<RenderViewHost*> DevToolsAgentHost::GetValidRenderViewHosts() {
112 std::vector<RenderViewHost*> result;
113 scoped_ptr<RenderWidgetHostIterator> widgets(
114 RenderWidgetHost::GetRenderWidgetHosts());
115 while (RenderWidgetHost* widget = widgets->GetNextHost()) {
116 // Ignore processes that don't have a connection, such as crashed contents.
117 if (!widget->GetProcess()->HasConnection())
118 continue;
119 if (!widget->IsRenderView())
120 continue;
122 RenderViewHost* rvh = RenderViewHost::From(widget);
123 WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
124 if (!web_contents)
125 continue;
127 // Don't report a RenderViewHost if it is not the current RenderViewHost
128 // for some WebContents (this filters out pre-render RVHs and similar).
129 // However report a RenderViewHost created for an out of process iframe.
130 // TODO (kaznacheev): Revisit this when it is clear how OOP iframes
131 // interact with pre-rendering.
132 // TODO (kaznacheev): GetMainFrame() call is a temporary hack. Iterate over
133 // all RenderFrameHost instances when multiple OOP frames are supported.
134 if (rvh != web_contents->GetRenderViewHost() &&
135 !rvh->GetMainFrame()->IsCrossProcessSubframe()) {
136 continue;
139 result.push_back(rvh);
141 return result;
144 // static
145 void RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
146 RenderViewHost* pending,
147 RenderViewHost* current) {
148 RenderViewDevToolsAgentHost* agent_host = FindAgentHost(pending);
149 if (!agent_host)
150 return;
151 agent_host->DisconnectRenderViewHost();
152 agent_host->ConnectRenderViewHost(current);
155 // static
156 bool RenderViewDevToolsAgentHost::DispatchIPCMessage(
157 RenderViewHost* source,
158 const IPC::Message& message) {
159 RenderViewDevToolsAgentHost* agent_host = FindAgentHost(source);
160 return agent_host && agent_host->DispatchIPCMessage(message);
163 RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost(
164 RenderViewHost* rvh)
165 : render_view_host_(NULL),
166 overrides_handler_(new RendererOverridesHandler(this)),
167 tracing_handler_(new DevToolsTracingHandler()),
168 power_handler_(new DevToolsPowerHandler())
170 SetRenderViewHost(rvh);
171 DevToolsProtocol::Notifier notifier(base::Bind(
172 &RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend,
173 base::Unretained(this)));
174 overrides_handler_->SetNotifier(notifier);
175 tracing_handler_->SetNotifier(notifier);
176 power_handler_->SetNotifier(notifier);
177 g_instances.Get().push_back(this);
178 AddRef(); // Balanced in RenderViewHostDestroyed.
181 RenderViewHost* RenderViewDevToolsAgentHost::GetRenderViewHost() {
182 return render_view_host_;
185 void RenderViewDevToolsAgentHost::DispatchOnInspectorBackend(
186 const std::string& message) {
187 std::string error_message;
188 scoped_refptr<DevToolsProtocol::Command> command =
189 DevToolsProtocol::ParseCommand(message, &error_message);
191 if (command) {
192 scoped_refptr<DevToolsProtocol::Response> overridden_response =
193 overrides_handler_->HandleCommand(command);
194 if (!overridden_response)
195 overridden_response = tracing_handler_->HandleCommand(command);
196 if (!overridden_response)
197 overridden_response = power_handler_->HandleCommand(command);
198 if (overridden_response) {
199 if (!overridden_response->is_async_promise())
200 OnDispatchOnInspectorFrontend(overridden_response->Serialize());
201 return;
205 IPCDevToolsAgentHost::DispatchOnInspectorBackend(message);
208 void RenderViewDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
209 if (!render_view_host_)
210 return;
211 msg->set_routing_id(render_view_host_->GetRoutingID());
212 render_view_host_->Send(msg);
215 void RenderViewDevToolsAgentHost::OnClientAttached() {
216 if (!render_view_host_)
217 return;
219 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
220 render_view_host_->GetProcess()->GetID());
222 // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when
223 // extensions::ProcessManager no longer relies on this notification.
224 DevToolsManagerImpl::GetInstance()->NotifyObservers(this, true);
226 #if defined(OS_ANDROID)
227 power_save_blocker_.reset(
228 static_cast<PowerSaveBlockerImpl*>(
229 PowerSaveBlocker::Create(
230 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
231 "DevTools").release()));
232 if (render_view_host_->GetView()) {
233 power_save_blocker_.get()->
234 InitDisplaySleepBlocker(render_view_host_->GetView()->GetNativeView());
236 #endif
239 void RenderViewDevToolsAgentHost::OnClientDetached() {
240 #if defined(OS_ANDROID)
241 power_save_blocker_.reset();
242 #endif
243 overrides_handler_->OnClientDetached();
244 ClientDetachedFromRenderer();
247 void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() {
248 if (!render_view_host_)
249 return;
251 bool process_has_agents = false;
252 RenderProcessHost* render_process_host = render_view_host_->GetProcess();
253 for (Instances::iterator it = g_instances.Get().begin();
254 it != g_instances.Get().end(); ++it) {
255 if (*it == this || !(*it)->IsAttached())
256 continue;
257 RenderViewHost* rvh = (*it)->render_view_host();
258 if (rvh && rvh->GetProcess() == render_process_host)
259 process_has_agents = true;
262 // We are the last to disconnect from the renderer -> revoke permissions.
263 if (!process_has_agents) {
264 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
265 render_process_host->GetID());
268 // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when
269 // extensions::ProcessManager no longer relies on this notification.
270 DevToolsManagerImpl::GetInstance()->NotifyObservers(this, false);
273 RenderViewDevToolsAgentHost::~RenderViewDevToolsAgentHost() {
274 Instances::iterator it = std::find(g_instances.Get().begin(),
275 g_instances.Get().end(),
276 this);
277 if (it != g_instances.Get().end())
278 g_instances.Get().erase(it);
281 void RenderViewDevToolsAgentHost::AboutToNavigateRenderView(
282 RenderViewHost* dest_rvh) {
283 if (!render_view_host_)
284 return;
286 if (render_view_host_ == dest_rvh && static_cast<RenderViewHostImpl*>(
287 render_view_host_)->render_view_termination_status() ==
288 base::TERMINATION_STATUS_STILL_RUNNING)
289 return;
290 DisconnectRenderViewHost();
291 ConnectRenderViewHost(dest_rvh);
294 void RenderViewDevToolsAgentHost::RenderViewHostChanged(
295 RenderViewHost* old_host,
296 RenderViewHost* new_host) {
297 if (new_host != render_view_host_) {
298 // AboutToNavigateRenderView was not called for renderer-initiated
299 // navigation.
300 DisconnectRenderViewHost();
301 ConnectRenderViewHost(new_host);
305 void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) {
306 if (rvh != render_view_host_)
307 return;
309 DCHECK(render_view_host_);
310 scoped_refptr<RenderViewDevToolsAgentHost> protect(this);
311 NotifyCloseListener();
312 ClearRenderViewHost();
313 Release();
316 void RenderViewDevToolsAgentHost::RenderProcessGone(
317 base::TerminationStatus status) {
318 switch(status) {
319 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
320 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
321 case base::TERMINATION_STATUS_PROCESS_CRASHED:
322 #if defined(OS_ANDROID)
323 case base::TERMINATION_STATUS_OOM_PROTECTED:
324 #endif
325 RenderViewCrashed();
326 break;
327 default:
328 break;
332 void RenderViewDevToolsAgentHost::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::Observe(int type,
346 const NotificationSource& source,
347 const NotificationDetails& details) {
348 if (type == content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
349 bool visible = *Details<bool>(details).ptr();
350 overrides_handler_->OnVisibilityChanged(visible);
354 void RenderViewDevToolsAgentHost::SetRenderViewHost(RenderViewHost* rvh) {
355 DCHECK(!render_view_host_);
356 render_view_host_ = rvh;
358 WebContentsObserver::Observe(WebContents::FromRenderViewHost(rvh));
360 registrar_.Add(
361 this,
362 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
363 content::Source<RenderWidgetHost>(render_view_host_));
366 void RenderViewDevToolsAgentHost::ClearRenderViewHost() {
367 DCHECK(render_view_host_);
368 registrar_.Remove(
369 this,
370 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
371 content::Source<RenderWidgetHost>(render_view_host_));
372 render_view_host_ = NULL;
375 void RenderViewDevToolsAgentHost::ConnectRenderViewHost(RenderViewHost* rvh) {
376 SetRenderViewHost(rvh);
377 if (IsAttached())
378 Reattach(state_);
381 void RenderViewDevToolsAgentHost::DisconnectRenderViewHost() {
382 ClientDetachedFromRenderer();
383 ClearRenderViewHost();
386 void RenderViewDevToolsAgentHost::RenderViewCrashed() {
387 scoped_refptr<DevToolsProtocol::Notification> notification =
388 DevToolsProtocol::CreateNotification(
389 devtools::Inspector::targetCrashed::kName, NULL);
390 DevToolsManagerImpl::GetInstance()->
391 DispatchOnInspectorFrontend(this, notification->Serialize());
394 bool RenderViewDevToolsAgentHost::DispatchIPCMessage(
395 const IPC::Message& msg) {
396 if (!render_view_host_)
397 return false;
399 bool handled = true;
400 IPC_BEGIN_MESSAGE_MAP(RenderViewDevToolsAgentHost, msg)
401 IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
402 OnDispatchOnInspectorFrontend)
403 IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
404 OnSaveAgentRuntimeState)
405 IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame,
406 handled = false; OnSwapCompositorFrame(msg))
407 IPC_MESSAGE_UNHANDLED(handled = false)
408 IPC_END_MESSAGE_MAP()
409 return handled;
412 void RenderViewDevToolsAgentHost::OnSwapCompositorFrame(
413 const IPC::Message& message) {
414 ViewHostMsg_SwapCompositorFrame::Param param;
415 if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
416 return;
417 overrides_handler_->OnSwapCompositorFrame(param.b.metadata);
420 void RenderViewDevToolsAgentHost::SynchronousSwapCompositorFrame(
421 const cc::CompositorFrameMetadata& frame_metadata) {
422 if (!render_view_host_)
423 return;
424 overrides_handler_->OnSwapCompositorFrame(frame_metadata);
427 void RenderViewDevToolsAgentHost::OnSaveAgentRuntimeState(
428 const std::string& state) {
429 if (!render_view_host_)
430 return;
431 state_ = state;
434 void RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend(
435 const std::string& message) {
436 if (!render_view_host_)
437 return;
438 DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(
439 this, message);
442 } // namespace content