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), next_embedded_worker_id_(0) { 23 } 24 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 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 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 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 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 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 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 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 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 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 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 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 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 180 EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() { 181 Shutdown(); 182 } 183 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 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 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