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