Home | History | Annotate | Download | only in devtools
      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/view_messages.h"
     16 #include "content/renderer/devtools/devtools_agent_filter.h"
     17 #include "content/renderer/devtools/devtools_client.h"
     18 #include "content/renderer/render_view_impl.h"
     19 #include "third_party/WebKit/public/platform/WebPoint.h"
     20 #include "third_party/WebKit/public/platform/WebString.h"
     21 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
     22 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
     23 #include "third_party/WebKit/public/web/WebDevToolsAgent.h"
     24 #include "third_party/WebKit/public/web/WebFrame.h"
     25 #include "third_party/WebKit/public/web/WebView.h"
     26 
     27 #if defined(USE_TCMALLOC)
     28 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
     29 #endif
     30 
     31 using WebKit::WebConsoleMessage;
     32 using WebKit::WebDevToolsAgent;
     33 using WebKit::WebDevToolsAgentClient;
     34 using WebKit::WebFrame;
     35 using WebKit::WebPoint;
     36 using WebKit::WebString;
     37 using WebKit::WebCString;
     38 using WebKit::WebVector;
     39 using WebKit::WebView;
     40 
     41 using base::debug::TraceLog;
     42 
     43 namespace content {
     44 
     45 namespace {
     46 
     47 class WebKitClientMessageLoopImpl
     48     : public WebDevToolsAgentClient::WebKitClientMessageLoop {
     49  public:
     50   WebKitClientMessageLoopImpl() : message_loop_(base::MessageLoop::current()) {}
     51   virtual ~WebKitClientMessageLoopImpl() { message_loop_ = NULL; }
     52   virtual void run() {
     53     base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_);
     54     message_loop_->Run();
     55   }
     56   virtual void quitNow() {
     57     message_loop_->QuitNow();
     58   }
     59  private:
     60   base::MessageLoop* message_loop_;
     61 };
     62 
     63 typedef std::map<int, DevToolsAgent*> IdToAgentMap;
     64 base::LazyInstance<IdToAgentMap>::Leaky
     65     g_agent_for_routing_id = LAZY_INSTANCE_INITIALIZER;
     66 
     67 } //  namespace
     68 
     69 DevToolsAgent::DevToolsAgent(RenderViewImpl* render_view)
     70     : RenderViewObserver(render_view),
     71       is_attached_(false),
     72       is_devtools_client_(false) {
     73   g_agent_for_routing_id.Get()[routing_id()] = this;
     74 
     75   render_view->webview()->setDevToolsAgentClient(this);
     76   render_view->webview()->devToolsAgent()->setProcessId(
     77       base::Process::Current().pid());
     78 }
     79 
     80 DevToolsAgent::~DevToolsAgent() {
     81   g_agent_for_routing_id.Get().erase(routing_id());
     82 }
     83 
     84 // Called on the Renderer thread.
     85 bool DevToolsAgent::OnMessageReceived(const IPC::Message& message) {
     86   bool handled = true;
     87   IPC_BEGIN_MESSAGE_MAP(DevToolsAgent, message)
     88     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Attach, OnAttach)
     89     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Reattach, OnReattach)
     90     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Detach, OnDetach)
     91     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DispatchOnInspectorBackend,
     92                         OnDispatchOnInspectorBackend)
     93     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_InspectElement, OnInspectElement)
     94     IPC_MESSAGE_HANDLER(DevToolsAgentMsg_AddMessageToConsole,
     95                         OnAddMessageToConsole)
     96     IPC_MESSAGE_HANDLER(DevToolsMsg_SetupDevToolsClient, OnSetupDevToolsClient)
     97     IPC_MESSAGE_UNHANDLED(handled = false)
     98   IPC_END_MESSAGE_MAP()
     99 
    100   if (message.type() == ViewMsg_Navigate::ID ||
    101       message.type() == ViewMsg_Close::ID)
    102     ContinueProgram();  // Don't want to swallow the message.
    103 
    104   return handled;
    105 }
    106 
    107 void DevToolsAgent::sendMessageToInspectorFrontend(
    108     const WebKit::WebString& message) {
    109   Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(routing_id(),
    110                                                          message.utf8()));
    111 }
    112 
    113 int DevToolsAgent::hostIdentifier() {
    114   return routing_id();
    115 }
    116 
    117 void DevToolsAgent::saveAgentRuntimeState(
    118     const WebKit::WebString& state) {
    119   Send(new DevToolsHostMsg_SaveAgentRuntimeState(routing_id(), state.utf8()));
    120 }
    121 
    122 WebKit::WebDevToolsAgentClient::WebKitClientMessageLoop*
    123     DevToolsAgent::createClientMessageLoop() {
    124   return new WebKitClientMessageLoopImpl();
    125 }
    126 
    127 void DevToolsAgent::clearBrowserCache() {
    128   Send(new DevToolsHostMsg_ClearBrowserCache(routing_id()));
    129 }
    130 
    131 void DevToolsAgent::clearBrowserCookies() {
    132   Send(new DevToolsHostMsg_ClearBrowserCookies(routing_id()));
    133 }
    134 
    135 void DevToolsAgent::setTraceEventCallback(TraceEventCallback cb) {
    136   TraceLog* trace_log = TraceLog::GetInstance();
    137   trace_log->SetEventCallback(cb);
    138   if (!!cb) {
    139     trace_log->SetEnabled(base::debug::CategoryFilter(
    140         base::debug::CategoryFilter::kDefaultCategoryFilterString),
    141         TraceLog::RECORD_UNTIL_FULL);
    142   } else {
    143     trace_log->SetDisabled();
    144   }
    145 }
    146 
    147 #if defined(USE_TCMALLOC) && !defined(OS_WIN)
    148 static void AllocationVisitor(void* data, const void* ptr) {
    149     typedef WebKit::WebDevToolsAgentClient::AllocatedObjectVisitor Visitor;
    150     Visitor* visitor = reinterpret_cast<Visitor*>(data);
    151     visitor->visitObject(ptr);
    152 }
    153 #endif
    154 
    155 void DevToolsAgent::visitAllocatedObjects(AllocatedObjectVisitor* visitor) {
    156 #if defined(USE_TCMALLOC) && !defined(OS_WIN)
    157   IterateAllocatedObjects(&AllocationVisitor, visitor);
    158 #endif
    159 }
    160 
    161 // static
    162 DevToolsAgent* DevToolsAgent::FromHostId(int host_id) {
    163   IdToAgentMap::iterator it = g_agent_for_routing_id.Get().find(host_id);
    164   if (it != g_agent_for_routing_id.Get().end()) {
    165     return it->second;
    166   }
    167   return NULL;
    168 }
    169 
    170 void DevToolsAgent::OnAttach() {
    171   WebDevToolsAgent* web_agent = GetWebAgent();
    172   if (web_agent) {
    173     web_agent->attach();
    174     is_attached_ = true;
    175   }
    176 }
    177 
    178 void DevToolsAgent::OnReattach(const std::string& agent_state) {
    179   WebDevToolsAgent* web_agent = GetWebAgent();
    180   if (web_agent) {
    181     web_agent->reattach(WebString::fromUTF8(agent_state));
    182     is_attached_ = true;
    183   }
    184 }
    185 
    186 void DevToolsAgent::OnDetach() {
    187   WebDevToolsAgent* web_agent = GetWebAgent();
    188   if (web_agent) {
    189     web_agent->detach();
    190     is_attached_ = false;
    191   }
    192 }
    193 
    194 void DevToolsAgent::OnDispatchOnInspectorBackend(const std::string& message) {
    195   WebDevToolsAgent* web_agent = GetWebAgent();
    196   if (web_agent)
    197     web_agent->dispatchOnInspectorBackend(WebString::fromUTF8(message));
    198 }
    199 
    200 void DevToolsAgent::OnInspectElement(int x, int y) {
    201   WebDevToolsAgent* web_agent = GetWebAgent();
    202   if (web_agent) {
    203     web_agent->attach();
    204     web_agent->inspectElementAt(WebPoint(x, y));
    205   }
    206 }
    207 
    208 void DevToolsAgent::OnAddMessageToConsole(ConsoleMessageLevel level,
    209                                           const std::string& message) {
    210   WebView* web_view = render_view()->GetWebView();
    211   if (!web_view)
    212     return;
    213 
    214   WebFrame* main_frame = web_view->mainFrame();
    215   if (!main_frame)
    216     return;
    217 
    218   WebConsoleMessage::Level target_level = WebConsoleMessage::LevelLog;
    219   switch (level) {
    220     case CONSOLE_MESSAGE_LEVEL_DEBUG:
    221       target_level = WebConsoleMessage::LevelDebug;
    222       break;
    223     case CONSOLE_MESSAGE_LEVEL_LOG:
    224       target_level = WebConsoleMessage::LevelLog;
    225       break;
    226     case CONSOLE_MESSAGE_LEVEL_WARNING:
    227       target_level = WebConsoleMessage::LevelWarning;
    228       break;
    229     case CONSOLE_MESSAGE_LEVEL_ERROR:
    230       target_level = WebConsoleMessage::LevelError;
    231       break;
    232   }
    233   main_frame->addMessageToConsole(
    234       WebConsoleMessage(target_level, WebString::fromUTF8(message)));
    235 }
    236 
    237 void DevToolsAgent::ContinueProgram() {
    238   WebDevToolsAgent* web_agent = GetWebAgent();
    239   // TODO(pfeldman): rename didNavigate to continueProgram upstream.
    240   // That is in fact the purpose of the signal.
    241   if (web_agent)
    242     web_agent->didNavigate();
    243 }
    244 
    245 void DevToolsAgent::OnSetupDevToolsClient() {
    246   // We only want to register once per render view.
    247   if (is_devtools_client_)
    248     return;
    249   is_devtools_client_ = true;
    250   new DevToolsClient(static_cast<RenderViewImpl*>(render_view()));
    251 }
    252 
    253 WebDevToolsAgent* DevToolsAgent::GetWebAgent() {
    254   WebView* web_view = render_view()->GetWebView();
    255   if (!web_view)
    256     return NULL;
    257   return web_view->devToolsAgent();
    258 }
    259 
    260 bool DevToolsAgent::IsAttached() {
    261   return is_attached_;
    262 }
    263 
    264 }  // namespace content
    265