• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/service_worker_version.h"
6 
7 #include "base/command_line.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string16.h"
10 #include "content/browser/service_worker/embedded_worker_instance.h"
11 #include "content/browser/service_worker/embedded_worker_registry.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_registration.h"
14 #include "content/browser/service_worker/service_worker_utils.h"
15 #include "content/common/service_worker/service_worker_messages.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/common/content_switches.h"
18 
19 namespace content {
20 
21 typedef ServiceWorkerVersion::StatusCallback StatusCallback;
22 typedef ServiceWorkerVersion::MessageCallback MessageCallback;
23 
24 namespace {
25 
26 // Default delay to stop the worker context after all documents that
27 // are associated to the worker are closed.
28 // (Note that if all references to the version is dropped the worker
29 // is also stopped without delay)
30 const int64 kStopWorkerDelay = 30;  // 30 secs.
31 
RunSoon(const base::Closure & callback)32 void RunSoon(const base::Closure& callback) {
33   if (!callback.is_null())
34     base::MessageLoop::current()->PostTask(FROM_HERE, callback);
35 }
36 
37 template <typename CallbackArray, typename Arg>
RunCallbacks(ServiceWorkerVersion * version,CallbackArray * callbacks_ptr,const Arg & arg)38 void RunCallbacks(ServiceWorkerVersion* version,
39                   CallbackArray* callbacks_ptr,
40                   const Arg& arg) {
41   CallbackArray callbacks;
42   callbacks.swap(*callbacks_ptr);
43   scoped_refptr<ServiceWorkerVersion> protect(version);
44   for (typename CallbackArray::const_iterator i = callbacks.begin();
45        i != callbacks.end(); ++i)
46     (*i).Run(arg);
47 }
48 
49 template <typename IDMAP, typename Method, typename Params>
RunIDMapCallbacks(IDMAP * callbacks,Method method,const Params & params)50 void RunIDMapCallbacks(IDMAP* callbacks, Method method, const Params& params) {
51   typename IDMAP::iterator iter(callbacks);
52   while (!iter.IsAtEnd()) {
53     DispatchToMethod(iter.GetCurrentValue(), method, params);
54     iter.Advance();
55   }
56   callbacks->Clear();
57 }
58 
59 // A callback adapter to start a |task| after StartWorker.
RunTaskAfterStartWorker(base::WeakPtr<ServiceWorkerVersion> version,const StatusCallback & error_callback,const base::Closure & task,ServiceWorkerStatusCode status)60 void RunTaskAfterStartWorker(
61     base::WeakPtr<ServiceWorkerVersion> version,
62     const StatusCallback& error_callback,
63     const base::Closure& task,
64     ServiceWorkerStatusCode status) {
65   if (status != SERVICE_WORKER_OK) {
66     if (!error_callback.is_null())
67       error_callback.Run(status);
68     return;
69   }
70   if (version->running_status() != ServiceWorkerVersion::RUNNING) {
71     // We've tried to start the worker (and it has succeeded), but
72     // it looks it's not running yet.
73     NOTREACHED() << "The worker's not running after successful StartWorker";
74     if (!error_callback.is_null())
75       error_callback.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED);
76     return;
77   }
78   task.Run();
79 }
80 
RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback & callback,ServiceWorkerStatusCode status)81 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
82                            ServiceWorkerStatusCode status) {
83   callback.Run(status,
84                SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
85                ServiceWorkerResponse());
86 }
87 
88 }  // namespace
89 
ServiceWorkerVersion(ServiceWorkerRegistration * registration,int64 version_id,base::WeakPtr<ServiceWorkerContextCore> context)90 ServiceWorkerVersion::ServiceWorkerVersion(
91     ServiceWorkerRegistration* registration,
92     int64 version_id,
93     base::WeakPtr<ServiceWorkerContextCore> context)
94     : version_id_(version_id),
95       registration_id_(kInvalidServiceWorkerVersionId),
96       status_(NEW),
97       context_(context),
98       script_cache_map_(this, context),
99       weak_factory_(this) {
100   DCHECK(context_);
101   DCHECK(registration);
102   if (registration) {
103     registration_id_ = registration->id();
104     script_url_ = registration->script_url();
105     scope_ = registration->pattern();
106   }
107   context_->AddLiveVersion(this);
108   embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
109   embedded_worker_->AddListener(this);
110 }
111 
~ServiceWorkerVersion()112 ServiceWorkerVersion::~ServiceWorkerVersion() {
113   embedded_worker_->RemoveListener(this);
114   if (context_)
115     context_->RemoveLiveVersion(version_id_);
116   // EmbeddedWorker's dtor sends StopWorker if it's still running.
117 }
118 
SetStatus(Status status)119 void ServiceWorkerVersion::SetStatus(Status status) {
120   if (status_ == status)
121     return;
122 
123   status_ = status;
124 
125   std::vector<base::Closure> callbacks;
126   callbacks.swap(status_change_callbacks_);
127   for (std::vector<base::Closure>::const_iterator i = callbacks.begin();
128        i != callbacks.end(); ++i) {
129     (*i).Run();
130   }
131 
132   FOR_EACH_OBSERVER(Listener, listeners_, OnVersionStateChanged(this));
133 }
134 
RegisterStatusChangeCallback(const base::Closure & callback)135 void ServiceWorkerVersion::RegisterStatusChangeCallback(
136     const base::Closure& callback) {
137   status_change_callbacks_.push_back(callback);
138 }
139 
GetInfo()140 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
141   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
142   return ServiceWorkerVersionInfo(
143       running_status(),
144       status(),
145       version_id(),
146       embedded_worker()->process_id(),
147       embedded_worker()->thread_id(),
148       embedded_worker()->worker_devtools_agent_route_id());
149 }
150 
StartWorker(const StatusCallback & callback)151 void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
152   StartWorkerWithCandidateProcesses(std::vector<int>(), callback);
153 }
154 
StartWorkerWithCandidateProcesses(const std::vector<int> & possible_process_ids,const StatusCallback & callback)155 void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
156     const std::vector<int>& possible_process_ids,
157     const StatusCallback& callback) {
158   switch (running_status()) {
159     case RUNNING:
160       RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
161       return;
162     case STOPPING:
163       RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
164       return;
165     case STOPPED:
166     case STARTING:
167       start_callbacks_.push_back(callback);
168       if (running_status() == STOPPED) {
169         embedded_worker_->Start(
170             version_id_,
171             scope_,
172             script_url_,
173             possible_process_ids,
174             base::Bind(&ServiceWorkerVersion::RunStartWorkerCallbacksOnError,
175                        weak_factory_.GetWeakPtr()));
176       }
177       return;
178   }
179 }
180 
StopWorker(const StatusCallback & callback)181 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
182   if (running_status() == STOPPED) {
183     RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
184     return;
185   }
186   if (stop_callbacks_.empty()) {
187     ServiceWorkerStatusCode status = embedded_worker_->Stop();
188     if (status != SERVICE_WORKER_OK) {
189       RunSoon(base::Bind(callback, status));
190       return;
191     }
192   }
193   stop_callbacks_.push_back(callback);
194 }
195 
SendMessage(const IPC::Message & message,const StatusCallback & callback)196 void ServiceWorkerVersion::SendMessage(
197     const IPC::Message& message, const StatusCallback& callback) {
198   if (running_status() != RUNNING) {
199     // Schedule calling this method after starting the worker.
200     StartWorker(base::Bind(&RunTaskAfterStartWorker,
201                            weak_factory_.GetWeakPtr(), callback,
202                            base::Bind(&self::SendMessage,
203                                       weak_factory_.GetWeakPtr(),
204                                       message, callback)));
205     return;
206   }
207 
208   ServiceWorkerStatusCode status = embedded_worker_->SendMessage(message);
209   RunSoon(base::Bind(callback, status));
210 }
211 
DispatchInstallEvent(int active_version_id,const StatusCallback & callback)212 void ServiceWorkerVersion::DispatchInstallEvent(
213     int active_version_id,
214     const StatusCallback& callback) {
215   DCHECK_EQ(NEW, status()) << status();
216   SetStatus(INSTALLING);
217 
218   if (running_status() != RUNNING) {
219     // Schedule calling this method after starting the worker.
220     StartWorker(
221         base::Bind(&RunTaskAfterStartWorker,
222                    weak_factory_.GetWeakPtr(),
223                    callback,
224                    base::Bind(&self::DispatchInstallEventAfterStartWorker,
225                               weak_factory_.GetWeakPtr(),
226                               active_version_id,
227                               callback)));
228   } else {
229     DispatchInstallEventAfterStartWorker(active_version_id, callback);
230   }
231 }
232 
DispatchActivateEvent(const StatusCallback & callback)233 void ServiceWorkerVersion::DispatchActivateEvent(
234     const StatusCallback& callback) {
235   DCHECK_EQ(INSTALLED, status()) << status();
236   SetStatus(ACTIVATING);
237 
238   if (running_status() != RUNNING) {
239     // Schedule calling this method after starting the worker.
240     StartWorker(
241         base::Bind(&RunTaskAfterStartWorker,
242                    weak_factory_.GetWeakPtr(),
243                    callback,
244                    base::Bind(&self::DispatchActivateEventAfterStartWorker,
245                               weak_factory_.GetWeakPtr(),
246                               callback)));
247   } else {
248     DispatchActivateEventAfterStartWorker(callback);
249   }
250 }
251 
DispatchFetchEvent(const ServiceWorkerFetchRequest & request,const FetchCallback & callback)252 void ServiceWorkerVersion::DispatchFetchEvent(
253     const ServiceWorkerFetchRequest& request,
254     const FetchCallback& callback) {
255   DCHECK_EQ(ACTIVE, status()) << status();
256 
257   if (running_status() != RUNNING) {
258     // Schedule calling this method after starting the worker.
259     StartWorker(base::Bind(&RunTaskAfterStartWorker,
260                            weak_factory_.GetWeakPtr(),
261                            base::Bind(&RunErrorFetchCallback, callback),
262                            base::Bind(&self::DispatchFetchEvent,
263                                       weak_factory_.GetWeakPtr(),
264                                       request, callback)));
265     return;
266   }
267 
268   int request_id = fetch_callbacks_.Add(new FetchCallback(callback));
269   ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
270       ServiceWorkerMsg_FetchEvent(request_id, request));
271   if (status != SERVICE_WORKER_OK) {
272     fetch_callbacks_.Remove(request_id);
273     RunSoon(base::Bind(&RunErrorFetchCallback,
274                        callback,
275                        SERVICE_WORKER_ERROR_FAILED));
276   }
277 }
278 
DispatchSyncEvent(const StatusCallback & callback)279 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
280   DCHECK_EQ(ACTIVE, status()) << status();
281 
282   if (!CommandLine::ForCurrentProcess()->HasSwitch(
283           switches::kEnableServiceWorkerSync)) {
284     callback.Run(SERVICE_WORKER_ERROR_ABORT);
285     return;
286   }
287 
288   if (running_status() != RUNNING) {
289     // Schedule calling this method after starting the worker.
290     StartWorker(base::Bind(&RunTaskAfterStartWorker,
291                            weak_factory_.GetWeakPtr(), callback,
292                            base::Bind(&self::DispatchSyncEvent,
293                                       weak_factory_.GetWeakPtr(),
294                                       callback)));
295     return;
296   }
297 
298   int request_id = sync_callbacks_.Add(new StatusCallback(callback));
299   ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
300       ServiceWorkerMsg_SyncEvent(request_id));
301   if (status != SERVICE_WORKER_OK) {
302     sync_callbacks_.Remove(request_id);
303     RunSoon(base::Bind(callback, status));
304   }
305 }
306 
DispatchPushEvent(const StatusCallback & callback,const std::string & data)307 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
308                                              const std::string& data) {
309   DCHECK_EQ(ACTIVE, status()) << status();
310 
311   if (!CommandLine::ForCurrentProcess()->HasSwitch(
312           switches::kEnableExperimentalWebPlatformFeatures)) {
313     callback.Run(SERVICE_WORKER_ERROR_ABORT);
314     return;
315   }
316 
317   if (running_status() != RUNNING) {
318     // Schedule calling this method after starting the worker.
319     StartWorker(base::Bind(&RunTaskAfterStartWorker,
320                            weak_factory_.GetWeakPtr(), callback,
321                            base::Bind(&self::DispatchPushEvent,
322                                       weak_factory_.GetWeakPtr(),
323                                       callback, data)));
324     return;
325   }
326 
327   int request_id = push_callbacks_.Add(new StatusCallback(callback));
328   ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
329       ServiceWorkerMsg_PushEvent(request_id, data));
330   if (status != SERVICE_WORKER_OK) {
331     push_callbacks_.Remove(request_id);
332     RunSoon(base::Bind(callback, status));
333   }
334 }
335 
AddProcessToWorker(int process_id)336 void ServiceWorkerVersion::AddProcessToWorker(int process_id) {
337   embedded_worker_->AddProcessReference(process_id);
338 }
339 
RemoveProcessFromWorker(int process_id)340 void ServiceWorkerVersion::RemoveProcessFromWorker(int process_id) {
341   embedded_worker_->ReleaseProcessReference(process_id);
342 }
343 
HasProcessToRun() const344 bool ServiceWorkerVersion::HasProcessToRun() const {
345   return embedded_worker_->HasProcessToRun();
346 }
347 
AddControllee(ServiceWorkerProviderHost * provider_host)348 void ServiceWorkerVersion::AddControllee(
349     ServiceWorkerProviderHost* provider_host) {
350   DCHECK(!ContainsKey(controllee_map_, provider_host));
351   int controllee_id = controllee_by_id_.Add(provider_host);
352   controllee_map_[provider_host] = controllee_id;
353   AddProcessToWorker(provider_host->process_id());
354   if (stop_worker_timer_.IsRunning())
355     stop_worker_timer_.Stop();
356 }
357 
RemoveControllee(ServiceWorkerProviderHost * provider_host)358 void ServiceWorkerVersion::RemoveControllee(
359     ServiceWorkerProviderHost* provider_host) {
360   ControlleeMap::iterator found = controllee_map_.find(provider_host);
361   DCHECK(found != controllee_map_.end());
362   controllee_by_id_.Remove(found->second);
363   controllee_map_.erase(found);
364   RemoveProcessFromWorker(provider_host->process_id());
365   if (!HasControllee())
366     ScheduleStopWorker();
367   // TODO(kinuko): Fire NoControllees notification when the # of controllees
368   // reaches 0, so that a new pending version can be activated (which will
369   // deactivate this version).
370   // TODO(michaeln): On no controllees call storage DeleteVersionResources
371   // if this version has been deactivated. Probably storage can listen for
372   // NoControllees for versions that have been deleted.
373 }
374 
AddWaitingControllee(ServiceWorkerProviderHost * provider_host)375 void ServiceWorkerVersion::AddWaitingControllee(
376     ServiceWorkerProviderHost* provider_host) {
377   AddProcessToWorker(provider_host->process_id());
378 }
379 
RemoveWaitingControllee(ServiceWorkerProviderHost * provider_host)380 void ServiceWorkerVersion::RemoveWaitingControllee(
381     ServiceWorkerProviderHost* provider_host) {
382   RemoveProcessFromWorker(provider_host->process_id());
383 }
384 
AddListener(Listener * listener)385 void ServiceWorkerVersion::AddListener(Listener* listener) {
386   listeners_.AddObserver(listener);
387 }
388 
RemoveListener(Listener * listener)389 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
390   listeners_.RemoveObserver(listener);
391 }
392 
OnStarted()393 void ServiceWorkerVersion::OnStarted() {
394   DCHECK_EQ(RUNNING, running_status());
395   // Fire all start callbacks.
396   RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
397   FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this));
398 }
399 
OnStopped()400 void ServiceWorkerVersion::OnStopped() {
401   DCHECK_EQ(STOPPED, running_status());
402   scoped_refptr<ServiceWorkerVersion> protect(this);
403 
404   // Fire all stop callbacks.
405   RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
406 
407   // Let all start callbacks fail.
408   RunCallbacks(
409       this, &start_callbacks_, SERVICE_WORKER_ERROR_START_WORKER_FAILED);
410 
411   // Let all message callbacks fail (this will also fire and clear all
412   // callbacks for events).
413   // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
414   RunIDMapCallbacks(&activate_callbacks_,
415                     &StatusCallback::Run,
416                     MakeTuple(SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED));
417   RunIDMapCallbacks(&install_callbacks_,
418                     &StatusCallback::Run,
419                     MakeTuple(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED));
420   RunIDMapCallbacks(&fetch_callbacks_,
421                     &FetchCallback::Run,
422                     MakeTuple(SERVICE_WORKER_ERROR_FAILED,
423                               SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
424                               ServiceWorkerResponse()));
425   RunIDMapCallbacks(&sync_callbacks_,
426                     &StatusCallback::Run,
427                     MakeTuple(SERVICE_WORKER_ERROR_FAILED));
428   RunIDMapCallbacks(&push_callbacks_,
429                     &StatusCallback::Run,
430                     MakeTuple(SERVICE_WORKER_ERROR_FAILED));
431 
432   FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
433 }
434 
OnReportException(const base::string16 & error_message,int line_number,int column_number,const GURL & source_url)435 void ServiceWorkerVersion::OnReportException(
436     const base::string16& error_message,
437     int line_number,
438     int column_number,
439     const GURL& source_url) {
440   FOR_EACH_OBSERVER(
441       Listener,
442       listeners_,
443       OnErrorReported(
444           this, error_message, line_number, column_number, source_url));
445 }
446 
OnReportConsoleMessage(int source_identifier,int message_level,const base::string16 & message,int line_number,const GURL & source_url)447 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
448                                                   int message_level,
449                                                   const base::string16& message,
450                                                   int line_number,
451                                                   const GURL& source_url) {
452   FOR_EACH_OBSERVER(Listener,
453                     listeners_,
454                     OnReportConsoleMessage(this,
455                                            source_identifier,
456                                            message_level,
457                                            message,
458                                            line_number,
459                                            source_url));
460 }
461 
OnMessageReceived(const IPC::Message & message)462 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
463   bool handled = true;
464   IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
465     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments,
466                         OnGetClientDocuments)
467     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
468                         OnActivateEventFinished)
469     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
470                         OnInstallEventFinished)
471     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
472                         OnFetchEventFinished)
473     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
474                         OnSyncEventFinished)
475     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
476                         OnPushEventFinished)
477     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
478                         OnPostMessageToDocument)
479     IPC_MESSAGE_UNHANDLED(handled = false)
480   IPC_END_MESSAGE_MAP()
481   return handled;
482 }
483 
RunStartWorkerCallbacksOnError(ServiceWorkerStatusCode status)484 void ServiceWorkerVersion::RunStartWorkerCallbacksOnError(
485     ServiceWorkerStatusCode status) {
486   if (status != SERVICE_WORKER_OK)
487     RunCallbacks(this, &start_callbacks_, status);
488 }
489 
DispatchInstallEventAfterStartWorker(int active_version_id,const StatusCallback & callback)490 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
491     int active_version_id,
492     const StatusCallback& callback) {
493   DCHECK_EQ(RUNNING, running_status())
494       << "Worker stopped too soon after it was started.";
495   int request_id = install_callbacks_.Add(new StatusCallback(callback));
496   ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
497       ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
498   if (status != SERVICE_WORKER_OK) {
499     install_callbacks_.Remove(request_id);
500     RunSoon(base::Bind(callback, status));
501   }
502 }
503 
DispatchActivateEventAfterStartWorker(const StatusCallback & callback)504 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
505     const StatusCallback& callback) {
506   DCHECK_EQ(RUNNING, running_status())
507       << "Worker stopped too soon after it was started.";
508   int request_id = activate_callbacks_.Add(new StatusCallback(callback));
509   ServiceWorkerStatusCode status =
510       embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
511   if (status != SERVICE_WORKER_OK) {
512     activate_callbacks_.Remove(request_id);
513     RunSoon(base::Bind(callback, status));
514   }
515 }
516 
OnGetClientDocuments(int request_id)517 void ServiceWorkerVersion::OnGetClientDocuments(int request_id) {
518   std::vector<int> client_ids;
519   ControlleeByIDMap::iterator it(&controllee_by_id_);
520   while (!it.IsAtEnd()) {
521     client_ids.push_back(it.GetCurrentKey());
522     it.Advance();
523   }
524   // Don't bother if it's no longer running.
525   if (running_status() == RUNNING) {
526     embedded_worker_->SendMessage(
527         ServiceWorkerMsg_DidGetClientDocuments(request_id, client_ids));
528   }
529 }
530 
OnActivateEventFinished(int request_id,blink::WebServiceWorkerEventResult result)531 void ServiceWorkerVersion::OnActivateEventFinished(
532     int request_id,
533     blink::WebServiceWorkerEventResult result) {
534   StatusCallback* callback = activate_callbacks_.Lookup(request_id);
535   if (!callback) {
536     NOTREACHED() << "Got unexpected message: " << request_id;
537     return;
538   }
539   ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
540   if (result == blink::WebServiceWorkerEventResultRejected)
541     status = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
542   else
543     SetStatus(ACTIVE);
544 
545   scoped_refptr<ServiceWorkerVersion> protect(this);
546   callback->Run(status);
547   activate_callbacks_.Remove(request_id);
548 }
549 
OnInstallEventFinished(int request_id,blink::WebServiceWorkerEventResult result)550 void ServiceWorkerVersion::OnInstallEventFinished(
551     int request_id,
552     blink::WebServiceWorkerEventResult result) {
553   StatusCallback* callback = install_callbacks_.Lookup(request_id);
554   if (!callback) {
555     NOTREACHED() << "Got unexpected message: " << request_id;
556     return;
557   }
558   ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
559   if (result == blink::WebServiceWorkerEventResultRejected)
560     status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
561   else
562     SetStatus(INSTALLED);
563 
564   scoped_refptr<ServiceWorkerVersion> protect(this);
565   callback->Run(status);
566   install_callbacks_.Remove(request_id);
567 }
568 
OnFetchEventFinished(int request_id,ServiceWorkerFetchEventResult result,const ServiceWorkerResponse & response)569 void ServiceWorkerVersion::OnFetchEventFinished(
570     int request_id,
571     ServiceWorkerFetchEventResult result,
572     const ServiceWorkerResponse& response) {
573   FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
574   if (!callback) {
575     NOTREACHED() << "Got unexpected message: " << request_id;
576     return;
577   }
578 
579   scoped_refptr<ServiceWorkerVersion> protect(this);
580   callback->Run(SERVICE_WORKER_OK, result, response);
581   fetch_callbacks_.Remove(request_id);
582 }
583 
OnSyncEventFinished(int request_id)584 void ServiceWorkerVersion::OnSyncEventFinished(
585     int request_id) {
586   StatusCallback* callback = sync_callbacks_.Lookup(request_id);
587   if (!callback) {
588     NOTREACHED() << "Got unexpected message: " << request_id;
589     return;
590   }
591 
592   scoped_refptr<ServiceWorkerVersion> protect(this);
593   callback->Run(SERVICE_WORKER_OK);
594   sync_callbacks_.Remove(request_id);
595 }
596 
OnPushEventFinished(int request_id)597 void ServiceWorkerVersion::OnPushEventFinished(
598     int request_id) {
599   StatusCallback* callback = push_callbacks_.Lookup(request_id);
600   if (!callback) {
601     NOTREACHED() << "Got unexpected message: " << request_id;
602     return;
603   }
604 
605   scoped_refptr<ServiceWorkerVersion> protect(this);
606   callback->Run(SERVICE_WORKER_OK);
607   push_callbacks_.Remove(request_id);
608 }
609 
OnPostMessageToDocument(int client_id,const base::string16 & message,const std::vector<int> & sent_message_port_ids)610 void ServiceWorkerVersion::OnPostMessageToDocument(
611     int client_id,
612     const base::string16& message,
613     const std::vector<int>& sent_message_port_ids) {
614   ServiceWorkerProviderHost* provider_host =
615       controllee_by_id_.Lookup(client_id);
616   if (!provider_host) {
617     // The client may already have been closed, just ignore.
618     return;
619   }
620   provider_host->PostMessage(message, sent_message_port_ids);
621 }
622 
ScheduleStopWorker()623 void ServiceWorkerVersion::ScheduleStopWorker() {
624   if (running_status() != RUNNING)
625     return;
626   if (stop_worker_timer_.IsRunning()) {
627     stop_worker_timer_.Reset();
628     return;
629   }
630   stop_worker_timer_.Start(
631       FROM_HERE, base::TimeDelta::FromSeconds(kStopWorkerDelay),
632       base::Bind(&ServiceWorkerVersion::StopWorker,
633                  weak_factory_.GetWeakPtr(),
634                  base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)));
635 }
636 
637 }  // namespace content
638