Upstream version 7.36.149.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
48 namespace content {
49
50 base::subtle::AtomicWord DevToolsAgent::event_callback_;
51
52 namespace {
53
54 class WebKitClientMessageLoopImpl
55     : public WebDevToolsAgentClient::WebKitClientMessageLoop {
56  public:
57   WebKitClientMessageLoopImpl() : message_loop_(base::MessageLoop::current()) {}
58   virtual ~WebKitClientMessageLoopImpl() { message_loop_ = NULL; }
59   virtual void run() {
60     base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_);
61     message_loop_->Run();
62   }
63   virtual void quitNow() {
64     message_loop_->QuitNow();
65   }
66  private:
67   base::MessageLoop* message_loop_;
68 };
69
70 typedef std::map<int, DevToolsAgent*> IdToAgentMap;
71 base::LazyInstance<IdToAgentMap>::Leaky
72     g_agent_for_routing_id = LAZY_INSTANCE_INITIALIZER;
73
74 } //  namespace
75
76 DevToolsAgent::DevToolsAgent(RenderViewImpl* render_view)
77     : RenderViewObserver(render_view),
78       is_attached_(false),
79       is_devtools_client_(false),
80       gpu_route_id_(MSG_ROUTING_NONE) {
81   g_agent_for_routing_id.Get()[routing_id()] = this;
82
83   render_view->webview()->setDevToolsAgentClient(this);
84   render_view->webview()->devToolsAgent()->setProcessId(
85       base::Process::Current().pid());
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 int DevToolsAgent::hostIdentifier() {
124   return routing_id();
125 }
126
127 void DevToolsAgent::saveAgentRuntimeState(
128     const blink::WebString& state) {
129   Send(new DevToolsHostMsg_SaveAgentRuntimeState(routing_id(), state.utf8()));
130 }
131
132 blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
133     DevToolsAgent::createClientMessageLoop() {
134   return new WebKitClientMessageLoopImpl();
135 }
136
137 void DevToolsAgent::resetTraceEventCallback()
138 {
139   TraceLog::GetInstance()->SetEventCallbackDisabled();
140   base::subtle::NoBarrier_Store(&event_callback_, 0);
141 }
142
143 void DevToolsAgent::setTraceEventCallback(const WebString& category_filter,
144                                           TraceEventCallback cb) {
145   TraceLog* trace_log = TraceLog::GetInstance();
146   base::subtle::NoBarrier_Store(&event_callback_,
147                                 reinterpret_cast<base::subtle::AtomicWord>(cb));
148   if (!!cb) {
149     trace_log->SetEventCallbackEnabled(base::debug::CategoryFilter(
150         category_filter.utf8()), TraceEventCallbackWrapper);
151   } else {
152     trace_log->SetEventCallbackDisabled();
153   }
154 }
155
156 void DevToolsAgent::enableTracing(const WebString& category_filter) {
157   TraceLog* trace_log = TraceLog::GetInstance();
158   trace_log->SetEnabled(base::debug::CategoryFilter(category_filter.utf8()),
159                         TraceLog::RECORDING_MODE,
160                         TraceLog::RECORD_UNTIL_FULL);
161 }
162
163 void DevToolsAgent::disableTracing() {
164   TraceLog::GetInstance()->SetDisabled();
165 }
166
167 // static
168 void DevToolsAgent::TraceEventCallbackWrapper(
169     base::TimeTicks timestamp,
170     char phase,
171     const unsigned char* category_group_enabled,
172     const char* name,
173     unsigned long long id,
174     int num_args,
175     const char* const arg_names[],
176     const unsigned char arg_types[],
177     const unsigned long long arg_values[],
178     unsigned char flags) {
179   TraceEventCallback callback =
180       reinterpret_cast<TraceEventCallback>(
181           base::subtle::NoBarrier_Load(&event_callback_));
182   if (callback) {
183     double timestamp_seconds = (timestamp - base::TimeTicks()).InSecondsF();
184     callback(phase, category_group_enabled, name, id, num_args,
185              arg_names, arg_types, arg_values, flags, timestamp_seconds);
186   }
187 }
188
189 void DevToolsAgent::startGPUEventsRecording() {
190   GpuChannelHost* gpu_channel_host =
191       RenderThreadImpl::current()->GetGpuChannel();
192   if (!gpu_channel_host)
193     return;
194   DCHECK(gpu_route_id_ == MSG_ROUTING_NONE);
195   int32 route_id = gpu_channel_host->GenerateRouteID();
196   bool succeeded = false;
197   gpu_channel_host->Send(
198       new GpuChannelMsg_DevToolsStartEventsRecording(route_id, &succeeded));
199   DCHECK(succeeded);
200   if (succeeded) {
201     gpu_route_id_ = route_id;
202     gpu_channel_host->AddRoute(gpu_route_id_, AsWeakPtr());
203   }
204 }
205
206 void DevToolsAgent::stopGPUEventsRecording() {
207   GpuChannelHost* gpu_channel_host =
208       RenderThreadImpl::current()->GetGpuChannel();
209   if (!gpu_channel_host || gpu_route_id_ == MSG_ROUTING_NONE)
210     return;
211   gpu_channel_host->Send(new GpuChannelMsg_DevToolsStopEventsRecording());
212   gpu_channel_host->RemoveRoute(gpu_route_id_);
213   gpu_route_id_ = MSG_ROUTING_NONE;
214 }
215
216 void DevToolsAgent::OnGpuTasksChunk(const std::vector<GpuTaskInfo>& tasks) {
217   WebDevToolsAgent* web_agent = GetWebAgent();
218   if (!web_agent)
219     return;
220   for (size_t i = 0; i < tasks.size(); i++) {
221     const GpuTaskInfo& task = tasks[i];
222     WebDevToolsAgent::GPUEvent event(
223         task.timestamp, task.phase, task.foreign, task.gpu_memory_used_bytes);
224     event.limitGPUMemoryBytes = task.gpu_memory_limit_bytes;
225     web_agent->processGPUEvent(event);
226   }
227 }
228
229 void DevToolsAgent::enableDeviceEmulation(
230     const blink::WebDeviceEmulationParams& params) {
231   RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
232   impl->webview()->settings()->setForceCompositingMode(true);
233   impl->EnableScreenMetricsEmulation(params);
234 }
235
236 void DevToolsAgent::disableDeviceEmulation() {
237   RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
238   impl->DisableScreenMetricsEmulation();
239 }
240
241 void DevToolsAgent::setTouchEventEmulationEnabled(
242     bool enabled, bool allow_pinch) {
243   RenderViewImpl* impl = static_cast<RenderViewImpl*>(render_view());
244   impl->Send(new ViewHostMsg_SetTouchEventEmulationEnabled(
245       impl->routing_id(), enabled, allow_pinch));
246 }
247
248 #if defined(USE_TCMALLOC) && !defined(OS_WIN)
249 static void AllocationVisitor(void* data, const void* ptr) {
250     typedef blink::WebDevToolsAgentClient::AllocatedObjectVisitor Visitor;
251     Visitor* visitor = reinterpret_cast<Visitor*>(data);
252     visitor->visitObject(ptr);
253 }
254 #endif
255
256 void DevToolsAgent::visitAllocatedObjects(AllocatedObjectVisitor* visitor) {
257 #if defined(USE_TCMALLOC) && !defined(OS_WIN)
258   IterateAllocatedObjects(&AllocationVisitor, visitor);
259 #endif
260 }
261
262 // static
263 DevToolsAgent* DevToolsAgent::FromHostId(int host_id) {
264   IdToAgentMap::iterator it = g_agent_for_routing_id.Get().find(host_id);
265   if (it != g_agent_for_routing_id.Get().end()) {
266     return it->second;
267   }
268   return NULL;
269 }
270
271 void DevToolsAgent::OnAttach() {
272   WebDevToolsAgent* web_agent = GetWebAgent();
273   if (web_agent) {
274     web_agent->attach();
275     is_attached_ = true;
276   }
277 }
278
279 void DevToolsAgent::OnReattach(const std::string& agent_state) {
280   WebDevToolsAgent* web_agent = GetWebAgent();
281   if (web_agent) {
282     web_agent->reattach(WebString::fromUTF8(agent_state));
283     is_attached_ = true;
284   }
285 }
286
287 void DevToolsAgent::OnDetach() {
288   WebDevToolsAgent* web_agent = GetWebAgent();
289   if (web_agent) {
290     web_agent->detach();
291     is_attached_ = false;
292   }
293 }
294
295 void DevToolsAgent::OnDispatchOnInspectorBackend(const std::string& message) {
296   TRACE_EVENT0("devtools", "DevToolsAgent::OnDispatchOnInspectorBackend");
297   WebDevToolsAgent* web_agent = GetWebAgent();
298   if (web_agent)
299     web_agent->dispatchOnInspectorBackend(WebString::fromUTF8(message));
300 }
301
302 void DevToolsAgent::OnInspectElement(int x, int y) {
303   WebDevToolsAgent* web_agent = GetWebAgent();
304   if (web_agent) {
305     web_agent->attach();
306     web_agent->inspectElementAt(WebPoint(x, y));
307   }
308 }
309
310 void DevToolsAgent::OnAddMessageToConsole(ConsoleMessageLevel level,
311                                           const std::string& message) {
312   WebView* web_view = render_view()->GetWebView();
313   if (!web_view)
314     return;
315
316   WebFrame* main_frame = web_view->mainFrame();
317   if (!main_frame)
318     return;
319
320   WebConsoleMessage::Level target_level = WebConsoleMessage::LevelLog;
321   switch (level) {
322     case CONSOLE_MESSAGE_LEVEL_DEBUG:
323       target_level = WebConsoleMessage::LevelDebug;
324       break;
325     case CONSOLE_MESSAGE_LEVEL_LOG:
326       target_level = WebConsoleMessage::LevelLog;
327       break;
328     case CONSOLE_MESSAGE_LEVEL_WARNING:
329       target_level = WebConsoleMessage::LevelWarning;
330       break;
331     case CONSOLE_MESSAGE_LEVEL_ERROR:
332       target_level = WebConsoleMessage::LevelError;
333       break;
334   }
335   main_frame->addMessageToConsole(
336       WebConsoleMessage(target_level, WebString::fromUTF8(message)));
337 }
338
339 void DevToolsAgent::ContinueProgram() {
340   WebDevToolsAgent* web_agent = GetWebAgent();
341   // TODO(pfeldman): rename didNavigate to continueProgram upstream.
342   // That is in fact the purpose of the signal.
343   if (web_agent)
344     web_agent->didNavigate();
345 }
346
347 void DevToolsAgent::OnSetupDevToolsClient() {
348   // We only want to register once per render view.
349   if (is_devtools_client_)
350     return;
351   is_devtools_client_ = true;
352   new DevToolsClient(static_cast<RenderViewImpl*>(render_view()));
353 }
354
355 WebDevToolsAgent* DevToolsAgent::GetWebAgent() {
356   WebView* web_view = render_view()->GetWebView();
357   if (!web_view)
358     return NULL;
359   return web_view->devToolsAgent();
360 }
361
362 bool DevToolsAgent::IsAttached() {
363   return is_attached_;
364 }
365
366 }  // namespace content