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