OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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/debugger/worker_devtools_manager_io.h" |
| 6 |
| 7 #include <list> |
| 8 |
| 9 #include "base/tuple.h" |
| 10 #include "chrome/browser/profiles/profile_manager.h" |
| 11 #include "content/browser/browser_thread.h" |
| 12 #include "content/browser/debugger/devtools_manager.h" |
| 13 #include "content/browser/debugger/devtools_window.h" |
| 14 #include "content/browser/debugger/worker_devtools_message_filter.h" |
| 15 #include "content/browser/worker_host/worker_process_host.h" |
| 16 #include "content/common/devtools_messages.h" |
| 17 |
| 18 namespace { |
| 19 |
| 20 void NotifyWorkerDevToolsClientClosingOnIOThread(int worker_process_host_id, |
| 21 int worker_route_id) { |
| 22 WorkerDevToolsManagerIO::GetInstance()->WorkerDevToolsClientClosing( |
| 23 worker_process_host_id, |
| 24 worker_route_id); |
| 25 } |
| 26 |
| 27 class ClientsUI : public DevToolsClientHost::CloseListener { |
| 28 public: |
| 29 static ClientsUI* GetInstance() { |
| 30 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 31 static ClientsUI* instance = new ClientsUI(); |
| 32 return instance; |
| 33 } |
| 34 |
| 35 DevToolsClientHost* FindDevToolsClient(int worker_process_host_id, |
| 36 int worker_route_id) { |
| 37 WorkerIdToClientHostMap::iterator it = |
| 38 worker_id_to_client_host_.find(WorkerId(worker_process_host_id, |
| 39 worker_route_id)); |
| 40 if (it == worker_id_to_client_host_.end()) |
| 41 return NULL; |
| 42 return it->second; |
| 43 } |
| 44 |
| 45 bool FindWorkerInfo(DevToolsClientHost* client_host, |
| 46 int* host_id, |
| 47 int* route_id) { |
| 48 for (WorkerIdToClientHostMap::const_iterator it = |
| 49 worker_id_to_client_host_.begin(); |
| 50 it != worker_id_to_client_host_.end(); ++it) { |
| 51 if (it->second == client_host) { |
| 52 WorkerId id = it->first; |
| 53 *host_id = id.first; |
| 54 *route_id = id.second; |
| 55 return true; |
| 56 } |
| 57 } |
| 58 return false; |
| 59 } |
| 60 |
| 61 void RegisterDevToolsClientForWorker(int worker_process_host_id, |
| 62 int worker_route_id, |
| 63 DevToolsClientHost* client) { |
| 64 client->set_close_listener(this); |
| 65 WorkerId worker_id(worker_process_host_id, worker_route_id); |
| 66 worker_id_to_client_host_[worker_id] = client; |
| 67 } |
| 68 |
| 69 private: |
| 70 ClientsUI() {} |
| 71 virtual ~ClientsUI() {} |
| 72 |
| 73 virtual void ClientHostClosing(DevToolsClientHost* host) { |
| 74 WorkerIdToClientHostMap::iterator it = worker_id_to_client_host_.begin(); |
| 75 for (; it != worker_id_to_client_host_.end(); ++it) { |
| 76 if (it->second == host) { |
| 77 WorkerId id = it->first; |
| 78 BrowserThread::PostTask( |
| 79 BrowserThread::IO, FROM_HERE, |
| 80 NewRunnableFunction(NotifyWorkerDevToolsClientClosingOnIOThread, |
| 81 id.first, id.second)); |
| 82 worker_id_to_client_host_.erase(it); |
| 83 return; |
| 84 } |
| 85 } |
| 86 } |
| 87 |
| 88 typedef std::pair<int, int> WorkerId; |
| 89 typedef std::map<WorkerId, DevToolsClientHost*> WorkerIdToClientHostMap; |
| 90 WorkerIdToClientHostMap worker_id_to_client_host_; |
| 91 |
| 92 DISALLOW_COPY_AND_ASSIGN(ClientsUI); |
| 93 }; |
| 94 |
| 95 } // namespace |
| 96 |
| 97 class WorkerDevToolsManagerIO::InspectedWorkersList { |
| 98 public: |
| 99 InspectedWorkersList() {} |
| 100 |
| 101 void AddInstance(WorkerProcessHost* host, int route_id) { |
| 102 DCHECK(!Contains(host->id(), route_id)); |
| 103 map_.push_back(Entry(host, route_id)); |
| 104 } |
| 105 |
| 106 bool Contains(int host_id, int route_id) { |
| 107 return FindHost(host_id, route_id) != NULL; |
| 108 } |
| 109 |
| 110 WorkerProcessHost* FindHost(int host_id, int route_id) { |
| 111 Entries::iterator it = FindEntry(host_id, route_id); |
| 112 if (it == map_.end()) |
| 113 return NULL; |
| 114 return it->host; |
| 115 } |
| 116 |
| 117 WorkerProcessHost* RemoveInstance(int host_id, int route_id) { |
| 118 Entries::iterator it = FindEntry(host_id, route_id); |
| 119 if (it == map_.end()) |
| 120 return NULL; |
| 121 WorkerProcessHost* host = it->host; |
| 122 map_.erase(it); |
| 123 return host; |
| 124 } |
| 125 |
| 126 void WorkerDevToolsMessageFilterClosing(int worker_process_host_id) { |
| 127 Entries::iterator it = map_.begin(); |
| 128 while (it != map_.end()) { |
| 129 if (it->host->id() == worker_process_host_id) |
| 130 it = map_.erase(it); |
| 131 else |
| 132 ++it; |
| 133 } |
| 134 } |
| 135 |
| 136 private: |
| 137 struct Entry { |
| 138 Entry(WorkerProcessHost* host, int route_id) |
| 139 : host(host), |
| 140 route_id(route_id) {} |
| 141 WorkerProcessHost* const host; |
| 142 int const route_id; |
| 143 }; |
| 144 typedef std::list<Entry> Entries; |
| 145 |
| 146 Entries::iterator FindEntry(int host_id, int route_id) { |
| 147 Entries::iterator it = map_.begin(); |
| 148 while (it != map_.end()) { |
| 149 if (it->host->id() == host_id && it->route_id == route_id) |
| 150 break; |
| 151 } |
| 152 return it; |
| 153 } |
| 154 |
| 155 Entries map_; |
| 156 DISALLOW_COPY_AND_ASSIGN(InspectedWorkersList); |
| 157 }; |
| 158 |
| 159 // static |
| 160 WorkerDevToolsManagerIO* WorkerDevToolsManagerIO::GetInstance() { |
| 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 162 return Singleton<WorkerDevToolsManagerIO>::get(); |
| 163 } |
| 164 |
| 165 WorkerDevToolsManagerIO::WorkerDevToolsManagerIO() |
| 166 : inspected_workers_(new InspectedWorkersList()) { |
| 167 } |
| 168 |
| 169 WorkerDevToolsManagerIO::~WorkerDevToolsManagerIO() { |
| 170 } |
| 171 |
| 172 bool WorkerDevToolsManagerIO::ForwardToWorkerDevToolsAgentOnUIThread( |
| 173 DevToolsClientHost* from, |
| 174 const IPC::Message& message) { |
| 175 int worker_process_host_id; |
| 176 int worker_route_id; |
| 177 if (!ClientsUI::GetInstance()->FindWorkerInfo( |
| 178 from, &worker_process_host_id, &worker_route_id)) |
| 179 return false; |
| 180 BrowserThread::PostTask( |
| 181 BrowserThread::IO, FROM_HERE, |
| 182 NewRunnableFunction( |
| 183 ForwardToWorkerDevToolsAgentOnIOThread, |
| 184 worker_process_host_id, |
| 185 worker_route_id, |
| 186 IPC::Message(message))); |
| 187 return true; |
| 188 } |
| 189 |
| 190 static void OpenDevToolsForWorkerOnUIThread(int worker_process_host_id, |
| 191 int worker_route_id) { |
| 192 Profile* profile = ProfileManager::GetDefaultProfile(); |
| 193 if (!profile) |
| 194 return; |
| 195 DevToolsWindow* window = DevToolsWindow::CreateDevToolsWindowForWorker( |
| 196 profile); |
| 197 window->Show(DEVTOOLS_TOGGLE_ACTION_NONE); |
| 198 ClientsUI::GetInstance()->RegisterDevToolsClientForWorker( |
| 199 worker_process_host_id, worker_route_id, window); |
| 200 } |
| 201 |
| 202 static WorkerProcessHost* FindWorkerProcessHostForWorker( |
| 203 int worker_process_host_id, |
| 204 int worker_route_id) { |
| 205 BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 206 for (; !iter.Done(); ++iter) { |
| 207 if (iter->id() != worker_process_host_id) |
| 208 continue; |
| 209 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 210 const WorkerProcessHost::Instances& instances = worker->instances(); |
| 211 for (WorkerProcessHost::Instances::const_iterator i = instances.begin(); |
| 212 i != instances.end(); ++i) { |
| 213 if (i->shared() && i->worker_route_id() == worker_route_id) |
| 214 return worker; |
| 215 } |
| 216 return NULL; |
| 217 } |
| 218 return NULL; |
| 219 } |
| 220 |
| 221 void WorkerDevToolsManagerIO::OpenDevToolsForWorker(int worker_process_host_id, |
| 222 int worker_route_id) { |
| 223 WorkerProcessHost* host = FindWorkerProcessHostForWorker( |
| 224 worker_process_host_id, |
| 225 worker_route_id); |
| 226 if (!host) |
| 227 return; |
| 228 |
| 229 // DevTools client is already attached. |
| 230 if (inspected_workers_->Contains(worker_process_host_id, worker_route_id)) |
| 231 return; |
| 232 |
| 233 host->Send(new WorkerDevToolsAgentMsg_Attach(worker_route_id)); |
| 234 |
| 235 inspected_workers_->AddInstance(host, worker_route_id); |
| 236 BrowserThread::PostTask( |
| 237 BrowserThread::UI, FROM_HERE, |
| 238 NewRunnableFunction( |
| 239 OpenDevToolsForWorkerOnUIThread, |
| 240 worker_process_host_id, |
| 241 worker_route_id)); |
| 242 } |
| 243 |
| 244 void WorkerDevToolsManagerIO::WorkerDevToolsClientClosing( |
| 245 int worker_process_host_id, |
| 246 int worker_route_id) { |
| 247 WorkerProcessHost* host = inspected_workers_->RemoveInstance( |
| 248 worker_process_host_id, worker_route_id); |
| 249 if (host) |
| 250 host->Send(new WorkerDevToolsAgentMsg_Detach(worker_route_id)); |
| 251 } |
| 252 |
| 253 static void ForwardToDevToolsClientOnUIThread( |
| 254 int worker_process_host_id, |
| 255 int worker_route_id, |
| 256 const IPC::Message& message) { |
| 257 DevToolsClientHost* client = ClientsUI::GetInstance()-> |
| 258 FindDevToolsClient(worker_process_host_id, worker_route_id); |
| 259 if (client) |
| 260 client->SendMessageToClient(message); |
| 261 } |
| 262 |
| 263 void WorkerDevToolsManagerIO::ForwardToDevToolsClient( |
| 264 int worker_process_host_id, |
| 265 int worker_route_id, |
| 266 const IPC::Message& message) { |
| 267 if (!inspected_workers_->Contains(worker_process_host_id, worker_route_id)) { |
| 268 NOTREACHED(); |
| 269 return; |
| 270 } |
| 271 BrowserThread::PostTask( |
| 272 BrowserThread::UI, FROM_HERE, |
| 273 NewRunnableFunction( |
| 274 ForwardToDevToolsClientOnUIThread, |
| 275 worker_process_host_id, |
| 276 worker_route_id, |
| 277 IPC::Message(message))); |
| 278 } |
| 279 |
| 280 void WorkerDevToolsManagerIO::WorkerProcessDestroying( |
| 281 int worker_process_host_id) { |
| 282 inspected_workers_->WorkerDevToolsMessageFilterClosing( |
| 283 worker_process_host_id); |
| 284 } |
| 285 |
| 286 void WorkerDevToolsManagerIO::ForwardToWorkerDevToolsAgentOnIOThread( |
| 287 int worker_process_host_id, |
| 288 int worker_route_id, |
| 289 const IPC::Message& message) { |
| 290 WorkerDevToolsManagerIO::GetInstance()->ForwardToWorkerDevToolsAgent( |
| 291 worker_process_host_id, worker_route_id, message); |
| 292 } |
| 293 |
| 294 void WorkerDevToolsManagerIO::ForwardToWorkerDevToolsAgent( |
| 295 int worker_process_host_id, |
| 296 int worker_route_id, |
| 297 const IPC::Message& message) { |
| 298 WorkerProcessHost* host = inspected_workers_->FindHost( |
| 299 worker_process_host_id, |
| 300 worker_route_id); |
| 301 if (!host) |
| 302 return; |
| 303 IPC::Message* msg = new IPC::Message(message); |
| 304 msg->set_routing_id(worker_route_id); |
| 305 host->Send(msg); |
| 306 } |
OLD | NEW |