| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/service_worker/service_worker_version.h" | 5 #include "content/browser/service_worker/service_worker_version.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <map> | 9 #include <map> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 template <typename CallbackArray, typename Arg> | 83 template <typename CallbackArray, typename Arg> |
| 84 void RunCallbacks(ServiceWorkerVersion* version, | 84 void RunCallbacks(ServiceWorkerVersion* version, |
| 85 CallbackArray* callbacks_ptr, | 85 CallbackArray* callbacks_ptr, |
| 86 const Arg& arg) { | 86 const Arg& arg) { |
| 87 CallbackArray callbacks; | 87 CallbackArray callbacks; |
| 88 callbacks.swap(*callbacks_ptr); | 88 callbacks.swap(*callbacks_ptr); |
| 89 for (const auto& callback : callbacks) | 89 for (const auto& callback : callbacks) |
| 90 callback.Run(arg); | 90 callback.Run(arg); |
| 91 } | 91 } |
| 92 | 92 |
| 93 template <typename IDMAP, typename... Params> | |
| 94 void RunIDMapCallbacks(IDMAP* requests, const Params&... params) { | |
| 95 typename IDMAP::iterator iter(requests); | |
| 96 while (!iter.IsAtEnd()) { | |
| 97 TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerVersion::Request", | |
| 98 iter.GetCurrentValue()); | |
| 99 iter.GetCurrentValue()->callback.Run(params...); | |
| 100 iter.Advance(); | |
| 101 } | |
| 102 requests->Clear(); | |
| 103 } | |
| 104 | |
| 105 template <typename CallbackType, typename... Params> | |
| 106 bool RunIDMapCallback(IDMap<CallbackType, IDMapOwnPointer>* requests, | |
| 107 int request_id, | |
| 108 const Params&... params) { | |
| 109 CallbackType* request = requests->Lookup(request_id); | |
| 110 if (!request) | |
| 111 return false; | |
| 112 | |
| 113 TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerVersion::Request", | |
| 114 request); | |
| 115 request->callback.Run(params...); | |
| 116 requests->Remove(request_id); | |
| 117 return true; | |
| 118 } | |
| 119 | |
| 120 void RunStartWorkerCallback( | 93 void RunStartWorkerCallback( |
| 121 const StatusCallback& callback, | 94 const StatusCallback& callback, |
| 122 scoped_refptr<ServiceWorkerRegistration> protect, | 95 scoped_refptr<ServiceWorkerRegistration> protect, |
| 123 ServiceWorkerStatusCode status) { | 96 ServiceWorkerStatusCode status) { |
| 124 callback.Run(status); | 97 callback.Run(status); |
| 125 } | 98 } |
| 126 | 99 |
| 127 // A callback adapter to start a |task| after StartWorker. | 100 // A callback adapter to start a |task| after StartWorker. |
| 128 void RunTaskAfterStartWorker( | 101 void RunTaskAfterStartWorker( |
| 129 base::WeakPtr<ServiceWorkerVersion> version, | 102 base::WeakPtr<ServiceWorkerVersion> version, |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 } | 452 } |
| 480 | 453 |
| 481 void ServiceWorkerVersion::DeferScheduledUpdate() { | 454 void ServiceWorkerVersion::DeferScheduledUpdate() { |
| 482 if (update_timer_.IsRunning()) | 455 if (update_timer_.IsRunning()) |
| 483 update_timer_.Reset(); | 456 update_timer_.Reset(); |
| 484 } | 457 } |
| 485 | 458 |
| 486 int ServiceWorkerVersion::StartRequest( | 459 int ServiceWorkerVersion::StartRequest( |
| 487 ServiceWorkerMetrics::EventType event_type, | 460 ServiceWorkerMetrics::EventType event_type, |
| 488 const StatusCallback& error_callback) { | 461 const StatusCallback& error_callback) { |
| 489 OnBeginEvent(); | 462 return StartRequestWithCustomTimeout( |
| 490 DCHECK_EQ(RUNNING, running_status()) | 463 event_type, error_callback, |
| 491 << "Can only start a request with a running worker."; | 464 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes), KILL_ON_TIMEOUT); |
| 492 DCHECK(event_type == ServiceWorkerMetrics::EventType::INSTALL || | |
| 493 event_type == ServiceWorkerMetrics::EventType::ACTIVATE || | |
| 494 event_type == ServiceWorkerMetrics::EventType::MESSAGE || | |
| 495 status() == ACTIVATED) | |
| 496 << "Event of type " << static_cast<int>(event_type) | |
| 497 << " can only be dispatched to an active worker: " << status(); | |
| 498 return AddRequest(error_callback, &custom_requests_, REQUEST_CUSTOM, | |
| 499 event_type); | |
| 500 } | 465 } |
| 501 | 466 |
| 502 int ServiceWorkerVersion::StartRequestWithCustomTimeout( | 467 int ServiceWorkerVersion::StartRequestWithCustomTimeout( |
| 503 ServiceWorkerMetrics::EventType event_type, | 468 ServiceWorkerMetrics::EventType event_type, |
| 504 const StatusCallback& error_callback, | 469 const StatusCallback& error_callback, |
| 505 const base::TimeDelta& timeout, | 470 const base::TimeDelta& timeout, |
| 506 TimeoutBehavior timeout_behavior) { | 471 TimeoutBehavior timeout_behavior) { |
| 507 OnBeginEvent(); | 472 OnBeginEvent(); |
| 508 DCHECK_EQ(RUNNING, running_status()) | 473 DCHECK_EQ(RUNNING, running_status()) |
| 509 << "Can only start a request with a running worker."; | 474 << "Can only start a request with a running worker."; |
| 510 return AddRequestWithExpiration( | 475 DCHECK(event_type == ServiceWorkerMetrics::EventType::INSTALL || |
| 511 error_callback, &custom_requests_, REQUEST_CUSTOM, event_type, | 476 event_type == ServiceWorkerMetrics::EventType::ACTIVATE || |
| 512 base::TimeTicks::Now() + timeout, timeout_behavior); | 477 event_type == ServiceWorkerMetrics::EventType::MESSAGE || |
| 478 status() == ACTIVATED) |
| 479 << "Event of type " << static_cast<int>(event_type) |
| 480 << " can only be dispatched to an active worker: " << status(); |
| 481 |
| 482 PendingRequest<StatusCallback>* request = new PendingRequest<StatusCallback>( |
| 483 error_callback, base::TimeTicks::Now(), event_type); |
| 484 int request_id = custom_requests_.Add(request); |
| 485 TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker", "ServiceWorkerVersion::Request", |
| 486 request, "Request id", request_id, "Event type", |
| 487 ServiceWorkerMetrics::EventTypeToString(event_type)); |
| 488 base::TimeTicks expiration_time = base::TimeTicks::Now() + timeout; |
| 489 requests_.push( |
| 490 RequestInfo(request_id, event_type, expiration_time, timeout_behavior)); |
| 491 return request_id; |
| 513 } | 492 } |
| 514 | 493 |
| 515 bool ServiceWorkerVersion::FinishRequest(int request_id, bool was_handled) { | 494 bool ServiceWorkerVersion::FinishRequest(int request_id, bool was_handled) { |
| 516 PendingRequest<StatusCallback>* request = custom_requests_.Lookup(request_id); | 495 PendingRequest<StatusCallback>* request = custom_requests_.Lookup(request_id); |
| 517 if (!request) | 496 if (!request) |
| 518 return false; | 497 return false; |
| 519 // TODO(kinuko): Record other event statuses too. | 498 // TODO(kinuko): Record other event statuses too. |
| 520 metrics_->RecordEventHandledStatus(request->event_type, was_handled); | 499 metrics_->RecordEventHandledStatus(request->event_type, was_handled); |
| 521 ServiceWorkerMetrics::RecordEventDuration( | 500 ServiceWorkerMetrics::RecordEventDuration( |
| 522 request->event_type, base::TimeTicks::Now() - request->start_time, | 501 request->event_type, base::TimeTicks::Now() - request->start_time, |
| 523 was_handled); | 502 was_handled); |
| 524 RemoveCallbackAndStopIfRedundant(&custom_requests_, request_id); | 503 |
| 504 RestartTick(&idle_time_); |
| 505 TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request", |
| 506 request, "Handled", was_handled); |
| 507 custom_requests_.Remove(request_id); |
| 508 if (is_redundant()) { |
| 509 // The stop should be already scheduled, but try to stop immediately, in |
| 510 // order to release worker resources soon. |
| 511 StopWorkerIfIdle(); |
| 512 } |
| 525 return true; | 513 return true; |
| 526 } | 514 } |
| 527 | 515 |
| 528 void ServiceWorkerVersion::RunAfterStartWorker( | 516 void ServiceWorkerVersion::RunAfterStartWorker( |
| 529 const base::Closure& task, | 517 const base::Closure& task, |
| 530 const StatusCallback& error_callback) { | 518 const StatusCallback& error_callback) { |
| 531 if (running_status() == RUNNING) { | 519 if (running_status() == RUNNING) { |
| 532 DCHECK(start_callbacks_.empty()); | 520 DCHECK(start_callbacks_.empty()); |
| 533 task.Run(); | 521 task.Run(); |
| 534 return; | 522 return; |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 kDisableWorkerFailureCountThreshold; | 728 kDisableWorkerFailureCountThreshold; |
| 741 } | 729 } |
| 742 | 730 |
| 743 const net::HttpResponseInfo* | 731 const net::HttpResponseInfo* |
| 744 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { | 732 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { |
| 745 return main_script_http_info_.get(); | 733 return main_script_http_info_.get(); |
| 746 } | 734 } |
| 747 | 735 |
| 748 ServiceWorkerVersion::RequestInfo::RequestInfo( | 736 ServiceWorkerVersion::RequestInfo::RequestInfo( |
| 749 int id, | 737 int id, |
| 750 RequestType type, | |
| 751 ServiceWorkerMetrics::EventType event_type, | 738 ServiceWorkerMetrics::EventType event_type, |
| 752 const base::TimeTicks& expiration, | 739 const base::TimeTicks& expiration, |
| 753 TimeoutBehavior timeout_behavior) | 740 TimeoutBehavior timeout_behavior) |
| 754 : id(id), | 741 : id(id), |
| 755 type(type), | |
| 756 event_type(event_type), | 742 event_type(event_type), |
| 757 expiration(expiration), | 743 expiration(expiration), |
| 758 timeout_behavior(timeout_behavior) {} | 744 timeout_behavior(timeout_behavior) {} |
| 759 | 745 |
| 760 ServiceWorkerVersion::RequestInfo::~RequestInfo() { | 746 ServiceWorkerVersion::RequestInfo::~RequestInfo() { |
| 761 } | 747 } |
| 762 | 748 |
| 763 bool ServiceWorkerVersion::RequestInfo::operator>( | 749 bool ServiceWorkerVersion::RequestInfo::operator>( |
| 764 const RequestInfo& other) const { | 750 const RequestInfo& other) const { |
| 765 return expiration > other.expiration; | 751 return expiration > other.expiration; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 776 ServiceWorkerVersion* worker, | 762 ServiceWorkerVersion* worker, |
| 777 const char* service_name) | 763 const char* service_name) |
| 778 : worker_(worker), service_name_(service_name) {} | 764 : worker_(worker), service_name_(service_name) {} |
| 779 | 765 |
| 780 ServiceWorkerVersion::BaseMojoServiceWrapper::~BaseMojoServiceWrapper() { | 766 ServiceWorkerVersion::BaseMojoServiceWrapper::~BaseMojoServiceWrapper() { |
| 781 IDMap<PendingRequest<StatusCallback>, IDMapOwnPointer>::iterator iter( | 767 IDMap<PendingRequest<StatusCallback>, IDMapOwnPointer>::iterator iter( |
| 782 &worker_->custom_requests_); | 768 &worker_->custom_requests_); |
| 783 while (!iter.IsAtEnd()) { | 769 while (!iter.IsAtEnd()) { |
| 784 PendingRequest<StatusCallback>* request = iter.GetCurrentValue(); | 770 PendingRequest<StatusCallback>* request = iter.GetCurrentValue(); |
| 785 if (request->mojo_service == service_name_) { | 771 if (request->mojo_service == service_name_) { |
| 786 TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerVersion::Request", | 772 TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request", |
| 787 request); | 773 request, "Error", "Service Disconnected"); |
| 788 request->callback.Run(SERVICE_WORKER_ERROR_FAILED); | 774 request->callback.Run(SERVICE_WORKER_ERROR_FAILED); |
| 789 worker_->custom_requests_.Remove(iter.GetCurrentKey()); | 775 worker_->custom_requests_.Remove(iter.GetCurrentKey()); |
| 790 } | 776 } |
| 791 iter.Advance(); | 777 iter.Advance(); |
| 792 } | 778 } |
| 793 } | 779 } |
| 794 | 780 |
| 795 void ServiceWorkerVersion::OnThreadStarted() { | 781 void ServiceWorkerVersion::OnThreadStarted() { |
| 796 if (running_status() == STOPPING) | 782 if (running_status() == STOPPING) |
| 797 return; | 783 return; |
| (...skipping 761 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1559 message.append(EmbeddedWorkerInstance::StartingPhaseToString(phase)); | 1545 message.append(EmbeddedWorkerInstance::StartingPhaseToString(phase)); |
| 1560 } | 1546 } |
| 1561 message.append("."); | 1547 message.append("."); |
| 1562 OnReportException(base::UTF8ToUTF16(message), -1, -1, GURL()); | 1548 OnReportException(base::UTF8ToUTF16(message), -1, -1, GURL()); |
| 1563 DVLOG(1) << message; | 1549 DVLOG(1) << message; |
| 1564 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.TimeoutPhase", | 1550 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.TimeoutPhase", |
| 1565 phase, | 1551 phase, |
| 1566 EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE); | 1552 EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE); |
| 1567 } | 1553 } |
| 1568 | 1554 |
| 1569 template <typename IDMAP> | 1555 bool ServiceWorkerVersion::MaybeTimeOutRequest(const RequestInfo& info) { |
| 1570 void ServiceWorkerVersion::RemoveCallbackAndStopIfRedundant(IDMAP* callbacks, | 1556 PendingRequest<StatusCallback>* request = custom_requests_.Lookup(info.id); |
| 1571 int request_id) { | 1557 if (!request) |
| 1572 RestartTick(&idle_time_); | 1558 return false; |
| 1573 auto* request = callbacks->Lookup(request_id); | |
| 1574 if (request) { | |
| 1575 TRACE_EVENT_ASYNC_END0("ServiceWorker", "ServiceWorkerVersion::Request", | |
| 1576 request); | |
| 1577 } | |
| 1578 callbacks->Remove(request_id); | |
| 1579 if (is_redundant()) { | |
| 1580 // The stop should be already scheduled, but try to stop immediately, in | |
| 1581 // order to release worker resources soon. | |
| 1582 StopWorkerIfIdle(); | |
| 1583 } | |
| 1584 } | |
| 1585 | 1559 |
| 1586 template <typename CallbackType> | 1560 TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request", |
| 1587 int ServiceWorkerVersion::AddRequest( | 1561 request, "Error", "Timeout"); |
| 1588 const CallbackType& callback, | 1562 request->callback.Run(SERVICE_WORKER_ERROR_TIMEOUT); |
| 1589 IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map, | 1563 custom_requests_.Remove(info.id); |
| 1590 RequestType request_type, | 1564 return true; |
| 1591 ServiceWorkerMetrics::EventType event_type) { | |
| 1592 base::TimeTicks expiration_time = | |
| 1593 base::TimeTicks::Now() + | |
| 1594 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes); | |
| 1595 return AddRequestWithExpiration(callback, callback_map, request_type, | |
| 1596 event_type, expiration_time, KILL_ON_TIMEOUT); | |
| 1597 } | |
| 1598 | |
| 1599 template <typename CallbackType> | |
| 1600 int ServiceWorkerVersion::AddRequestWithExpiration( | |
| 1601 const CallbackType& callback, | |
| 1602 IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map, | |
| 1603 RequestType request_type, | |
| 1604 ServiceWorkerMetrics::EventType event_type, | |
| 1605 base::TimeTicks expiration, | |
| 1606 TimeoutBehavior timeout_behavior) { | |
| 1607 PendingRequest<CallbackType>* request = new PendingRequest<CallbackType>( | |
| 1608 callback, base::TimeTicks::Now(), event_type); | |
| 1609 int request_id = callback_map->Add(request); | |
| 1610 TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker", "ServiceWorkerVersion::Request", | |
| 1611 request, "Request id", request_id, "Event type", | |
| 1612 ServiceWorkerMetrics::EventTypeToString(event_type)); | |
| 1613 requests_.push(RequestInfo(request_id, request_type, event_type, expiration, | |
| 1614 timeout_behavior)); | |
| 1615 return request_id; | |
| 1616 } | |
| 1617 | |
| 1618 bool ServiceWorkerVersion::MaybeTimeOutRequest(const RequestInfo& info) { | |
| 1619 switch (info.type) { | |
| 1620 case REQUEST_CUSTOM: | |
| 1621 return RunIDMapCallback(&custom_requests_, info.id, | |
| 1622 SERVICE_WORKER_ERROR_TIMEOUT); | |
| 1623 case NUM_REQUEST_TYPES: | |
| 1624 break; | |
| 1625 } | |
| 1626 NOTREACHED() << "Got unexpected request type: " << info.type; | |
| 1627 return false; | |
| 1628 } | 1565 } |
| 1629 | 1566 |
| 1630 void ServiceWorkerVersion::SetAllRequestExpirations( | 1567 void ServiceWorkerVersion::SetAllRequestExpirations( |
| 1631 const base::TimeTicks& expiration) { | 1568 const base::TimeTicks& expiration) { |
| 1632 RequestInfoPriorityQueue new_requests; | 1569 RequestInfoPriorityQueue new_requests; |
| 1633 while (!requests_.empty()) { | 1570 while (!requests_.empty()) { |
| 1634 RequestInfo info = requests_.top(); | 1571 RequestInfo info = requests_.top(); |
| 1635 info.expiration = expiration; | 1572 info.expiration = expiration; |
| 1636 new_requests.push(info); | 1573 new_requests.push(info); |
| 1637 requests_.pop(); | 1574 requests_.pop(); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1721 if (!should_restart) { | 1658 if (!should_restart) { |
| 1722 // Let all start callbacks fail. | 1659 // Let all start callbacks fail. |
| 1723 RunCallbacks(this, &start_callbacks_, | 1660 RunCallbacks(this, &start_callbacks_, |
| 1724 DeduceStartWorkerFailureReason( | 1661 DeduceStartWorkerFailureReason( |
| 1725 SERVICE_WORKER_ERROR_START_WORKER_FAILED)); | 1662 SERVICE_WORKER_ERROR_START_WORKER_FAILED)); |
| 1726 } | 1663 } |
| 1727 | 1664 |
| 1728 // Let all message callbacks fail (this will also fire and clear all | 1665 // Let all message callbacks fail (this will also fire and clear all |
| 1729 // callbacks for events). | 1666 // callbacks for events). |
| 1730 // TODO(kinuko): Consider if we want to add queue+resend mechanism here. | 1667 // TODO(kinuko): Consider if we want to add queue+resend mechanism here. |
| 1731 RunIDMapCallbacks(&custom_requests_, SERVICE_WORKER_ERROR_FAILED); | 1668 IDMap<PendingRequest<StatusCallback>, IDMapOwnPointer>::iterator iter( |
| 1669 &custom_requests_); |
| 1670 while (!iter.IsAtEnd()) { |
| 1671 TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request", |
| 1672 iter.GetCurrentValue(), "Error", "Worker Stopped"); |
| 1673 iter.GetCurrentValue()->callback.Run(SERVICE_WORKER_ERROR_FAILED); |
| 1674 iter.Advance(); |
| 1675 } |
| 1676 custom_requests_.Clear(); |
| 1732 | 1677 |
| 1733 // Close all mojo services. This will also fire and clear all callbacks | 1678 // Close all mojo services. This will also fire and clear all callbacks |
| 1734 // for messages that are still outstanding for those services. | 1679 // for messages that are still outstanding for those services. |
| 1735 mojo_services_.clear(); | 1680 mojo_services_.clear(); |
| 1736 | 1681 |
| 1737 // TODO(falken): Call SWURLRequestJob::ClearStream here? | 1682 // TODO(falken): Call SWURLRequestJob::ClearStream here? |
| 1738 streaming_url_request_jobs_.clear(); | 1683 streaming_url_request_jobs_.clear(); |
| 1739 | 1684 |
| 1740 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this)); | 1685 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this)); |
| 1741 | 1686 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1752 void ServiceWorkerVersion::OnBeginEvent() { | 1697 void ServiceWorkerVersion::OnBeginEvent() { |
| 1753 if (should_exclude_from_uma_ || running_status() != RUNNING || | 1698 if (should_exclude_from_uma_ || running_status() != RUNNING || |
| 1754 idle_time_.is_null()) { | 1699 idle_time_.is_null()) { |
| 1755 return; | 1700 return; |
| 1756 } | 1701 } |
| 1757 ServiceWorkerMetrics::RecordTimeBetweenEvents(base::TimeTicks::Now() - | 1702 ServiceWorkerMetrics::RecordTimeBetweenEvents(base::TimeTicks::Now() - |
| 1758 idle_time_); | 1703 idle_time_); |
| 1759 } | 1704 } |
| 1760 | 1705 |
| 1761 } // namespace content | 1706 } // namespace content |
| OLD | NEW |