ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / devtools / render_frame_devtools_agent_host.cc
blobe5e7ce7a2ede15d91b7af435ee81215f7ccc8ee0
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/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_frame_trace_recorder.h"
13 #include "content/browser/devtools/devtools_manager.h"
14 #include "content/browser/devtools/protocol/devtools_protocol_handler.h"
15 #include "content/browser/devtools/protocol/dom_handler.h"
16 #include "content/browser/devtools/protocol/input_handler.h"
17 #include "content/browser/devtools/protocol/inspector_handler.h"
18 #include "content/browser/devtools/protocol/network_handler.h"
19 #include "content/browser/devtools/protocol/page_handler.h"
20 #include "content/browser/devtools/protocol/power_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/devtools_manager_delegate.h"
31 #include "content/public/browser/notification_service.h"
32 #include "content/public/browser/notification_types.h"
33 #include "content/public/browser/render_widget_host_iterator.h"
34 #include "content/public/browser/web_contents_delegate.h"
36 #if defined(OS_ANDROID)
37 #include "content/browser/power_save_blocker_impl.h"
38 #include "content/public/browser/render_widget_host_view.h"
39 #endif
41 namespace content {
43 typedef std::vector<RenderFrameDevToolsAgentHost*> Instances;
45 namespace {
46 base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
48 static RenderFrameDevToolsAgentHost* FindAgentHost(RenderFrameHost* host) {
49 if (g_instances == NULL)
50 return NULL;
51 for (Instances::iterator it = g_instances.Get().begin();
52 it != g_instances.Get().end(); ++it) {
53 if ((*it)->HasRenderFrameHost(host))
54 return *it;
56 return NULL;
59 // Returns RenderFrameDevToolsAgentHost attached to any of RenderFrameHost
60 // instances associated with |web_contents|
61 static RenderFrameDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
62 if (g_instances == NULL)
63 return NULL;
64 for (Instances::iterator it = g_instances.Get().begin();
65 it != g_instances.Get().end(); ++it) {
66 if ((*it)->GetWebContents() == web_contents)
67 return *it;
69 return NULL;
72 } // namespace
74 scoped_refptr<DevToolsAgentHost>
75 DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
76 RenderFrameDevToolsAgentHost* result = FindAgentHost(web_contents);
77 if (!result)
78 result = new RenderFrameDevToolsAgentHost(web_contents->GetMainFrame());
79 return result;
82 // static
83 bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
84 return FindAgentHost(web_contents) != NULL;
87 // static
88 bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
89 RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
90 return agent_host && agent_host->IsAttached();
93 //static
94 std::vector<WebContents*> DevToolsAgentHostImpl::GetInspectableWebContents() {
95 std::set<WebContents*> set;
96 scoped_ptr<RenderWidgetHostIterator> widgets(
97 RenderWidgetHost::GetRenderWidgetHosts());
98 while (RenderWidgetHost* widget = widgets->GetNextHost()) {
99 // Ignore processes that don't have a connection, such as crashed contents.
100 if (!widget->GetProcess()->HasConnection())
101 continue;
102 if (!widget->IsRenderView())
103 continue;
105 RenderViewHost* rvh = RenderViewHost::From(widget);
106 WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
107 if (web_contents)
108 set.insert(web_contents);
110 std::vector<WebContents*> result(set.size());
111 std::copy(set.begin(), set.end(), result.begin());
112 return result;
115 // static
116 void RenderFrameDevToolsAgentHost::OnCancelPendingNavigation(
117 RenderFrameHost* pending,
118 RenderFrameHost* current) {
119 RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(pending);
120 if (!agent_host)
121 return;
122 agent_host->DisconnectRenderFrameHost();
123 agent_host->ConnectRenderFrameHost(current);
126 RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(RenderFrameHost* rfh)
127 : render_frame_host_(NULL),
128 dom_handler_(new devtools::dom::DOMHandler()),
129 input_handler_(new devtools::input::InputHandler()),
130 inspector_handler_(new devtools::inspector::InspectorHandler()),
131 network_handler_(new devtools::network::NetworkHandler()),
132 page_handler_(new devtools::page::PageHandler()),
133 power_handler_(new devtools::power::PowerHandler()),
134 tracing_handler_(new devtools::tracing::TracingHandler(
135 devtools::tracing::TracingHandler::Renderer)),
136 protocol_handler_(new DevToolsProtocolHandler(
137 base::Bind(&RenderFrameDevToolsAgentHost::DispatchOnInspectorFrontend,
138 base::Unretained(this)))),
139 frame_trace_recorder_(new DevToolsFrameTraceRecorder()),
140 reattaching_(false) {
141 DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
142 dispatcher->SetDOMHandler(dom_handler_.get());
143 dispatcher->SetInputHandler(input_handler_.get());
144 dispatcher->SetInspectorHandler(inspector_handler_.get());
145 dispatcher->SetNetworkHandler(network_handler_.get());
146 dispatcher->SetPageHandler(page_handler_.get());
147 dispatcher->SetPowerHandler(power_handler_.get());
148 dispatcher->SetTracingHandler(tracing_handler_.get());
149 SetRenderFrameHost(rfh);
150 g_instances.Get().push_back(this);
151 AddRef(); // Balanced in RenderFrameHostDestroyed.
152 DevToolsManager::GetInstance()->AgentHostChanged(this);
155 BrowserContext* RenderFrameDevToolsAgentHost::GetBrowserContext() {
156 WebContents* contents = web_contents();
157 return contents ? contents->GetBrowserContext() : nullptr;
160 WebContents* RenderFrameDevToolsAgentHost::GetWebContents() {
161 return web_contents();
164 void RenderFrameDevToolsAgentHost::DispatchProtocolMessage(
165 const std::string& message) {
166 scoped_ptr<base::DictionaryValue> command =
167 protocol_handler_->ParseCommand(message);
168 if (!command)
169 return;
171 DevToolsManagerDelegate* delegate =
172 DevToolsManager::GetInstance()->delegate();
173 if (delegate) {
174 scoped_ptr<base::DictionaryValue> response(
175 delegate->HandleCommand(this, command.get()));
176 if (response) {
177 std::string json_response;
178 base::JSONWriter::Write(response.get(), &json_response);
179 DispatchOnInspectorFrontend(json_response);
180 return;
184 if (protocol_handler_->HandleOptionalCommand(command.Pass()))
185 return;
187 IPCDevToolsAgentHost::DispatchProtocolMessage(message);
190 void RenderFrameDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
191 if (!render_frame_host_)
192 return;
193 msg->set_routing_id(render_frame_host_->GetRoutingID());
194 render_frame_host_->Send(msg);
197 void RenderFrameDevToolsAgentHost::OnClientAttached() {
198 if (!render_frame_host_)
199 return;
201 InnerOnClientAttached();
203 // TODO(kaznacheev): Move this call back to DevToolsManager when
204 // extensions::ProcessManager no longer relies on this notification.
205 if (!reattaching_)
206 DevToolsAgentHostImpl::NotifyCallbacks(this, true);
209 void RenderFrameDevToolsAgentHost::InnerOnClientAttached() {
210 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
211 render_frame_host_->GetProcess()->GetID());
213 #if defined(OS_ANDROID)
214 power_save_blocker_.reset(static_cast<PowerSaveBlockerImpl*>(
215 PowerSaveBlocker::Create(
216 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
217 PowerSaveBlocker::kReasonOther, "DevTools").release()));
218 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
219 render_frame_host_->GetRenderViewHost());
220 if (rvh->GetView()) {
221 power_save_blocker_.get()->
222 InitDisplaySleepBlocker(rvh->GetView()->GetNativeView());
224 #endif
227 void RenderFrameDevToolsAgentHost::OnClientDetached() {
228 #if defined(OS_ANDROID)
229 power_save_blocker_.reset();
230 #endif
231 page_handler_->Detached();
232 power_handler_->Detached();
233 tracing_handler_->Detached();
234 ClientDetachedFromRenderer();
236 // TODO(kaznacheev): Move this call back to DevToolsManager when
237 // extensions::ProcessManager no longer relies on this notification.
238 if (!reattaching_)
239 DevToolsAgentHostImpl::NotifyCallbacks(this, false);
242 void RenderFrameDevToolsAgentHost::ClientDetachedFromRenderer() {
243 if (!render_frame_host_)
244 return;
246 InnerClientDetachedFromRenderer();
249 void RenderFrameDevToolsAgentHost::InnerClientDetachedFromRenderer() {
250 bool process_has_agents = false;
251 RenderProcessHost* render_process_host = render_frame_host_->GetProcess();
252 for (Instances::iterator it = g_instances.Get().begin();
253 it != g_instances.Get().end(); ++it) {
254 if (*it == this || !(*it)->IsAttached())
255 continue;
256 RenderFrameHost* rfh = (*it)->render_frame_host_;
257 if (rfh && rfh->GetProcess() == render_process_host)
258 process_has_agents = true;
261 // We are the last to disconnect from the renderer -> revoke permissions.
262 if (!process_has_agents) {
263 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
264 render_process_host->GetID());
268 RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() {
269 Instances::iterator it = std::find(g_instances.Get().begin(),
270 g_instances.Get().end(),
271 this);
272 if (it != g_instances.Get().end())
273 g_instances.Get().erase(it);
276 // TODO(creis): Consider removing this in favor of RenderFrameHostChanged.
277 void RenderFrameDevToolsAgentHost::AboutToNavigateRenderFrame(
278 RenderFrameHost* old_host,
279 RenderFrameHost* new_host) {
280 if (render_frame_host_ != old_host)
281 return;
283 // TODO(creis): This will need to be updated for --site-per-process, since
284 // RenderViewHost is going away and navigations could happen in any frame.
285 if (render_frame_host_ == new_host) {
286 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
287 render_frame_host_->GetRenderViewHost());
288 if (rvh->render_view_termination_status() ==
289 base::TERMINATION_STATUS_STILL_RUNNING)
290 return;
292 ReattachToRenderFrameHost(new_host);
295 void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
296 RenderFrameHost* old_host,
297 RenderFrameHost* new_host) {
298 if (old_host == render_frame_host_ && new_host != render_frame_host_) {
299 // AboutToNavigateRenderFrame was not called for renderer-initiated
300 // navigation.
301 ReattachToRenderFrameHost(new_host);
305 void
306 RenderFrameDevToolsAgentHost::ReattachToRenderFrameHost(RenderFrameHost* rfh) {
307 DCHECK(!reattaching_);
308 reattaching_ = true;
309 DisconnectRenderFrameHost();
310 ConnectRenderFrameHost(rfh);
311 reattaching_ = false;
314 void RenderFrameDevToolsAgentHost::FrameDeleted(RenderFrameHost* rfh) {
315 if (rfh != render_frame_host_)
316 return;
318 DCHECK(render_frame_host_);
319 scoped_refptr<RenderFrameDevToolsAgentHost> protect(this);
320 HostClosed();
321 ClearRenderFrameHost();
322 DevToolsManager::GetInstance()->AgentHostChanged(this);
323 Release();
326 void RenderFrameDevToolsAgentHost::RenderProcessGone(
327 base::TerminationStatus status) {
328 switch(status) {
329 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
330 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
331 case base::TERMINATION_STATUS_PROCESS_CRASHED:
332 #if defined(OS_ANDROID)
333 case base::TERMINATION_STATUS_OOM_PROTECTED:
334 #endif
335 RenderFrameCrashed();
336 break;
337 default:
338 break;
342 bool RenderFrameDevToolsAgentHost::OnMessageReceived(
343 const IPC::Message& message) {
344 if (!render_frame_host_)
345 return false;
346 if (message.type() == ViewHostMsg_SwapCompositorFrame::ID)
347 OnSwapCompositorFrame(message);
348 return false;
351 bool RenderFrameDevToolsAgentHost::OnMessageReceived(
352 const IPC::Message& message,
353 RenderFrameHost* render_frame_host) {
354 if (!render_frame_host_ || render_frame_host != render_frame_host_)
355 return false;
357 bool handled = true;
358 IPC_BEGIN_MESSAGE_MAP(RenderFrameDevToolsAgentHost, message)
359 IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
360 OnDispatchOnInspectorFrontend)
361 IPC_MESSAGE_UNHANDLED(handled = false)
362 IPC_END_MESSAGE_MAP()
363 return handled;
366 void RenderFrameDevToolsAgentHost::DidAttachInterstitialPage() {
367 page_handler_->DidAttachInterstitialPage();
369 if (!render_frame_host_)
370 return;
371 // The rvh set in AboutToNavigateRenderFrame turned out to be interstitial.
372 // Connect back to the real one.
373 WebContents* web_contents =
374 WebContents::FromRenderFrameHost(render_frame_host_);
375 if (!web_contents)
376 return;
377 DisconnectRenderFrameHost();
378 ConnectRenderFrameHost(web_contents->GetMainFrame());
381 void RenderFrameDevToolsAgentHost::DidDetachInterstitialPage() {
382 page_handler_->DidDetachInterstitialPage();
385 void RenderFrameDevToolsAgentHost::TitleWasSet(
386 NavigationEntry* entry, bool explicit_set) {
387 DevToolsManager::GetInstance()->AgentHostChanged(this);
390 void RenderFrameDevToolsAgentHost::NavigationEntryCommitted(
391 const LoadCommittedDetails& load_details) {
392 DevToolsManager::GetInstance()->AgentHostChanged(this);
395 void RenderFrameDevToolsAgentHost::Observe(int type,
396 const NotificationSource& source,
397 const NotificationDetails& details) {
398 if (type == content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
399 bool visible = *Details<bool>(details).ptr();
400 page_handler_->OnVisibilityChanged(visible);
404 void RenderFrameDevToolsAgentHost::SetRenderFrameHost(RenderFrameHost* rfh) {
405 DCHECK(!render_frame_host_);
406 render_frame_host_ = static_cast<RenderFrameHostImpl*>(rfh);
408 WebContentsObserver::Observe(WebContents::FromRenderFrameHost(rfh));
409 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
410 rfh->GetRenderViewHost());
411 dom_handler_->SetRenderViewHost(rvh);
412 input_handler_->SetRenderViewHost(rvh);
413 network_handler_->SetRenderViewHost(rvh);
414 page_handler_->SetRenderViewHost(rvh);
416 registrar_.Add(
417 this,
418 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
419 content::Source<RenderWidgetHost>(rvh));
422 void RenderFrameDevToolsAgentHost::ClearRenderFrameHost() {
423 DCHECK(render_frame_host_);
424 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
425 render_frame_host_->GetRenderViewHost());
426 registrar_.Remove(
427 this,
428 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
429 content::Source<RenderWidgetHost>(rvh));
430 render_frame_host_ = nullptr;
431 dom_handler_->SetRenderViewHost(nullptr);
432 input_handler_->SetRenderViewHost(nullptr);
433 network_handler_->SetRenderViewHost(nullptr);
434 page_handler_->SetRenderViewHost(nullptr);
437 void RenderFrameDevToolsAgentHost::DisconnectWebContents() {
438 DisconnectRenderFrameHost();
441 void RenderFrameDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
442 ConnectRenderFrameHost(wc->GetMainFrame());
445 DevToolsAgentHost::Type RenderFrameDevToolsAgentHost::GetType() {
446 return TYPE_WEB_CONTENTS;
449 std::string RenderFrameDevToolsAgentHost::GetTitle() {
450 if (WebContents* web_contents = GetWebContents())
451 return base::UTF16ToUTF8(web_contents->GetTitle());
452 return "";
455 GURL RenderFrameDevToolsAgentHost::GetURL() {
456 if (WebContents* web_contents = GetWebContents())
457 return web_contents->GetVisibleURL();
458 return render_frame_host_ ?
459 render_frame_host_->GetLastCommittedURL() : GURL();
462 bool RenderFrameDevToolsAgentHost::Activate() {
463 if (render_frame_host_) {
464 render_frame_host_->GetRenderViewHost()->GetDelegate()->Activate();
465 return true;
467 return false;
470 bool RenderFrameDevToolsAgentHost::Close() {
471 if (render_frame_host_) {
472 render_frame_host_->GetRenderViewHost()->ClosePage();
473 return true;
475 return false;
478 void RenderFrameDevToolsAgentHost::ConnectRenderFrameHost(
479 RenderFrameHost* rfh) {
480 SetRenderFrameHost(rfh);
481 if (IsAttached())
482 Reattach();
485 void RenderFrameDevToolsAgentHost::DisconnectRenderFrameHost() {
486 ClientDetachedFromRenderer();
487 ClearRenderFrameHost();
490 void RenderFrameDevToolsAgentHost::RenderFrameCrashed() {
491 inspector_handler_->TargetCrashed();
494 void RenderFrameDevToolsAgentHost::OnSwapCompositorFrame(
495 const IPC::Message& message) {
496 ViewHostMsg_SwapCompositorFrame::Param param;
497 if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
498 return;
499 page_handler_->OnSwapCompositorFrame(get<1>(param).metadata);
500 frame_trace_recorder_->OnSwapCompositorFrame(
501 render_frame_host_, get<1>(param).metadata);
504 void RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame(
505 const cc::CompositorFrameMetadata& frame_metadata) {
506 if (!render_frame_host_)
507 return;
508 page_handler_->OnSwapCompositorFrame(frame_metadata);
509 frame_trace_recorder_->OnSwapCompositorFrame(
510 render_frame_host_, frame_metadata);
513 bool RenderFrameDevToolsAgentHost::HasRenderFrameHost(
514 RenderFrameHost* host) {
515 return host == render_frame_host_;
518 void RenderFrameDevToolsAgentHost::OnDispatchOnInspectorFrontend(
519 const DevToolsMessageChunk& message) {
520 if (!IsAttached() || !render_frame_host_)
521 return;
522 ProcessChunkedMessageFromAgent(message);
525 void RenderFrameDevToolsAgentHost::DispatchOnInspectorFrontend(
526 const std::string& message) {
527 if (!IsAttached() || !render_frame_host_)
528 return;
529 SendMessageToClient(message);
532 } // namespace content