1// Copyright 2014 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/embedded_worker_devtools_manager.h"
6
7#include "content/browser/devtools/devtools_protocol.h"
8#include "content/browser/devtools/devtools_protocol_constants.h"
9#include "content/browser/devtools/embedded_worker_devtools_agent_host.h"
10#include "content/browser/devtools/ipc_devtools_agent_host.h"
11#include "content/browser/shared_worker/shared_worker_instance.h"
12#include "content/common/devtools_messages.h"
13#include "content/public/browser/browser_thread.h"
14#include "content/public/browser/render_process_host.h"
15#include "content/public/browser/worker_service.h"
16#include "ipc/ipc_listener.h"
17
18namespace content {
19
20// Called on the UI thread.
21// static
22scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForWorker(
23    int worker_process_id,
24    int worker_route_id) {
25  return EmbeddedWorkerDevToolsManager::GetInstance()
26      ->GetDevToolsAgentHostForWorker(worker_process_id, worker_route_id);
27}
28
29EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
30    const ServiceWorkerContextCore* context,
31    base::WeakPtr<ServiceWorkerContextCore> context_weak,
32    int64 version_id,
33    const GURL& url)
34    : context_(context),
35      context_weak_(context_weak),
36      version_id_(version_id),
37      url_(url) {
38}
39
40EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
41    const ServiceWorkerIdentifier& other)
42    : context_(other.context_),
43      context_weak_(other.context_weak_),
44      version_id_(other.version_id_),
45      url_(other.url_) {
46}
47
48EmbeddedWorkerDevToolsManager::
49ServiceWorkerIdentifier::~ServiceWorkerIdentifier() {
50}
51
52bool EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::Matches(
53    const ServiceWorkerIdentifier& other) const {
54  return context_ == other.context_ && version_id_ == other.version_id_;
55}
56
57const ServiceWorkerContextCore*
58EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::context() const {
59  return context_;
60}
61
62base::WeakPtr<ServiceWorkerContextCore>
63EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::context_weak() const {
64  return context_weak_;
65}
66
67int64
68EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::version_id() const {
69  return version_id_;
70}
71
72GURL EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::url() const {
73  return url_;
74}
75
76// static
77EmbeddedWorkerDevToolsManager* EmbeddedWorkerDevToolsManager::GetInstance() {
78  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79  return Singleton<EmbeddedWorkerDevToolsManager>::get();
80}
81
82DevToolsAgentHostImpl*
83EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForWorker(
84    int worker_process_id,
85    int worker_route_id) {
86  AgentHostMap::iterator it = workers_.find(
87      WorkerId(worker_process_id, worker_route_id));
88  return it == workers_.end() ? NULL : it->second;
89}
90
91EmbeddedWorkerDevToolsManager::EmbeddedWorkerDevToolsManager()
92    : debug_service_worker_on_start_(false) {
93}
94
95EmbeddedWorkerDevToolsManager::~EmbeddedWorkerDevToolsManager() {
96}
97
98bool EmbeddedWorkerDevToolsManager::SharedWorkerCreated(
99    int worker_process_id,
100    int worker_route_id,
101    const SharedWorkerInstance& instance) {
102  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
103  const WorkerId id(worker_process_id, worker_route_id);
104  AgentHostMap::iterator it = FindExistingSharedWorkerAgentHost(instance);
105  if (it == workers_.end()) {
106    workers_[id] = new EmbeddedWorkerDevToolsAgentHost(id, instance);
107    return false;
108  }
109  WorkerRestarted(id, it);
110  return true;
111}
112
113bool EmbeddedWorkerDevToolsManager::ServiceWorkerCreated(
114    int worker_process_id,
115    int worker_route_id,
116    const ServiceWorkerIdentifier& service_worker_id) {
117  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
118  const WorkerId id(worker_process_id, worker_route_id);
119  AgentHostMap::iterator it =
120      FindExistingServiceWorkerAgentHost(service_worker_id);
121  if (it == workers_.end()) {
122    workers_[id] = new EmbeddedWorkerDevToolsAgentHost(
123        id, service_worker_id, debug_service_worker_on_start_);
124    return debug_service_worker_on_start_;
125  }
126  WorkerRestarted(id, it);
127  return true;
128}
129
130void EmbeddedWorkerDevToolsManager::WorkerDestroyed(int worker_process_id,
131                                                    int worker_route_id) {
132  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
133  const WorkerId id(worker_process_id, worker_route_id);
134  AgentHostMap::iterator it = workers_.find(id);
135  DCHECK(it != workers_.end());
136  it->second->WorkerDestroyed();
137}
138
139void EmbeddedWorkerDevToolsManager::WorkerReadyForInspection(
140    int worker_process_id,
141    int worker_route_id) {
142  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143  const WorkerId id(worker_process_id, worker_route_id);
144  AgentHostMap::iterator it = workers_.find(id);
145  DCHECK(it != workers_.end());
146  it->second->WorkerReadyForInspection();
147}
148
149void EmbeddedWorkerDevToolsManager::WorkerContextStarted(int worker_process_id,
150                                                         int worker_route_id) {
151  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152  const WorkerId id(worker_process_id, worker_route_id);
153  AgentHostMap::iterator it = workers_.find(id);
154  DCHECK(it != workers_.end());
155  it->second->WorkerContextStarted();
156}
157
158void EmbeddedWorkerDevToolsManager::RemoveInspectedWorkerData(WorkerId id) {
159  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160  workers_.erase(id);
161}
162
163EmbeddedWorkerDevToolsManager::AgentHostMap::iterator
164EmbeddedWorkerDevToolsManager::FindExistingSharedWorkerAgentHost(
165    const SharedWorkerInstance& instance) {
166  AgentHostMap::iterator it = workers_.begin();
167  for (; it != workers_.end(); ++it) {
168    if (it->second->Matches(instance))
169      break;
170  }
171  return it;
172}
173
174EmbeddedWorkerDevToolsManager::AgentHostMap::iterator
175EmbeddedWorkerDevToolsManager::FindExistingServiceWorkerAgentHost(
176    const ServiceWorkerIdentifier& service_worker_id) {
177  AgentHostMap::iterator it = workers_.begin();
178  for (; it != workers_.end(); ++it) {
179    if (it->second->Matches(service_worker_id))
180      break;
181  }
182  return it;
183}
184
185DevToolsAgentHost::List
186EmbeddedWorkerDevToolsManager::GetOrCreateAllAgentHosts() {
187  DevToolsAgentHost::List result;
188  EmbeddedWorkerDevToolsManager* instance = GetInstance();
189  for (AgentHostMap::iterator it = instance->workers_.begin();
190      it != instance->workers_.end(); ++it) {
191    if (!it->second->IsTerminated())
192      result.push_back(it->second);
193  }
194  return result;
195}
196
197void EmbeddedWorkerDevToolsManager::WorkerRestarted(
198    const WorkerId& id,
199    const AgentHostMap::iterator& it) {
200  EmbeddedWorkerDevToolsAgentHost* agent_host = it->second;
201  agent_host->WorkerRestarted(id);
202  workers_.erase(it);
203  workers_[id] = agent_host;
204}
205
206void EmbeddedWorkerDevToolsManager::ResetForTesting() {
207  workers_.clear();
208}
209
210}  // namespace content
211