| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/background_fetch/background_fetch_event_dispatcher.h" |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/strings/stringprintf.h" |
| #include "content/browser/background_fetch/background_fetch_registration_id.h" |
| #include "content/browser/service_worker/service_worker_context_wrapper.h" |
| #include "content/browser/service_worker/service_worker_registration.h" |
| #include "content/browser/service_worker/service_worker_version.h" |
| #include "content/public/browser/browser_thread.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| // Returns the histogram suffix for the given |event| type. |
| std::string HistogramSuffixForEventType(ServiceWorkerMetrics::EventType event) { |
| switch (event) { |
| case ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_ABORT: |
| return "AbortEvent"; |
| case ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_CLICK: |
| return "ClickEvent"; |
| case ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_FAIL: |
| return "FailEvent"; |
| case ServiceWorkerMetrics::EventType::BACKGROUND_FETCHED: |
| return "FetchedEvent"; |
| default: |
| NOTREACHED(); |
| return std::string(); |
| } |
| } |
| |
| // Records the result of a dispatched Background Fetch event. |
| void RecordDispatchResult( |
| ServiceWorkerMetrics::EventType event, |
| BackgroundFetchEventDispatcher::DispatchResult result) { |
| std::string histogram_name = "BackgroundFetch.EventDispatchResult." + |
| HistogramSuffixForEventType(event); |
| |
| // Used because the |histogram_name| is not a constant. |
| base::UmaHistogramEnumeration( |
| histogram_name, result, |
| BackgroundFetchEventDispatcher::DISPATCH_RESULT_COUNT); |
| } |
| |
| // Records the failure reason of a failed dispatch for |metric_name|. |
| void RecordFailureResult(ServiceWorkerMetrics::EventType event, |
| const char* metric_name, |
| blink::ServiceWorkerStatusCode service_worker_status) { |
| std::string histogram_name = base::StringPrintf( |
| "BackgroundFetch.EventDispatchFailure.%s.%s", metric_name, |
| HistogramSuffixForEventType(event).c_str()); |
| |
| // Used because the |histogram_name| is not a constant. |
| base::UmaHistogramEnumeration(histogram_name, service_worker_status); |
| } |
| |
| } // namespace |
| |
| BackgroundFetchEventDispatcher::BackgroundFetchEventDispatcher( |
| scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) |
| : service_worker_context_(std::move(service_worker_context)) { |
| // Constructed on the UI thread, then lives on the IO thread. |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| } |
| |
| BackgroundFetchEventDispatcher::~BackgroundFetchEventDispatcher() { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| } |
| |
| void BackgroundFetchEventDispatcher::DispatchBackgroundFetchAbortEvent( |
| const BackgroundFetchRegistrationId& registration_id, |
| const std::vector<BackgroundFetchSettledFetch>& fetches, |
| base::OnceClosure finished_closure) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| LoadServiceWorkerRegistrationForDispatch( |
| registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_ABORT, |
| std::move(finished_closure), |
| base::Bind( |
| &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchAbortEvent, |
| registration_id.developer_id(), registration_id.unique_id(), |
| fetches)); |
| } |
| |
| void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchAbortEvent( |
| const std::string& developer_id, |
| const std::string& unique_id, |
| const std::vector<BackgroundFetchSettledFetch>& fetches, |
| scoped_refptr<ServiceWorkerVersion> service_worker_version, |
| int request_id) { |
| DCHECK(service_worker_version); |
| service_worker_version->event_dispatcher()->DispatchBackgroundFetchAbortEvent( |
| developer_id, unique_id, fetches, |
| service_worker_version->CreateSimpleEventCallback(request_id)); |
| } |
| |
| void BackgroundFetchEventDispatcher::DispatchBackgroundFetchClickEvent( |
| const BackgroundFetchRegistrationId& registration_id, |
| mojom::BackgroundFetchState state, |
| base::OnceClosure finished_closure) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| LoadServiceWorkerRegistrationForDispatch( |
| registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_CLICK, |
| std::move(finished_closure), |
| base::Bind( |
| &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchClickEvent, |
| registration_id.developer_id(), state)); |
| } |
| |
| void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchClickEvent( |
| const std::string& developer_id, |
| mojom::BackgroundFetchState state, |
| scoped_refptr<ServiceWorkerVersion> service_worker_version, |
| int request_id) { |
| DCHECK(service_worker_version); |
| service_worker_version->event_dispatcher()->DispatchBackgroundFetchClickEvent( |
| developer_id, state, |
| service_worker_version->CreateSimpleEventCallback(request_id)); |
| } |
| |
| void BackgroundFetchEventDispatcher::DispatchBackgroundFetchFailEvent( |
| const BackgroundFetchRegistrationId& registration_id, |
| const std::vector<BackgroundFetchSettledFetch>& fetches, |
| base::OnceClosure finished_closure) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| LoadServiceWorkerRegistrationForDispatch( |
| registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_FAIL, |
| std::move(finished_closure), |
| base::Bind( |
| &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchFailEvent, |
| registration_id.developer_id(), registration_id.unique_id(), |
| fetches)); |
| } |
| |
| void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchFailEvent( |
| const std::string& developer_id, |
| const std::string& unique_id, |
| const std::vector<BackgroundFetchSettledFetch>& fetches, |
| scoped_refptr<ServiceWorkerVersion> service_worker_version, |
| int request_id) { |
| DCHECK(service_worker_version); |
| service_worker_version->event_dispatcher()->DispatchBackgroundFetchFailEvent( |
| developer_id, unique_id, fetches, |
| service_worker_version->CreateSimpleEventCallback(request_id)); |
| } |
| |
| void BackgroundFetchEventDispatcher::DispatchBackgroundFetchedEvent( |
| const BackgroundFetchRegistrationId& registration_id, |
| const std::vector<BackgroundFetchSettledFetch>& fetches, |
| base::OnceClosure finished_closure) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| LoadServiceWorkerRegistrationForDispatch( |
| registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCHED, |
| std::move(finished_closure), |
| base::Bind( |
| &BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchedEvent, |
| registration_id.developer_id(), registration_id.unique_id(), |
| fetches)); |
| } |
| |
| void BackgroundFetchEventDispatcher::DoDispatchBackgroundFetchedEvent( |
| const std::string& developer_id, |
| const std::string& unique_id, |
| const std::vector<BackgroundFetchSettledFetch>& fetches, |
| scoped_refptr<ServiceWorkerVersion> service_worker_version, |
| int request_id) { |
| DCHECK(service_worker_version); |
| service_worker_version->event_dispatcher()->DispatchBackgroundFetchedEvent( |
| developer_id, unique_id, fetches, |
| service_worker_version->CreateSimpleEventCallback(request_id)); |
| } |
| |
| void BackgroundFetchEventDispatcher::LoadServiceWorkerRegistrationForDispatch( |
| const BackgroundFetchRegistrationId& registration_id, |
| ServiceWorkerMetrics::EventType event, |
| base::OnceClosure finished_closure, |
| ServiceWorkerLoadedCallback loaded_callback) { |
| service_worker_context_->FindReadyRegistrationForId( |
| registration_id.service_worker_registration_id(), |
| registration_id.origin().GetURL(), |
| base::BindOnce( |
| &BackgroundFetchEventDispatcher::StartActiveWorkerForDispatch, event, |
| std::move(finished_closure), std::move(loaded_callback))); |
| } |
| |
| void BackgroundFetchEventDispatcher::StartActiveWorkerForDispatch( |
| ServiceWorkerMetrics::EventType event, |
| base::OnceClosure finished_closure, |
| ServiceWorkerLoadedCallback loaded_callback, |
| blink::ServiceWorkerStatusCode service_worker_status, |
| scoped_refptr<ServiceWorkerRegistration> registration) { |
| if (service_worker_status != blink::ServiceWorkerStatusCode::kOk) { |
| DidDispatchEvent(event, std::move(finished_closure), DispatchPhase::FINDING, |
| service_worker_status); |
| return; |
| } |
| |
| ServiceWorkerVersion* service_worker_version = registration->active_version(); |
| DCHECK(service_worker_version); |
| |
| service_worker_version->RunAfterStartWorker( |
| event, |
| base::BindOnce(&BackgroundFetchEventDispatcher::DispatchEvent, event, |
| std::move(finished_closure), std::move(loaded_callback), |
| base::WrapRefCounted(service_worker_version))); |
| } |
| |
| void BackgroundFetchEventDispatcher::DispatchEvent( |
| ServiceWorkerMetrics::EventType event, |
| base::OnceClosure finished_closure, |
| ServiceWorkerLoadedCallback loaded_callback, |
| scoped_refptr<ServiceWorkerVersion> service_worker_version, |
| blink::ServiceWorkerStatusCode start_worker_status) { |
| if (start_worker_status != blink::ServiceWorkerStatusCode::kOk) { |
| DidDispatchEvent(event, std::move(finished_closure), |
| DispatchPhase::STARTING, start_worker_status); |
| return; |
| } |
| |
| int request_id = service_worker_version->StartRequest( |
| event, |
| base::BindOnce(&BackgroundFetchEventDispatcher::DidDispatchEvent, event, |
| std::move(finished_closure), DispatchPhase::DISPATCHING)); |
| |
| std::move(loaded_callback).Run(std::move(service_worker_version), request_id); |
| } |
| |
| void BackgroundFetchEventDispatcher::DidDispatchEvent( |
| ServiceWorkerMetrics::EventType event, |
| base::OnceClosure finished_closure, |
| DispatchPhase dispatch_phase, |
| blink::ServiceWorkerStatusCode service_worker_status) { |
| // Record the histograms tracking event dispatching success. |
| switch (dispatch_phase) { |
| case DispatchPhase::FINDING: |
| RecordDispatchResult(event, DISPATCH_RESULT_CANNOT_FIND_WORKER); |
| RecordFailureResult(event, "FindWorker", service_worker_status); |
| break; |
| case DispatchPhase::STARTING: |
| RecordDispatchResult(event, DISPATCH_RESULT_CANNOT_START_WORKER); |
| RecordFailureResult(event, "StartWorker", service_worker_status); |
| break; |
| case DispatchPhase::DISPATCHING: |
| if (service_worker_status != blink::ServiceWorkerStatusCode::kOk) { |
| RecordDispatchResult(event, DISPATCH_RESULT_CANNOT_DISPATCH_EVENT); |
| RecordFailureResult(event, "Dispatch", service_worker_status); |
| } else { |
| RecordDispatchResult(event, DISPATCH_RESULT_SUCCESS); |
| } |
| break; |
| } |
| |
| std::move(finished_closure).Run(); |
| } |
| |
| } // namespace content |