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