1 // Copyright 2013 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.
5 #include "content/browser/service_worker/embedded_worker_registry.h"
7 #include "base/bind_helpers.h"
8 #include "base/stl_util.h"
9 #include "content/browser/renderer_host/render_widget_helper.h"
10 #include "content/browser/service_worker/embedded_worker_instance.h"
11 #include "content/browser/service_worker/service_worker_context_core.h"
12 #include "content/browser/service_worker/service_worker_context_wrapper.h"
13 #include "content/common/service_worker/embedded_worker_messages.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "ipc/ipc_message.h"
16 #include "ipc/ipc_sender.h"
20 EmbeddedWorkerRegistry::EmbeddedWorkerRegistry(
21 base::WeakPtr<ServiceWorkerContextCore> context)
23 next_embedded_worker_id_(0) {}
25 scoped_ptr<EmbeddedWorkerInstance> EmbeddedWorkerRegistry::CreateWorker() {
26 scoped_ptr<EmbeddedWorkerInstance> worker(
27 new EmbeddedWorkerInstance(this, next_embedded_worker_id_));
28 worker_map_[next_embedded_worker_id_++] = worker.get();
32 void EmbeddedWorkerRegistry::StartWorker(const std::vector<int>& process_ids,
33 int embedded_worker_id,
34 int64 service_worker_version_id,
36 const GURL& script_url,
37 const StatusCallback& callback) {
39 callback.Run(SERVICE_WORKER_ERROR_ABORT);
42 scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
43 new EmbeddedWorkerMsg_StartWorker_Params());
44 params->embedded_worker_id = embedded_worker_id;
45 params->service_worker_version_id = service_worker_version_id;
46 params->scope = scope;
47 params->script_url = script_url;
48 params->worker_devtools_agent_route_id = MSG_ROUTING_NONE;
49 context_->process_manager()->AllocateWorkerProcess(
52 base::Bind(&EmbeddedWorkerRegistry::StartWorkerWithProcessId,
55 base::Passed(¶ms),
59 ServiceWorkerStatusCode EmbeddedWorkerRegistry::StopWorker(
60 int process_id, int embedded_worker_id) {
62 context_->process_manager()->ReleaseWorkerProcess(process_id);
63 return Send(process_id,
64 new EmbeddedWorkerMsg_StopWorker(embedded_worker_id));
67 bool EmbeddedWorkerRegistry::OnMessageReceived(const IPC::Message& message) {
68 // TODO(kinuko): Move all EmbeddedWorker message handling from
69 // ServiceWorkerDispatcherHost.
71 WorkerInstanceMap::iterator found = worker_map_.find(message.routing_id());
72 if (found == worker_map_.end()) {
73 LOG(ERROR) << "Worker " << message.routing_id() << " not registered";
76 return found->second->OnMessageReceived(message);
79 void EmbeddedWorkerRegistry::Shutdown() {
80 for (WorkerInstanceMap::iterator it = worker_map_.begin();
81 it != worker_map_.end();
87 void EmbeddedWorkerRegistry::OnWorkerScriptLoaded(int process_id,
88 int embedded_worker_id) {
89 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
90 if (found == worker_map_.end()) {
91 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
94 if (found->second->process_id() != process_id) {
95 LOG(ERROR) << "Incorrect embedded_worker_id";
98 found->second->OnScriptLoaded();
101 void EmbeddedWorkerRegistry::OnWorkerScriptLoadFailed(int process_id,
102 int embedded_worker_id) {
103 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
104 if (found == worker_map_.end()) {
105 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
108 if (found->second->process_id() != process_id) {
109 LOG(ERROR) << "Incorrect embedded_worker_id";
112 found->second->OnScriptLoadFailed();
115 void EmbeddedWorkerRegistry::OnWorkerStarted(
116 int process_id, int thread_id, int embedded_worker_id) {
117 DCHECK(!ContainsKey(worker_process_map_, process_id) ||
118 worker_process_map_[process_id].count(embedded_worker_id) == 0);
119 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
120 if (found == worker_map_.end()) {
121 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
124 if (found->second->process_id() != process_id) {
125 LOG(ERROR) << "Incorrect embedded_worker_id";
128 worker_process_map_[process_id].insert(embedded_worker_id);
129 found->second->OnStarted(thread_id);
132 void EmbeddedWorkerRegistry::OnWorkerStopped(
133 int process_id, int embedded_worker_id) {
134 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
135 if (found == worker_map_.end()) {
136 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
139 if (found->second->process_id() != process_id) {
140 LOG(ERROR) << "Incorrect embedded_worker_id";
143 worker_process_map_[process_id].erase(embedded_worker_id);
144 found->second->OnStopped();
147 void EmbeddedWorkerRegistry::OnReportException(
148 int embedded_worker_id,
149 const base::string16& error_message,
152 const GURL& source_url) {
153 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
154 if (found == worker_map_.end()) {
155 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
158 found->second->OnReportException(
159 error_message, line_number, column_number, source_url);
162 void EmbeddedWorkerRegistry::OnReportConsoleMessage(
163 int embedded_worker_id,
164 int source_identifier,
166 const base::string16& message,
168 const GURL& source_url) {
169 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
170 if (found == worker_map_.end()) {
171 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
174 found->second->OnReportConsoleMessage(
175 source_identifier, message_level, message, line_number, source_url);
178 void EmbeddedWorkerRegistry::AddChildProcessSender(
179 int process_id, IPC::Sender* sender) {
180 process_sender_map_[process_id] = sender;
181 DCHECK(!ContainsKey(worker_process_map_, process_id));
184 void EmbeddedWorkerRegistry::RemoveChildProcessSender(int process_id) {
185 process_sender_map_.erase(process_id);
186 std::map<int, std::set<int> >::iterator found =
187 worker_process_map_.find(process_id);
188 if (found != worker_process_map_.end()) {
189 const std::set<int>& worker_set = worker_process_map_[process_id];
190 for (std::set<int>::const_iterator it = worker_set.begin();
191 it != worker_set.end();
193 int embedded_worker_id = *it;
194 DCHECK(ContainsKey(worker_map_, embedded_worker_id));
195 worker_map_[embedded_worker_id]->OnStopped();
197 worker_process_map_.erase(found);
201 EmbeddedWorkerInstance* EmbeddedWorkerRegistry::GetWorker(
202 int embedded_worker_id) {
203 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
204 if (found == worker_map_.end())
206 return found->second;
209 EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() {
213 void EmbeddedWorkerRegistry::StartWorkerWithProcessId(
214 int embedded_worker_id,
215 scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
216 const StatusCallback& callback,
217 ServiceWorkerStatusCode status,
219 WorkerInstanceMap::const_iterator worker =
220 worker_map_.find(embedded_worker_id);
221 if (worker == worker_map_.end()) {
222 // The Instance was destroyed before it could finish starting. Undo what
223 // we've done so far.
225 context_->process_manager()->ReleaseWorkerProcess(process_id);
226 callback.Run(SERVICE_WORKER_ERROR_ABORT);
229 if (status == SERVICE_WORKER_OK) {
230 // Gets the new routing id for the renderer process.
231 scoped_refptr<RenderWidgetHelper> helper(
232 RenderWidgetHelper::FromProcessHostID(process_id));
233 // |helper| may be NULL in unittest.
234 params->worker_devtools_agent_route_id =
235 helper ? helper->GetNextRoutingID() : MSG_ROUTING_NONE;
237 worker->second->RecordProcessId(
238 process_id, status, params->worker_devtools_agent_route_id);
240 if (status != SERVICE_WORKER_OK) {
241 callback.Run(status);
244 // The ServiceWorkerDispatcherHost is supposed to be created when the process
245 // is created, and keep an entry in process_sender_map_ for its whole
247 DCHECK(ContainsKey(process_sender_map_, process_id));
248 callback.Run(Send(process_id, new EmbeddedWorkerMsg_StartWorker(*params)));
251 ServiceWorkerStatusCode EmbeddedWorkerRegistry::Send(
252 int process_id, IPC::Message* message) {
254 return SERVICE_WORKER_ERROR_ABORT;
255 ProcessToSenderMap::iterator found = process_sender_map_.find(process_id);
256 if (found == process_sender_map_.end())
257 return SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND;
258 if (!found->second->Send(message))
259 return SERVICE_WORKER_ERROR_IPC_FAILED;
260 return SERVICE_WORKER_OK;
263 void EmbeddedWorkerRegistry::RemoveWorker(int process_id,
264 int embedded_worker_id) {
265 DCHECK(ContainsKey(worker_map_, embedded_worker_id));
266 worker_map_.erase(embedded_worker_id);
267 worker_process_map_.erase(process_id);
270 } // namespace content