Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / embedded_worker_registry.cc
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.
4
5 #include "content/browser/service_worker/embedded_worker_registry.h"
6
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"
17
18 namespace content {
19
20 EmbeddedWorkerRegistry::EmbeddedWorkerRegistry(
21     base::WeakPtr<ServiceWorkerContextCore> context)
22     : context_(context),
23       next_embedded_worker_id_(0) {}
24
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();
29   return worker.Pass();
30 }
31
32 void EmbeddedWorkerRegistry::StartWorker(const std::vector<int>& process_ids,
33                                          int embedded_worker_id,
34                                          int64 service_worker_version_id,
35                                          const GURL& scope,
36                                          const GURL& script_url,
37                                          const StatusCallback& callback) {
38   if (!context_) {
39     callback.Run(SERVICE_WORKER_ERROR_ABORT);
40     return;
41   }
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(
50       process_ids,
51       script_url,
52       base::Bind(&EmbeddedWorkerRegistry::StartWorkerWithProcessId,
53                  this,
54                  embedded_worker_id,
55                  base::Passed(&params),
56                  callback));
57 }
58
59 ServiceWorkerStatusCode EmbeddedWorkerRegistry::StopWorker(
60     int process_id, int embedded_worker_id) {
61   if (context_)
62     context_->process_manager()->ReleaseWorkerProcess(process_id);
63   return Send(process_id,
64               new EmbeddedWorkerMsg_StopWorker(embedded_worker_id));
65 }
66
67 bool EmbeddedWorkerRegistry::OnMessageReceived(const IPC::Message& message) {
68   // TODO(kinuko): Move all EmbeddedWorker message handling from
69   // ServiceWorkerDispatcherHost.
70
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";
74     return false;
75   }
76   return found->second->OnMessageReceived(message);
77 }
78
79 void EmbeddedWorkerRegistry::Shutdown() {
80   for (WorkerInstanceMap::iterator it = worker_map_.begin();
81        it != worker_map_.end();
82        ++it) {
83     it->second->Stop();
84   }
85 }
86
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";
92     return;
93   }
94   if (found->second->process_id() != process_id) {
95     LOG(ERROR) << "Incorrect embedded_worker_id";
96     return;
97   }
98   found->second->OnScriptLoaded();
99 }
100
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";
106     return;
107   }
108   if (found->second->process_id() != process_id) {
109     LOG(ERROR) << "Incorrect embedded_worker_id";
110     return;
111   }
112   found->second->OnScriptLoadFailed();
113 }
114
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";
122     return;
123   }
124   if (found->second->process_id() != process_id) {
125     LOG(ERROR) << "Incorrect embedded_worker_id";
126     return;
127   }
128   worker_process_map_[process_id].insert(embedded_worker_id);
129   found->second->OnStarted(thread_id);
130 }
131
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";
137     return;
138   }
139   if (found->second->process_id() != process_id) {
140     LOG(ERROR) << "Incorrect embedded_worker_id";
141     return;
142   }
143   worker_process_map_[process_id].erase(embedded_worker_id);
144   found->second->OnStopped();
145 }
146
147 void EmbeddedWorkerRegistry::OnReportException(
148     int embedded_worker_id,
149     const base::string16& error_message,
150     int line_number,
151     int column_number,
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";
156     return;
157   }
158   found->second->OnReportException(
159       error_message, line_number, column_number, source_url);
160 }
161
162 void EmbeddedWorkerRegistry::OnReportConsoleMessage(
163     int embedded_worker_id,
164     int source_identifier,
165     int message_level,
166     const base::string16& message,
167     int line_number,
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";
172     return;
173   }
174   found->second->OnReportConsoleMessage(
175       source_identifier, message_level, message, line_number, source_url);
176 }
177
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));
182 }
183
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();
192          ++it) {
193       int embedded_worker_id = *it;
194       DCHECK(ContainsKey(worker_map_, embedded_worker_id));
195       worker_map_[embedded_worker_id]->OnStopped();
196     }
197     worker_process_map_.erase(found);
198   }
199 }
200
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())
205     return NULL;
206   return found->second;
207 }
208
209 EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() {
210   Shutdown();
211 }
212
213 void EmbeddedWorkerRegistry::StartWorkerWithProcessId(
214     int embedded_worker_id,
215     scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
216     const StatusCallback& callback,
217     ServiceWorkerStatusCode status,
218     int process_id) {
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.
224     if (context_)
225       context_->process_manager()->ReleaseWorkerProcess(process_id);
226     callback.Run(SERVICE_WORKER_ERROR_ABORT);
227     return;
228   }
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;
236   }
237   worker->second->RecordProcessId(
238       process_id, status, params->worker_devtools_agent_route_id);
239
240   if (status != SERVICE_WORKER_OK) {
241     callback.Run(status);
242     return;
243   }
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
246   // lifetime.
247   DCHECK(ContainsKey(process_sender_map_, process_id));
248   callback.Run(Send(process_id, new EmbeddedWorkerMsg_StartWorker(*params)));
249 }
250
251 ServiceWorkerStatusCode EmbeddedWorkerRegistry::Send(
252     int process_id, IPC::Message* message) {
253   if (!context_)
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;
261 }
262
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);
268 }
269
270 }  // namespace content