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