Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / content / browser / devtools / render_view_devtools_agent_host.cc
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.
4
5 #include "content/browser/devtools/render_view_devtools_agent_host.h"
6
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/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
28 #if defined(OS_ANDROID)
29 #include "content/browser/power_save_blocker_impl.h"
30 #include "content/public/browser/render_widget_host_view.h"
31 #endif
32
33 namespace content {
34
35 typedef std::vector<RenderViewDevToolsAgentHost*> Instances;
36
37 namespace {
38 base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
39
40 //Returns RenderViewDevToolsAgentHost attached to any of RenderViewHost
41 //instances associated with |web_contents|
42 static RenderViewDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
43   if (g_instances == NULL)
44     return NULL;
45   for (Instances::iterator it = g_instances.Get().begin();
46        it != g_instances.Get().end(); ++it) {
47     if ((*it)->GetWebContents() == web_contents)
48       return *it;
49   }
50   return NULL;
51 }
52
53 }  // namespace
54
55 scoped_refptr<DevToolsAgentHost>
56 DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
57   RenderViewDevToolsAgentHost* result = FindAgentHost(web_contents);
58   if (!result)
59     result = new RenderViewDevToolsAgentHost(web_contents->GetRenderViewHost());
60   return result;
61 }
62
63 // static
64 bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
65   return FindAgentHost(web_contents) != NULL;
66 }
67
68 // static
69 bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
70   RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
71   return agent_host && agent_host->IsAttached();
72 }
73
74 //static
75 std::vector<WebContents*> DevToolsAgentHost::GetInspectableWebContents() {
76   std::set<WebContents*> set;
77   scoped_ptr<RenderWidgetHostIterator> widgets(
78       RenderWidgetHost::GetRenderWidgetHosts());
79   while (RenderWidgetHost* widget = widgets->GetNextHost()) {
80     // Ignore processes that don't have a connection, such as crashed contents.
81     if (!widget->GetProcess()->HasConnection())
82       continue;
83     if (!widget->IsRenderView())
84       continue;
85
86     RenderViewHost* rvh = RenderViewHost::From(widget);
87     WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
88     if (web_contents)
89       set.insert(web_contents);
90   }
91   std::vector<WebContents*> result(set.size());
92   std::copy(set.begin(), set.end(), result.begin());
93   return result;
94 }
95
96 // static
97 void RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
98     RenderViewHost* pending,
99     RenderViewHost* current) {
100   WebContents* web_contents = WebContents::FromRenderViewHost(pending);
101   RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
102   if (!agent_host)
103     return;
104   agent_host->DisconnectRenderViewHost();
105   agent_host->ConnectRenderViewHost(current);
106 }
107
108 RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost(RenderViewHost* rvh)
109     : render_view_host_(NULL),
110       overrides_handler_(new RendererOverridesHandler()),
111       tracing_handler_(
112           new DevToolsTracingHandler(DevToolsTracingHandler::Renderer)),
113       power_handler_(new DevToolsPowerHandler()),
114       reattaching_(false) {
115   SetRenderViewHost(rvh);
116   DevToolsProtocol::Notifier notifier(base::Bind(
117       &RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend,
118       base::Unretained(this)));
119   overrides_handler_->SetNotifier(notifier);
120   tracing_handler_->SetNotifier(notifier);
121   power_handler_->SetNotifier(notifier);
122   g_instances.Get().push_back(this);
123   AddRef();  // Balanced in RenderViewHostDestroyed.
124 }
125
126 WebContents* RenderViewDevToolsAgentHost::GetWebContents() {
127   return web_contents();
128 }
129
130 void RenderViewDevToolsAgentHost::DispatchOnInspectorBackend(
131     const std::string& message) {
132   std::string error_message;
133
134   scoped_ptr<base::DictionaryValue> message_dict(
135       DevToolsProtocol::ParseMessage(message, &error_message));
136   scoped_refptr<DevToolsProtocol::Command> command =
137       DevToolsProtocol::ParseCommand(message_dict.get(), &error_message);
138
139   if (command) {
140     scoped_refptr<DevToolsProtocol::Response> overridden_response;
141
142     DevToolsManagerDelegate* delegate =
143         DevToolsManagerImpl::GetInstance()->delegate();
144     if (delegate) {
145       scoped_ptr<base::DictionaryValue> overridden_response_value(
146           delegate->HandleCommand(this, message_dict.get()));
147       if (overridden_response_value)
148         overridden_response = DevToolsProtocol::ParseResponse(
149             overridden_response_value.get());
150     }
151     if (!overridden_response)
152       overridden_response = overrides_handler_->HandleCommand(command);
153     if (!overridden_response)
154       overridden_response = tracing_handler_->HandleCommand(command);
155     if (!overridden_response)
156       overridden_response = power_handler_->HandleCommand(command);
157     if (overridden_response) {
158       if (!overridden_response->is_async_promise())
159         OnDispatchOnInspectorFrontend(overridden_response->Serialize());
160       return;
161     }
162   }
163
164   IPCDevToolsAgentHost::DispatchOnInspectorBackend(message);
165 }
166
167 void RenderViewDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
168   if (!render_view_host_)
169     return;
170   msg->set_routing_id(render_view_host_->GetRoutingID());
171   render_view_host_->Send(msg);
172 }
173
174 void RenderViewDevToolsAgentHost::OnClientAttached() {
175   if (!render_view_host_)
176     return;
177
178   InnerOnClientAttached();
179
180   // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when
181   // extensions::ProcessManager no longer relies on this notification.
182   if (!reattaching_)
183     DevToolsManagerImpl::GetInstance()->NotifyObservers(this, true);
184 }
185
186 void RenderViewDevToolsAgentHost::InnerOnClientAttached() {
187   ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
188       render_view_host_->GetProcess()->GetID());
189
190 #if defined(OS_ANDROID)
191   power_save_blocker_.reset(
192       static_cast<PowerSaveBlockerImpl*>(
193           PowerSaveBlocker::Create(
194               PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
195               "DevTools").release()));
196   if (render_view_host_->GetView()) {
197     power_save_blocker_.get()->
198         InitDisplaySleepBlocker(render_view_host_->GetView()->GetNativeView());
199   }
200 #endif
201 }
202
203 void RenderViewDevToolsAgentHost::OnClientDetached() {
204 #if defined(OS_ANDROID)
205   power_save_blocker_.reset();
206 #endif
207   overrides_handler_->OnClientDetached();
208   tracing_handler_->OnClientDetached();
209   power_handler_->OnClientDetached();
210   ClientDetachedFromRenderer();
211
212   // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when
213   // extensions::ProcessManager no longer relies on this notification.
214   if (!reattaching_)
215     DevToolsManagerImpl::GetInstance()->NotifyObservers(this, false);
216 }
217
218 void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() {
219   if (!render_view_host_)
220     return;
221
222   InnerClientDetachedFromRenderer();
223 }
224
225 void RenderViewDevToolsAgentHost::InnerClientDetachedFromRenderer() {
226   bool process_has_agents = false;
227   RenderProcessHost* render_process_host = render_view_host_->GetProcess();
228   for (Instances::iterator it = g_instances.Get().begin();
229        it != g_instances.Get().end(); ++it) {
230     if (*it == this || !(*it)->IsAttached())
231       continue;
232     RenderViewHost* rvh = (*it)->render_view_host_;
233     if (rvh && rvh->GetProcess() == render_process_host)
234       process_has_agents = true;
235   }
236
237   // We are the last to disconnect from the renderer -> revoke permissions.
238   if (!process_has_agents) {
239     ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
240         render_process_host->GetID());
241   }
242 }
243
244 RenderViewDevToolsAgentHost::~RenderViewDevToolsAgentHost() {
245   Instances::iterator it = std::find(g_instances.Get().begin(),
246                                      g_instances.Get().end(),
247                                      this);
248   if (it != g_instances.Get().end())
249     g_instances.Get().erase(it);
250 }
251
252 void RenderViewDevToolsAgentHost::AboutToNavigateRenderView(
253     RenderViewHost* dest_rvh) {
254   if (!render_view_host_)
255     return;
256
257   if (render_view_host_ == dest_rvh &&
258           render_view_host_->render_view_termination_status() ==
259               base::TERMINATION_STATUS_STILL_RUNNING)
260     return;
261   ReattachToRenderViewHost(dest_rvh);
262 }
263
264 void RenderViewDevToolsAgentHost::RenderViewHostChanged(
265     RenderViewHost* old_host,
266     RenderViewHost* new_host) {
267   if (new_host != render_view_host_) {
268     // AboutToNavigateRenderView was not called for renderer-initiated
269     // navigation.
270     ReattachToRenderViewHost(new_host);
271   }
272 }
273
274 void
275 RenderViewDevToolsAgentHost::ReattachToRenderViewHost(RenderViewHost* rvh) {
276   DCHECK(!reattaching_);
277   reattaching_ = true;
278   DisconnectRenderViewHost();
279   ConnectRenderViewHost(rvh);
280   reattaching_ = false;
281 }
282
283 void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) {
284   if (rvh != render_view_host_)
285     return;
286
287   DCHECK(render_view_host_);
288   scoped_refptr<RenderViewDevToolsAgentHost> protect(this);
289   NotifyCloseListener();
290   ClearRenderViewHost();
291   Release();
292 }
293
294 void RenderViewDevToolsAgentHost::RenderProcessGone(
295     base::TerminationStatus status) {
296   switch(status) {
297     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
298     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
299     case base::TERMINATION_STATUS_PROCESS_CRASHED:
300 #if defined(OS_ANDROID)
301     case base::TERMINATION_STATUS_OOM_PROTECTED:
302 #endif
303       RenderViewCrashed();
304       break;
305     default:
306       break;
307   }
308 }
309
310 bool RenderViewDevToolsAgentHost::OnMessageReceived(
311     const IPC::Message& message,
312     RenderFrameHost* render_frame_host) {
313   return DispatchIPCMessage(message);
314 }
315
316 bool RenderViewDevToolsAgentHost::OnMessageReceived(
317     const IPC::Message& message) {
318   return DispatchIPCMessage(message);
319 }
320
321 void RenderViewDevToolsAgentHost::DidAttachInterstitialPage() {
322   if (!render_view_host_)
323     return;
324   // The rvh set in AboutToNavigateRenderView turned out to be interstitial.
325   // Connect back to the real one.
326   WebContents* web_contents =
327     WebContents::FromRenderViewHost(render_view_host_);
328   if (!web_contents)
329     return;
330   DisconnectRenderViewHost();
331   ConnectRenderViewHost(web_contents->GetRenderViewHost());
332 }
333
334 void RenderViewDevToolsAgentHost::Observe(int type,
335                                           const NotificationSource& source,
336                                           const NotificationDetails& details) {
337   if (type == content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
338     bool visible = *Details<bool>(details).ptr();
339     overrides_handler_->OnVisibilityChanged(visible);
340   }
341 }
342
343 void RenderViewDevToolsAgentHost::SetRenderViewHost(RenderViewHost* rvh) {
344   DCHECK(!render_view_host_);
345   render_view_host_ = static_cast<RenderViewHostImpl*>(rvh);
346
347   WebContentsObserver::Observe(WebContents::FromRenderViewHost(rvh));
348   overrides_handler_->SetRenderViewHost(render_view_host_);
349
350   registrar_.Add(
351       this,
352       content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
353       content::Source<RenderWidgetHost>(render_view_host_));
354 }
355
356 void RenderViewDevToolsAgentHost::ClearRenderViewHost() {
357   DCHECK(render_view_host_);
358   registrar_.Remove(
359       this,
360       content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
361       content::Source<RenderWidgetHost>(render_view_host_));
362   render_view_host_ = NULL;
363   overrides_handler_->ClearRenderViewHost();
364 }
365
366 void RenderViewDevToolsAgentHost::DisconnectWebContents() {
367   DisconnectRenderViewHost();
368 }
369
370 void RenderViewDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
371   ConnectRenderViewHost(wc->GetRenderViewHost());
372 }
373
374 void RenderViewDevToolsAgentHost::ConnectRenderViewHost(RenderViewHost* rvh) {
375   SetRenderViewHost(rvh);
376   if (IsAttached())
377     Reattach(state_);
378 }
379
380 void RenderViewDevToolsAgentHost::DisconnectRenderViewHost() {
381   ClientDetachedFromRenderer();
382   ClearRenderViewHost();
383 }
384
385 void RenderViewDevToolsAgentHost::RenderViewCrashed() {
386   scoped_refptr<DevToolsProtocol::Notification> notification =
387       DevToolsProtocol::CreateNotification(
388           devtools::Inspector::targetCrashed::kName, NULL);
389   DevToolsManagerImpl::GetInstance()->
390       DispatchOnInspectorFrontend(this, notification->Serialize());
391 }
392
393 bool RenderViewDevToolsAgentHost::DispatchIPCMessage(
394     const IPC::Message& msg) {
395   if (!render_view_host_)
396     return false;
397
398   bool handled = true;
399   IPC_BEGIN_MESSAGE_MAP(RenderViewDevToolsAgentHost, msg)
400     IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
401                         OnDispatchOnInspectorFrontend)
402     IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
403                         OnSaveAgentRuntimeState)
404     IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame,
405                                 handled = false; OnSwapCompositorFrame(msg))
406     IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SetTouchEventEmulationEnabled,
407                                 handled = OnSetTouchEventEmulationEnabled(msg))
408     IPC_MESSAGE_UNHANDLED(handled = false)
409   IPC_END_MESSAGE_MAP()
410   return handled;
411 }
412
413 void RenderViewDevToolsAgentHost::OnSwapCompositorFrame(
414     const IPC::Message& message) {
415   ViewHostMsg_SwapCompositorFrame::Param param;
416   if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
417     return;
418   overrides_handler_->OnSwapCompositorFrame(param.b.metadata);
419 }
420
421 bool RenderViewDevToolsAgentHost::OnSetTouchEventEmulationEnabled(
422     const IPC::Message& message) {
423   return overrides_handler_->OnSetTouchEventEmulationEnabled();
424 }
425
426 void RenderViewDevToolsAgentHost::SynchronousSwapCompositorFrame(
427     const cc::CompositorFrameMetadata& frame_metadata) {
428   if (!render_view_host_)
429     return;
430   overrides_handler_->OnSwapCompositorFrame(frame_metadata);
431 }
432
433 void RenderViewDevToolsAgentHost::OnSaveAgentRuntimeState(
434     const std::string& state) {
435   if (!render_view_host_)
436     return;
437   state_ = state;
438 }
439
440 void RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend(
441     const std::string& message) {
442   if (!render_view_host_)
443     return;
444
445   scoped_refptr<DevToolsProtocol::Notification> notification =
446       DevToolsProtocol::ParseNotification(message);
447
448   if (notification) {
449     tracing_handler_->HandleNotification(notification);
450   }
451   DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(
452       this, message);
453 }
454
455 }  // namespace content