Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / renderer / devtools / devtools_agent.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/renderer/devtools/devtools_agent.h"
6
7 #include <map>
8
9 #include "base/debug/trace_event.h"
10 #include "base/lazy_instance.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/process/process.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "content/common/devtools_messages.h"
15 #include "content/common/frame_messages.h"
16 #include "content/common/gpu/gpu_messages.h"
17 #include "content/common/view_messages.h"
18 #include "content/renderer/devtools/devtools_agent_filter.h"
19 #include "content/renderer/devtools/devtools_client.h"
20 #include "content/renderer/render_thread_impl.h"
21 #include "content/renderer/render_view_impl.h"
22 #include "third_party/WebKit/public/platform/WebPoint.h"
23 #include "third_party/WebKit/public/platform/WebString.h"
24 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
25 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
26 #include "third_party/WebKit/public/web/WebDevToolsAgent.h"
27 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
28 #include "third_party/WebKit/public/web/WebFrame.h"
29 #include "third_party/WebKit/public/web/WebSettings.h"
30 #include "third_party/WebKit/public/web/WebView.h"
31
32 #if defined(USE_TCMALLOC)
33 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
34 #endif
35
36 using blink::WebConsoleMessage;
37 using blink::WebDevToolsAgent;
38 using blink::WebDevToolsAgentClient;
39 using blink::WebFrame;
40 using blink::WebPoint;
41 using blink::WebString;
42 using blink::WebCString;
43 using blink::WebVector;
44 using blink::WebView;
45
46 using base::debug::TraceLog;
47 using base::debug::TraceOptions;
48
49 namespace content {
50
51 base::subtle::AtomicWord DevToolsAgent::event_callback_;
52
53 namespace {
54
55 class WebKitClientMessageLoopImpl
56     : public WebDevToolsAgentClient::WebKitClientMessageLoop {
57  public:
58   WebKitClientMessageLoopImpl() : message_loop_(base::MessageLoop::current()) {}
59   virtual ~WebKitClientMessageLoopImpl() { message_loop_ = NULL; }
60   virtual void run() {
61     base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_);
62     message_loop_->Run();
63   }
64   virtual void quitNow() {
65     message_loop_->QuitNow();
66   }
67  private:
68   base::MessageLoop* message_loop_;
69 };
70
71 typedef std::map<int, DevToolsAgent*> IdToAgentMap;
72 base::LazyInstance<IdToAgentMap>::Leaky
73     g_agent_for_routing_id = LAZY_INSTANCE_INITIALIZER;
74
75 } //  namespace
76
77 DevToolsAgent::DevToolsAgent(RenderViewImpl* render_view)
78     : RenderViewObserver(render_view),
79       is_attached_(false),
80       is_devtools_client_(false),
81       gpu_route_id_(MSG_ROUTING_NONE),
82       paused_in_mouse_move_(false) {
83   g_agent_for_routing_id.Get()[routing_id()] = this;
84
85   render_view->webview()->setDevToolsAgentClient(this);
86 }
87
88 DevToolsAgent::~DevToolsAgent() {
89   g_agent_for_routing_id.Get().erase(routing_id());
90   resetTraceEventCallback();
91 }
92
93 // Called on the Renderer thread.
94 bool DevToolsAgent::OnMessageReceived(const IPC::Message& message) {
95   bool handled = true;
96   IPC_BEGIN_MESSAGE_MAP(DevToolsAgent, message)
97     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Attach, OnAttach)
98     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Reattach, OnReattach)
99     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Detach, OnDetach)
100     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DispatchOnInspectorBackend,
101                         OnDispatchOnInspectorBackend)
102     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_InspectElement, OnInspectElement)
103     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_AddMessageToConsole,
104                         OnAddMessageToConsole)
105     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_GpuTasksChunk, OnGpuTasksChunk)
106     IPC_MESSAGE_HANDLER(DevToolsMsg_SetupDevToolsClient, OnSetupDevToolsClient)
107     IPC_MESSAGE_UNHANDLED(handled = false)
108   IPC_END_MESSAGE_MAP()
109
110   if (message.type() == FrameMsg_Navigate::ID ||
111       message.type() == ViewMsg_Close::ID)
112     ContinueProgram();  // Don't want to swallow the message.
113
114   return handled;
115 }
116
117 void DevToolsAgent::sendMessageToInspectorFrontend(
118     const blink::WebString& message) {
119   Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(routing_id(),
120                                                          message.utf8()));
121 }
122
123 long DevToolsAgent::processId() {
124   return base::Process::Current().pid();
125 }
126
127 int DevToolsAgent::debuggerId() {
128   return routing_id();
129 }
130
131 void DevToolsAgent::saveAgentRuntimeState(
132     const blink::WebString& state) {
133   Send(new DevToolsHostMsg_SaveAgentRuntimeState(routing_id(), state.utf8()));
134 }
135
136 blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
137     DevToolsAgent::createClientMessageLoop() {
138   return new WebKitClientMessageLoopImpl();
139 }
140
141 void DevToolsAgent::willEnterDebugLoop() {
142   RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
143   paused_in_mouse_move_ = impl->SendAckForMouseMoveFromDebugger();
144 }
145
146 void DevToolsAgent::didExitDebugLoop() {
147   RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
148   if (paused_in_mouse_move_) {
149     impl->IgnoreAckForMouseMoveFromDebugger();
150     paused_in_mouse_move_ = false;
151   }
152 }
153
154 void DevToolsAgent::resetTraceEventCallback()
155 {
156   TraceLog::GetInstance()->SetEventCallbackDisabled();
157   base::subtle::NoBarrier_Store(&event_callback_, 0);
158 }
159
160 void DevToolsAgent::setTraceEventCallback(const WebString& category_filter,
161                                           TraceEventCallback cb) {
162   TraceLog* trace_log = TraceLog::GetInstance();
163   base::subtle::NoBarrier_Store(&event_callback_,
164                                 reinterpret_cast<base::subtle::AtomicWord>(cb));
165   if (!!cb) {
166     trace_log->SetEventCallbackEnabled(base::debug::CategoryFilter(
167         category_filter.utf8()), TraceEventCallbackWrapper);
168   } else {
169     trace_log->SetEventCallbackDisabled();
170   }
171 }
172
173 void DevToolsAgent::enableTracing(const WebString& category_filter) {
174   TraceLog* trace_log = TraceLog::GetInstance();
175   trace_log->SetEnabled(base::debug::CategoryFilter(category_filter.utf8()),
176                         TraceLog::RECORDING_MODE,
177                         TraceOptions());
178 }
179
180 void DevToolsAgent::disableTracing() {
181   TraceLog::GetInstance()->SetDisabled();
182 }
183
184 // static
185 void DevToolsAgent::TraceEventCallbackWrapper(
186     base::TimeTicks timestamp,
187     char phase,
188     const unsigned char* category_group_enabled,
189     const char* name,
190     unsigned long long id,
191     int num_args,
192     const char* const arg_names[],
193     const unsigned char arg_types[],
194     const unsigned long long arg_values[],
195     unsigned char flags) {
196   TraceEventCallback callback =
197       reinterpret_cast<TraceEventCallback>(
198           base::subtle::NoBarrier_Load(&event_callback_));
199   if (callback) {
200     double timestamp_seconds = (timestamp - base::TimeTicks()).InSecondsF();
201     callback(phase, category_group_enabled, name, id, num_args,
202              arg_names, arg_types, arg_values, flags, timestamp_seconds);
203   }
204 }
205
206 void DevToolsAgent::startGPUEventsRecording() {
207   GpuChannelHost* gpu_channel_host =
208       RenderThreadImpl::current()->GetGpuChannel();
209   if (!gpu_channel_host)
210     return;
211   DCHECK(gpu_route_id_ == MSG_ROUTING_NONE);
212   int32 route_id = gpu_channel_host->GenerateRouteID();
213   bool succeeded = false;
214   gpu_channel_host->Send(
215       new GpuChannelMsg_DevToolsStartEventsRecording(route_id, &succeeded));
216   DCHECK(succeeded);
217   if (succeeded) {
218     gpu_route_id_ = route_id;
219     gpu_channel_host->AddRoute(gpu_route_id_, AsWeakPtr());
220   }
221 }
222
223 void DevToolsAgent::stopGPUEventsRecording() {
224   GpuChannelHost* gpu_channel_host =
225       RenderThreadImpl::current()->GetGpuChannel();
226   if (!gpu_channel_host || gpu_route_id_ == MSG_ROUTING_NONE)
227     return;
228   gpu_channel_host->Send(new GpuChannelMsg_DevToolsStopEventsRecording());
229   gpu_channel_host->RemoveRoute(gpu_route_id_);
230   gpu_route_id_ = MSG_ROUTING_NONE;
231 }
232
233 void DevToolsAgent::OnGpuTasksChunk(const std::vector<GpuTaskInfo>& tasks) {
234   WebDevToolsAgent* web_agent = GetWebAgent();
235   if (!web_agent)
236     return;
237   for (size_t i = 0; i < tasks.size(); i++) {
238     const GpuTaskInfo& task = tasks[i];
239     WebDevToolsAgent::GPUEvent event(
240         task.timestamp, task.phase, task.foreign, task.gpu_memory_used_bytes);
241     event.limitGPUMemoryBytes = task.gpu_memory_limit_bytes;
242     web_agent->processGPUEvent(event);
243   }
244 }
245
246 void DevToolsAgent::enableDeviceEmulation(
247     const blink::WebDeviceEmulationParams& params) {
248   RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
249   impl->EnableScreenMetricsEmulation(params);
250 }
251
252 void DevToolsAgent::disableDeviceEmulation() {
253   RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
254   impl->DisableScreenMetricsEmulation();
255 }
256
257 // static
258 DevToolsAgent* DevToolsAgent::FromRoutingId(int routing_id) {
259   IdToAgentMap::iterator it = g_agent_for_routing_id.Get().find(routing_id);
260   if (it != g_agent_for_routing_id.Get().end()) {
261     return it->second;
262   }
263   return NULL;
264 }
265
266 void DevToolsAgent::OnAttach(const std::string& host_id) {
267   WebDevToolsAgent* web_agent = GetWebAgent();
268   if (web_agent) {
269     web_agent->attach(WebString::fromUTF8(host_id));
270     is_attached_ = true;
271   }
272 }
273
274 void DevToolsAgent::OnReattach(const std::string& host_id,
275                                const std::string& agent_state) {
276   WebDevToolsAgent* web_agent = GetWebAgent();
277   if (web_agent) {
278     web_agent->reattach(WebString::fromUTF8(host_id),
279                         WebString::fromUTF8(agent_state));
280     is_attached_ = true;
281   }
282 }
283
284 void DevToolsAgent::OnDetach() {
285   WebDevToolsAgent* web_agent = GetWebAgent();
286   if (web_agent) {
287     web_agent->detach();
288     is_attached_ = false;
289   }
290 }
291
292 void DevToolsAgent::OnDispatchOnInspectorBackend(const std::string& message) {
293   TRACE_EVENT0("devtools", "DevToolsAgent::OnDispatchOnInspectorBackend");
294   WebDevToolsAgent* web_agent = GetWebAgent();
295   if (web_agent)
296     web_agent->dispatchOnInspectorBackend(WebString::fromUTF8(message));
297 }
298
299 void DevToolsAgent::OnInspectElement(
300     const std::string& host_id, int x, int y) {
301   WebDevToolsAgent* web_agent = GetWebAgent();
302   if (web_agent) {
303     web_agent->attach(WebString::fromUTF8(host_id));
304     web_agent->inspectElementAt(WebPoint(x, y));
305     is_attached_ = true;
306   }
307 }
308
309 void DevToolsAgent::OnAddMessageToConsole(ConsoleMessageLevel level,
310                                           const std::string& message) {
311   WebView* web_view = render_view()->GetWebView();
312   if (!web_view)
313     return;
314
315   WebFrame* main_frame = web_view->mainFrame();
316   if (!main_frame)
317     return;
318
319   WebConsoleMessage::Level target_level = WebConsoleMessage::LevelLog;
320   switch (level) {
321     case CONSOLE_MESSAGE_LEVEL_DEBUG:
322       target_level = WebConsoleMessage::LevelDebug;
323       break;
324     case CONSOLE_MESSAGE_LEVEL_LOG:
325       target_level = WebConsoleMessage::LevelLog;
326       break;
327     case CONSOLE_MESSAGE_LEVEL_WARNING:
328       target_level = WebConsoleMessage::LevelWarning;
329       break;
330     case CONSOLE_MESSAGE_LEVEL_ERROR:
331       target_level = WebConsoleMessage::LevelError;
332       break;
333   }
334   main_frame->addMessageToConsole(
335       WebConsoleMessage(target_level, WebString::fromUTF8(message)));
336 }
337
338 void DevToolsAgent::ContinueProgram() {
339   WebDevToolsAgent* web_agent = GetWebAgent();
340   if (web_agent)
341     web_agent->continueProgram();
342 }
343
344 void DevToolsAgent::OnSetupDevToolsClient() {
345   // We only want to register once per render view.
346   if (is_devtools_client_)
347     return;
348   is_devtools_client_ = true;
349   new DevToolsClient(static_cast<RenderViewImpl*>(render_view()));
350 }
351
352 WebDevToolsAgent* DevToolsAgent::GetWebAgent() {
353   WebView* web_view = render_view()->GetWebView();
354   if (!web_view)
355     return NULL;
356   return web_view->devToolsAgent();
357 }
358
359 bool DevToolsAgent::IsAttached() {
360   return is_attached_;
361 }
362
363 }  // namespace content