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
EmbeddedWorkerRegistry(base::WeakPtr<ServiceWorkerContextCore> context)20 EmbeddedWorkerRegistry::EmbeddedWorkerRegistry(
21 base::WeakPtr<ServiceWorkerContextCore> context)
22 : context_(context), next_embedded_worker_id_(0) {
23 }
24
CreateWorker()25 scoped_ptr<EmbeddedWorkerInstance> EmbeddedWorkerRegistry::CreateWorker() {
26 scoped_ptr<EmbeddedWorkerInstance> worker(
27 new EmbeddedWorkerInstance(context_, next_embedded_worker_id_));
28 worker_map_[next_embedded_worker_id_++] = worker.get();
29 return worker.Pass();
30 }
31
StopWorker(int process_id,int embedded_worker_id)32 ServiceWorkerStatusCode EmbeddedWorkerRegistry::StopWorker(
33 int process_id, int embedded_worker_id) {
34 return Send(process_id,
35 new EmbeddedWorkerMsg_StopWorker(embedded_worker_id));
36 }
37
OnMessageReceived(const IPC::Message & message)38 bool EmbeddedWorkerRegistry::OnMessageReceived(const IPC::Message& message) {
39 // TODO(kinuko): Move all EmbeddedWorker message handling from
40 // ServiceWorkerDispatcherHost.
41
42 WorkerInstanceMap::iterator found = worker_map_.find(message.routing_id());
43 if (found == worker_map_.end()) {
44 LOG(ERROR) << "Worker " << message.routing_id() << " not registered";
45 return false;
46 }
47 return found->second->OnMessageReceived(message);
48 }
49
Shutdown()50 void EmbeddedWorkerRegistry::Shutdown() {
51 for (WorkerInstanceMap::iterator it = worker_map_.begin();
52 it != worker_map_.end();
53 ++it) {
54 it->second->Stop();
55 }
56 }
57
OnWorkerScriptLoaded(int process_id,int embedded_worker_id)58 void EmbeddedWorkerRegistry::OnWorkerScriptLoaded(int process_id,
59 int embedded_worker_id) {
60 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
61 if (found == worker_map_.end()) {
62 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
63 return;
64 }
65 if (found->second->process_id() != process_id) {
66 LOG(ERROR) << "Incorrect embedded_worker_id";
67 return;
68 }
69 found->second->OnScriptLoaded();
70 }
71
OnWorkerScriptLoadFailed(int process_id,int embedded_worker_id)72 void EmbeddedWorkerRegistry::OnWorkerScriptLoadFailed(int process_id,
73 int embedded_worker_id) {
74 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
75 if (found == worker_map_.end()) {
76 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
77 return;
78 }
79 if (found->second->process_id() != process_id) {
80 LOG(ERROR) << "Incorrect embedded_worker_id";
81 return;
82 }
83 found->second->OnScriptLoadFailed();
84 }
85
OnWorkerStarted(int process_id,int thread_id,int embedded_worker_id)86 void EmbeddedWorkerRegistry::OnWorkerStarted(
87 int process_id, int thread_id, int embedded_worker_id) {
88 DCHECK(!ContainsKey(worker_process_map_, process_id) ||
89 worker_process_map_[process_id].count(embedded_worker_id) == 0);
90 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
91 if (found == worker_map_.end()) {
92 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
93 return;
94 }
95 if (found->second->process_id() != process_id) {
96 LOG(ERROR) << "Incorrect embedded_worker_id";
97 return;
98 }
99 worker_process_map_[process_id].insert(embedded_worker_id);
100 found->second->OnStarted(thread_id);
101 }
102
OnWorkerStopped(int process_id,int embedded_worker_id)103 void EmbeddedWorkerRegistry::OnWorkerStopped(
104 int process_id, int embedded_worker_id) {
105 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
106 if (found == worker_map_.end()) {
107 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
108 return;
109 }
110 if (found->second->process_id() != process_id) {
111 LOG(ERROR) << "Incorrect embedded_worker_id";
112 return;
113 }
114 worker_process_map_[process_id].erase(embedded_worker_id);
115 found->second->OnStopped();
116 }
117
OnReportException(int embedded_worker_id,const base::string16 & error_message,int line_number,int column_number,const GURL & source_url)118 void EmbeddedWorkerRegistry::OnReportException(
119 int embedded_worker_id,
120 const base::string16& error_message,
121 int line_number,
122 int column_number,
123 const GURL& source_url) {
124 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
125 if (found == worker_map_.end()) {
126 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
127 return;
128 }
129 found->second->OnReportException(
130 error_message, line_number, column_number, source_url);
131 }
132
OnReportConsoleMessage(int embedded_worker_id,int source_identifier,int message_level,const base::string16 & message,int line_number,const GURL & source_url)133 void EmbeddedWorkerRegistry::OnReportConsoleMessage(
134 int embedded_worker_id,
135 int source_identifier,
136 int message_level,
137 const base::string16& message,
138 int line_number,
139 const GURL& source_url) {
140 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
141 if (found == worker_map_.end()) {
142 LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
143 return;
144 }
145 found->second->OnReportConsoleMessage(
146 source_identifier, message_level, message, line_number, source_url);
147 }
148
AddChildProcessSender(int process_id,IPC::Sender * sender)149 void EmbeddedWorkerRegistry::AddChildProcessSender(
150 int process_id, IPC::Sender* sender) {
151 process_sender_map_[process_id] = sender;
152 DCHECK(!ContainsKey(worker_process_map_, process_id));
153 }
154
RemoveChildProcessSender(int process_id)155 void EmbeddedWorkerRegistry::RemoveChildProcessSender(int process_id) {
156 process_sender_map_.erase(process_id);
157 std::map<int, std::set<int> >::iterator found =
158 worker_process_map_.find(process_id);
159 if (found != worker_process_map_.end()) {
160 const std::set<int>& worker_set = worker_process_map_[process_id];
161 for (std::set<int>::const_iterator it = worker_set.begin();
162 it != worker_set.end();
163 ++it) {
164 int embedded_worker_id = *it;
165 DCHECK(ContainsKey(worker_map_, embedded_worker_id));
166 worker_map_[embedded_worker_id]->OnStopped();
167 }
168 worker_process_map_.erase(found);
169 }
170 }
171
GetWorker(int embedded_worker_id)172 EmbeddedWorkerInstance* EmbeddedWorkerRegistry::GetWorker(
173 int embedded_worker_id) {
174 WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
175 if (found == worker_map_.end())
176 return NULL;
177 return found->second;
178 }
179
~EmbeddedWorkerRegistry()180 EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() {
181 Shutdown();
182 }
183
SendStartWorker(scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,const StatusCallback & callback,int process_id)184 void EmbeddedWorkerRegistry::SendStartWorker(
185 scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
186 const StatusCallback& callback,
187 int process_id) {
188 // The ServiceWorkerDispatcherHost is supposed to be created when the process
189 // is created, and keep an entry in process_sender_map_ for its whole
190 // lifetime.
191 DCHECK(ContainsKey(process_sender_map_, process_id));
192 callback.Run(Send(process_id, new EmbeddedWorkerMsg_StartWorker(*params)));
193 }
194
Send(int process_id,IPC::Message * message_ptr)195 ServiceWorkerStatusCode EmbeddedWorkerRegistry::Send(
196 int process_id, IPC::Message* message_ptr) {
197 scoped_ptr<IPC::Message> message(message_ptr);
198 if (!context_)
199 return SERVICE_WORKER_ERROR_ABORT;
200 ProcessToSenderMap::iterator found = process_sender_map_.find(process_id);
201 if (found == process_sender_map_.end())
202 return SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND;
203 if (!found->second->Send(message.release()))
204 return SERVICE_WORKER_ERROR_IPC_FAILED;
205 return SERVICE_WORKER_OK;
206 }
207
RemoveWorker(int process_id,int embedded_worker_id)208 void EmbeddedWorkerRegistry::RemoveWorker(int process_id,
209 int embedded_worker_id) {
210 DCHECK(ContainsKey(worker_map_, embedded_worker_id));
211 worker_map_.erase(embedded_worker_id);
212 worker_process_map_.erase(process_id);
213 }
214
215 } // namespace content
216