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_agent_host_impl.h" 6 7 #include <map> 8 #include <vector> 9 10 #include "base/basictypes.h" 11 #include "base/guid.h" 12 #include "base/lazy_instance.h" 13 #include "content/browser/devtools/devtools_manager.h" 14 #include "content/browser/devtools/embedded_worker_devtools_manager.h" 15 #include "content/browser/devtools/forwarding_agent_host.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "content/public/browser/devtools_manager_delegate.h" 18 19 namespace content { 20 21 namespace { 22 typedef std::map<std::string, DevToolsAgentHostImpl*> Instances; 23 base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER; 24 25 typedef std::vector<const DevToolsAgentHost::AgentStateCallback*> 26 AgentStateCallbacks; 27 base::LazyInstance<AgentStateCallbacks>::Leaky g_callbacks = 28 LAZY_INSTANCE_INITIALIZER; 29 } // namespace 30 31 // static 32 DevToolsAgentHost::List DevToolsAgentHost::GetOrCreateAll() { 33 List result = EmbeddedWorkerDevToolsManager::GetInstance() 34 ->GetOrCreateAllAgentHosts(); 35 std::vector<WebContents*> wc_list = 36 DevToolsAgentHostImpl::GetInspectableWebContents(); 37 for (std::vector<WebContents*>::iterator it = wc_list.begin(); 38 it != wc_list.end(); ++it) { 39 result.push_back(GetOrCreateFor(*it)); 40 } 41 return result; 42 } 43 44 DevToolsAgentHostImpl::DevToolsAgentHostImpl() 45 : id_(base::GenerateGUID()), 46 client_(NULL) { 47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 48 g_instances.Get()[id_] = this; 49 } 50 51 DevToolsAgentHostImpl::~DevToolsAgentHostImpl() { 52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 53 g_instances.Get().erase(g_instances.Get().find(id_)); 54 } 55 56 // static 57 scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForId( 58 const std::string& id) { 59 if (g_instances == NULL) 60 return NULL; 61 Instances::iterator it = g_instances.Get().find(id); 62 if (it == g_instances.Get().end()) 63 return NULL; 64 return it->second; 65 } 66 67 //static 68 scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::Create( 69 DevToolsExternalAgentProxyDelegate* delegate) { 70 return new ForwardingAgentHost(delegate); 71 } 72 73 void DevToolsAgentHostImpl::AttachClient(DevToolsAgentHostClient* client) { 74 scoped_refptr<DevToolsAgentHostImpl> protect(this); 75 if (client_) { 76 client_->AgentHostClosed(this, true); 77 Detach(); 78 } else { 79 DevToolsManager::GetInstance()->OnClientAttached(); 80 } 81 client_ = client; 82 Attach(); 83 } 84 85 void DevToolsAgentHostImpl::DetachClient() { 86 if (!client_) 87 return; 88 89 scoped_refptr<DevToolsAgentHostImpl> protect(this); 90 client_ = NULL; 91 DevToolsManager::GetInstance()->OnClientDetached(); 92 Detach(); 93 } 94 95 bool DevToolsAgentHostImpl::IsAttached() { 96 return !!client_; 97 } 98 99 void DevToolsAgentHostImpl::InspectElement(int x, int y) { 100 } 101 102 std::string DevToolsAgentHostImpl::GetId() { 103 return id_; 104 } 105 106 WebContents* DevToolsAgentHostImpl::GetWebContents() { 107 return NULL; 108 } 109 110 void DevToolsAgentHostImpl::DisconnectWebContents() { 111 } 112 113 void DevToolsAgentHostImpl::ConnectWebContents(WebContents* wc) { 114 } 115 116 bool DevToolsAgentHostImpl::IsWorker() const { 117 return false; 118 } 119 120 void DevToolsAgentHostImpl::HostClosed() { 121 if (!client_) 122 return; 123 124 scoped_refptr<DevToolsAgentHostImpl> protect(this); 125 // Clear |client_| before notifying it. 126 DevToolsAgentHostClient* client = client_; 127 client_ = NULL; 128 DevToolsManager::GetInstance()->OnClientDetached(); 129 client->AgentHostClosed(this, false); 130 } 131 132 void DevToolsAgentHostImpl::SendMessageToClient(const std::string& message) { 133 if (!client_) 134 return; 135 client_->DispatchProtocolMessage(this, message); 136 } 137 138 // static 139 void DevToolsAgentHost::DetachAllClients() { 140 if (g_instances == NULL) 141 return; 142 143 // Make a copy, since detaching may lead to agent destruction, which 144 // removes it from the instances. 145 Instances copy = g_instances.Get(); 146 for (Instances::iterator it(copy.begin()); it != copy.end(); ++it) { 147 DevToolsAgentHostImpl* agent_host = it->second; 148 if (agent_host->client_) { 149 scoped_refptr<DevToolsAgentHostImpl> protect(agent_host); 150 // Clear |client_| before notifying it. 151 DevToolsAgentHostClient* client = agent_host->client_; 152 agent_host->client_ = NULL; 153 DevToolsManager::GetInstance()->OnClientDetached(); 154 client->AgentHostClosed(agent_host, true); 155 agent_host->Detach(); 156 } 157 } 158 } 159 160 // static 161 void DevToolsAgentHost::AddAgentStateCallback( 162 const AgentStateCallback& callback) { 163 g_callbacks.Get().push_back(&callback); 164 } 165 166 // static 167 void DevToolsAgentHost::RemoveAgentStateCallback( 168 const AgentStateCallback& callback) { 169 if (g_callbacks == NULL) 170 return; 171 172 AgentStateCallbacks* callbacks_ = g_callbacks.Pointer(); 173 AgentStateCallbacks::iterator it = 174 std::find(callbacks_->begin(), callbacks_->end(), &callback); 175 DCHECK(it != callbacks_->end()); 176 callbacks_->erase(it); 177 } 178 179 // static 180 void DevToolsAgentHostImpl::NotifyCallbacks( 181 DevToolsAgentHostImpl* agent_host, bool attached) { 182 AgentStateCallbacks copy(g_callbacks.Get()); 183 DevToolsManager* manager = DevToolsManager::GetInstance(); 184 if (manager->delegate()) 185 manager->delegate()->DevToolsAgentStateChanged(agent_host, attached); 186 for (AgentStateCallbacks::iterator it = copy.begin(); it != copy.end(); ++it) 187 (*it)->Run(agent_host, attached); 188 } 189 190 void DevToolsAgentHostImpl::Inspect(BrowserContext* browser_context) { 191 DevToolsManager* manager = DevToolsManager::GetInstance(); 192 if (manager->delegate()) 193 manager->delegate()->Inspect(browser_context, this); 194 } 195 196 } // namespace content 197