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