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/browser/devtools/devtools_manager_impl.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "content/browser/devtools/devtools_netlog_observer.h"
     12 #include "content/browser/devtools/render_view_devtools_agent_host.h"
     13 #include "content/browser/renderer_host/render_view_host_impl.h"
     14 #include "content/browser/web_contents/web_contents_impl.h"
     15 #include "content/public/browser/browser_thread.h"
     16 #include "content/public/browser/content_browser_client.h"
     17 #include "content/public/browser/devtools_client_host.h"
     18 #include "content/public/browser/devtools_manager_delegate.h"
     19 
     20 namespace content {
     21 
     22 // static
     23 DevToolsManager* DevToolsManager::GetInstance() {
     24   return DevToolsManagerImpl::GetInstance();
     25 }
     26 
     27 // static
     28 DevToolsManagerImpl* DevToolsManagerImpl::GetInstance() {
     29   return Singleton<DevToolsManagerImpl>::get();
     30 }
     31 
     32 DevToolsManagerImpl::DevToolsManagerImpl()
     33     : delegate_(GetContentClient()->browser()->GetDevToolsManagerDelegate()) {
     34 }
     35 
     36 DevToolsManagerImpl::~DevToolsManagerImpl() {
     37   DCHECK(agent_to_client_host_.empty());
     38   DCHECK(client_to_agent_host_.empty());
     39 }
     40 
     41 void DevToolsManagerImpl::Inspect(BrowserContext* browser_context,
     42                                   DevToolsAgentHost* agent_host) {
     43   if (delegate_)
     44     delegate_->Inspect(browser_context, agent_host);
     45 }
     46 
     47 DevToolsClientHost* DevToolsManagerImpl::GetDevToolsClientHostFor(
     48     DevToolsAgentHostImpl* agent_host_impl) {
     49   AgentToClientHostMap::iterator it =
     50       agent_to_client_host_.find(agent_host_impl);
     51   if (it != agent_to_client_host_.end())
     52     return it->second;
     53   return NULL;
     54 }
     55 
     56 DevToolsAgentHost* DevToolsManagerImpl::GetDevToolsAgentHostFor(
     57     DevToolsClientHost* client_host) {
     58   ClientToAgentHostMap::iterator it = client_to_agent_host_.find(client_host);
     59   if (it != client_to_agent_host_.end())
     60     return it->second.get();
     61   return NULL;
     62 }
     63 
     64 void DevToolsManagerImpl::RegisterDevToolsClientHostFor(
     65     DevToolsAgentHost* agent_host,
     66     DevToolsClientHost* client_host) {
     67   DevToolsAgentHostImpl* agent_host_impl =
     68       static_cast<DevToolsAgentHostImpl*>(agent_host);
     69   DevToolsClientHost* old_client_host =
     70       GetDevToolsClientHostFor(agent_host_impl);
     71   if (old_client_host) {
     72     old_client_host->ReplacedWithAnotherClient();
     73     UnregisterDevToolsClientHostFor(agent_host_impl);
     74   }
     75   BindClientHost(agent_host_impl, client_host);
     76   agent_host_impl->Attach();
     77 }
     78 
     79 bool DevToolsManagerImpl::DispatchOnInspectorBackend(
     80     DevToolsClientHost* from,
     81     const std::string& message) {
     82   DevToolsAgentHost* agent_host = GetDevToolsAgentHostFor(from);
     83   if (!agent_host)
     84     return false;
     85   DevToolsAgentHostImpl* agent_host_impl =
     86       static_cast<DevToolsAgentHostImpl*>(agent_host);
     87   agent_host_impl->DispatchOnInspectorBackend(message);
     88   return true;
     89 }
     90 
     91 void DevToolsManagerImpl::DispatchOnInspectorFrontend(
     92     DevToolsAgentHost* agent_host,
     93     const std::string& message) {
     94   DevToolsAgentHostImpl* agent_host_impl =
     95       static_cast<DevToolsAgentHostImpl*>(agent_host);
     96   DevToolsClientHost* client_host = GetDevToolsClientHostFor(agent_host_impl);
     97   if (!client_host) {
     98     // Client window was closed while there were messages
     99     // being sent to it.
    100     return;
    101   }
    102   client_host->DispatchOnInspectorFrontend(message);
    103 }
    104 
    105 void DevToolsManagerImpl::ClientHostClosing(DevToolsClientHost* client_host) {
    106   DevToolsAgentHost* agent_host = GetDevToolsAgentHostFor(client_host);
    107   if (!agent_host)
    108     return;
    109   DevToolsAgentHostImpl* agent_host_impl =
    110       static_cast<DevToolsAgentHostImpl*>(agent_host);
    111   UnbindClientHost(agent_host_impl, client_host);
    112 }
    113 
    114 void DevToolsManagerImpl::AgentHostClosing(DevToolsAgentHostImpl* agent_host) {
    115   UnregisterDevToolsClientHostFor(agent_host);
    116 }
    117 
    118 void DevToolsManagerImpl::UnregisterDevToolsClientHostFor(
    119     DevToolsAgentHostImpl* agent_host_impl) {
    120   DevToolsClientHost* client_host = GetDevToolsClientHostFor(agent_host_impl);
    121   if (!client_host)
    122     return;
    123   UnbindClientHost(agent_host_impl, client_host);
    124   client_host->InspectedContentsClosing();
    125 }
    126 
    127 void DevToolsManagerImpl::BindClientHost(
    128     DevToolsAgentHostImpl* agent_host,
    129     DevToolsClientHost* client_host) {
    130   DCHECK(agent_to_client_host_.find(agent_host) ==
    131       agent_to_client_host_.end());
    132   DCHECK(client_to_agent_host_.find(client_host) ==
    133       client_to_agent_host_.end());
    134 
    135   if (client_to_agent_host_.empty()) {
    136     BrowserThread::PostTask(
    137         BrowserThread::IO,
    138         FROM_HERE,
    139         base::Bind(&DevToolsNetLogObserver::Attach));
    140   }
    141   agent_to_client_host_[agent_host] = client_host;
    142   client_to_agent_host_[client_host] = agent_host;
    143   agent_host->set_close_listener(this);
    144 }
    145 
    146 void DevToolsManagerImpl::UnbindClientHost(DevToolsAgentHostImpl* agent_host,
    147                                            DevToolsClientHost* client_host) {
    148   DCHECK(agent_host);
    149   scoped_refptr<DevToolsAgentHostImpl> protect(agent_host);
    150   DCHECK(agent_to_client_host_.find(agent_host)->second ==
    151       client_host);
    152   DCHECK(client_to_agent_host_.find(client_host)->second.get() == agent_host);
    153   agent_host->set_close_listener(NULL);
    154 
    155   agent_to_client_host_.erase(agent_host);
    156   client_to_agent_host_.erase(client_host);
    157 
    158   if (client_to_agent_host_.empty()) {
    159     BrowserThread::PostTask(
    160         BrowserThread::IO,
    161         FROM_HERE,
    162         base::Bind(&DevToolsNetLogObserver::Detach));
    163   }
    164   // Lazy agent hosts can be deleted from within detach.
    165   // Do not access agent_host below this line.
    166   agent_host->Detach();
    167 }
    168 
    169 void DevToolsManagerImpl::CloseAllClientHosts() {
    170   std::vector<DevToolsAgentHostImpl*> agents;
    171   for (AgentToClientHostMap::iterator it =
    172            agent_to_client_host_.begin();
    173        it != agent_to_client_host_.end(); ++it) {
    174     agents.push_back(it->first);
    175   }
    176   for (std::vector<DevToolsAgentHostImpl*>::iterator it = agents.begin();
    177        it != agents.end(); ++it) {
    178     UnregisterDevToolsClientHostFor(*it);
    179   }
    180 }
    181 
    182 void DevToolsManagerImpl::AddAgentStateCallback(const Callback& callback) {
    183   callbacks_.push_back(&callback);
    184 }
    185 
    186 void DevToolsManagerImpl::RemoveAgentStateCallback(const Callback& callback) {
    187   CallbackContainer::iterator it =
    188       std::find(callbacks_.begin(), callbacks_.end(), &callback);
    189   DCHECK(it != callbacks_.end());
    190   callbacks_.erase(it);
    191 }
    192 
    193 void DevToolsManagerImpl::NotifyObservers(DevToolsAgentHost* agent_host,
    194                                           bool attached) {
    195   CallbackContainer copy(callbacks_);
    196   if (delegate_)
    197     delegate_->DevToolsAgentStateChanged(agent_host, attached);
    198   for (CallbackContainer::iterator it = copy.begin(); it != copy.end(); ++it)
    199      (*it)->Run(agent_host, attached);
    200 }
    201 
    202 }  // namespace content
    203