blob: 1f11208bae27fc6bdb043949c512e02dc1a792a4 [file] [log] [blame]
// Copyright 2014 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.
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_METRICS_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_METRICS_H_
#include <stddef.h>
#include <map>
#include <set>
#include "base/macros.h"
#include "base/time/time.h"
#include "content/browser/service_worker/service_worker_context_request_handler.h"
#include "content/browser/service_worker/service_worker_database.h"
#include "content/browser/service_worker/service_worker_installed_script_reader.h"
#include "content/common/service_worker/embedded_worker.mojom.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/service_worker_context.h"
#include "services/network/public/mojom/fetch_api.mojom.h"
#include "ui/base/page_transition_types.h"
class GURL;
namespace content {
enum class EmbeddedWorkerStatus;
class ServiceWorkerMetrics {
public:
// Used for UMA. Append-only.
enum ReadResponseResult {
READ_OK,
READ_HEADERS_ERROR,
READ_DATA_ERROR,
NUM_READ_RESPONSE_RESULT_TYPES,
};
// Used for UMA. Append-only.
enum WriteResponseResult {
WRITE_OK,
WRITE_HEADERS_ERROR,
WRITE_DATA_ERROR,
NUM_WRITE_RESPONSE_RESULT_TYPES,
};
// Used for UMA. Append-only.
enum DeleteAndStartOverResult {
DELETE_OK,
DELETE_DATABASE_ERROR,
DELETE_DISK_CACHE_ERROR,
NUM_DELETE_AND_START_OVER_RESULT_TYPES,
};
// Used for UMA. Append-only.
enum URLRequestJobResult {
// The service worker fell back to network.
REQUEST_JOB_FALLBACK_RESPONSE = 0,
// The service worker fell back to network and CORS check is needed.
REQUEST_JOB_FALLBACK_FOR_CORS = 1,
// The service worker responded with headers only (no body).
REQUEST_JOB_HEADERS_ONLY_RESPONSE = 2,
// The service worker responded with a stream body.
REQUEST_JOB_STREAM_RESPONSE = 3,
// The service worker responded with a blob body.
REQUEST_JOB_BLOB_RESPONSE = 4,
// The renderer responded with network error (see
// RecordStatusZeroResponseError() for error reasons).
REQUEST_JOB_ERROR_RESPONSE_STATUS_ZERO = 5,
// The renderer returned a response blob that could not be read.
REQUEST_JOB_ERROR_BAD_BLOB = 6,
// The provider host for the request was destroyed before the request
// could start.
REQUEST_JOB_ERROR_NO_PROVIDER_HOST = 7,
// The service worker assigned to the request could not be found, when
// the request tried to start.
REQUEST_JOB_ERROR_NO_ACTIVE_VERSION = 8,
// Obsolete.
// REQUEST_JOB_ERROR_NO_REQUEST = 9,
// An error occurred attempting to dispatch the event to the service worker.
REQUEST_JOB_ERROR_FETCH_EVENT_DISPATCH = 10,
// An error occurred while reading the blob response.
REQUEST_JOB_ERROR_BLOB_READ = 11,
// The connection to the stream response was destroyed before all the data
// was read.
REQUEST_JOB_ERROR_STREAM_ABORTED = 12,
// The request job destructed before it finished.
REQUEST_JOB_ERROR_KILLED = 13,
// The request job destructed before it finished. It was reading
// a blob response.
REQUEST_JOB_ERROR_KILLED_WITH_BLOB = 14,
// The request job was destructed before it finished. It was reading
// a stream response.
REQUEST_JOB_ERROR_KILLED_WITH_STREAM = 15,
// Obsolete.
// REQUEST_JOB_ERROR_DESTROYED = 16,
// REQUEST_JOB_ERROR_DESTROYED_WITH_BLOB = 17,
// REQUEST_JOB_ERROR_DESTROYED_WITH_STREAM = 18,
// The request job delegate behaved incorrectly.
REQUEST_JOB_ERROR_BAD_DELEGATE = 19,
// The browser failed to construct the request body.
REQUEST_JOB_ERROR_REQUEST_BODY_BLOB_FAILED = 20,
NUM_REQUEST_JOB_RESULT_TYPES,
};
// Used for UMA. Append-only.
enum class StopStatus {
NORMAL,
DETACH_BY_REGISTRY,
TIMEOUT,
// Add new types here.
NUM_TYPES
};
// Used for UMA. Append-only.
// This class is used to indicate which event is fired/finished. Most events
// have only one request that starts the event and one response that finishes
// the event, but the fetch and the foreign fetch event have two responses, so
// there are two types of EventType to break down the measurement into two:
// FETCH/FOREIGN_FETCH and FETCH_WAITUNTIL/FOREIGN_FETCH_WAITUNTIL.
// Moreover, FETCH is separated into the four: MAIN_FRAME, SUB_FRAME,
// SHARED_WORKER and SUB_RESOURCE for more detailed UMA.
enum class EventType {
ACTIVATE = 0,
INSTALL = 1,
// FETCH = 2, // Obsolete
SYNC = 3,
NOTIFICATION_CLICK = 4,
PUSH = 5,
// GEOFENCING = 6, // Obsolete
// SERVICE_PORT_CONNECT = 7, // Obsolete
MESSAGE = 8,
NOTIFICATION_CLOSE = 9,
FETCH_MAIN_FRAME = 10,
FETCH_SUB_FRAME = 11,
FETCH_SHARED_WORKER = 12,
FETCH_SUB_RESOURCE = 13,
UNKNOWN = 14, // Used when event type is not known.
FOREIGN_FETCH = 15,
FETCH_WAITUNTIL = 16,
FOREIGN_FETCH_WAITUNTIL = 17,
// NAVIGATION_HINT_LINK_MOUSE_DOWN = 18, // Obsolete
// NAVIGATION_HINT_LINK_TAP_UNCONFIRMED = 19, // Obsolete
// NAVIGATION_HINT_LINK_TAP_DOWN = 20, // Obsolete
// Used when external consumers want to add a request to
// ServiceWorkerVersion to keep it alive.
EXTERNAL_REQUEST = 21,
PAYMENT_REQUEST = 22,
BACKGROUND_FETCH_ABORT = 23,
BACKGROUND_FETCH_CLICK = 24,
BACKGROUND_FETCH_FAIL = 25,
BACKGROUND_FETCHED = 26,
NAVIGATION_HINT = 27,
CAN_MAKE_PAYMENT = 28,
ABORT_PAYMENT = 29,
COOKIE_CHANGE = 30,
// Add new events to record here.
NUM_TYPES
};
// Used for UMA. Append only.
enum class Site {
OTHER, // Obsolete for UMA. Use WITH_FETCH_HANDLER or
// WITHOUT_FETCH_HANDLER.
NEW_TAB_PAGE,
WITH_FETCH_HANDLER,
WITHOUT_FETCH_HANDLER,
PLUS,
INBOX,
DOCS,
NUM_TYPES
};
// Not used for UMA.
enum class StartSituation {
// Failed to allocate a process.
UNKNOWN,
// The service worker started up during browser startup.
DURING_STARTUP,
// The service worker started up in a new process.
NEW_PROCESS,
// The service worker started up in an existing unready process. (Ex: The
// process was created for the navigation by PlzNavigate but the IPC
// connection is not established yet.)
EXISTING_UNREADY_PROCESS,
// The service worker started up in an existing ready process.
EXISTING_READY_PROCESS
};
// Used for UMA. Append only.
// This enum describes how an activated worker was found and prepared (i.e.,
// reached the RUNNING status) in order to dispatch a fetch event to.
enum class WorkerPreparationType {
UNKNOWN = 0,
// The worker was already starting up. We waited for it to finish.
STARTING = 1,
// The worker was already running.
RUNNING = 2,
// The worker was stopping. We waited for it to stop, and then started it
// up.
STOPPING = 3,
// The worker was in the stopped state. We started it up, and startup
// required a new process to be created.
START_IN_NEW_PROCESS = 4,
// Deprecated 07/2017; replaced by START_IN_EXISTING_UNREADY_PROCESS and
// START_IN_EXISTING_READY_PROCESS.
// START_IN_EXISTING_PROCESS = 5,
// The worker was in the stopped state. We started it up, and this occurred
// during browser startup.
START_DURING_STARTUP = 6,
// The worker was in the stopped state. We started it up, and it used an
// existing unready process.
START_IN_EXISTING_UNREADY_PROCESS = 7,
// The worker was in the stopped state. We started it up, and it used an
// existing ready process.
START_IN_EXISTING_READY_PROCESS = 8,
// Add new types here.
NUM_TYPES
};
// Used for UMA. Append only.
// Describes the outcome of a time measurement taken between processes.
enum class CrossProcessTimeDelta {
NORMAL,
NEGATIVE,
INACCURATE_CLOCK,
// Add new types here.
NUM_TYPES
};
class ScopedEventRecorder {
public:
explicit ScopedEventRecorder(EventType start_worker_purpose);
~ScopedEventRecorder();
void RecordEventHandledStatus(EventType event, bool handled);
private:
struct EventStat {
size_t fired_events = 0;
size_t handled_events = 0;
};
// Records how much of dispatched events are handled.
static void RecordEventHandledRatio(EventType event,
size_t handled_events,
size_t fired_events);
std::map<EventType, EventStat> event_stats_;
const EventType start_worker_purpose_;
DISALLOW_COPY_AND_ASSIGN(ScopedEventRecorder);
};
// Converts an event type to a string. Used for tracing.
static const char* EventTypeToString(EventType event_type);
// Converts a start situation to a string. Used for tracing.
static const char* StartSituationToString(StartSituation start_situation);
// If the |url| is not a special site, returns Site::OTHER.
static Site SiteFromURL(const GURL& url);
// Excludes NTP scope from UMA for now as it tends to dominate the stats and
// makes the results largely skewed. Some metrics don't follow this policy
// and hence don't call this function.
static bool ShouldExcludeSiteFromHistogram(Site site);
// Used for ServiceWorkerDiskCache.
static void CountInitDiskCacheResult(bool result);
static void CountReadResponseResult(ReadResponseResult result);
static void CountWriteResponseResult(WriteResponseResult result);
// Used for ServiceWorkerDatabase.
static void CountOpenDatabaseResult(ServiceWorkerDatabase::Status status);
static void CountReadDatabaseResult(ServiceWorkerDatabase::Status status);
static void CountWriteDatabaseResult(ServiceWorkerDatabase::Status status);
static void RecordDestroyDatabaseResult(ServiceWorkerDatabase::Status status);
// Used for ServiceWorkerStorage.
static void RecordPurgeResourceResult(int net_error);
static void RecordDeleteAndStartOverResult(DeleteAndStartOverResult result);
// Counts the number of page loads controlled by a Service Worker.
static void CountControlledPageLoad(Site site,
const GURL& url,
bool is_main_frame_load);
// Records the result of trying to start a worker. |is_installed| indicates
// whether the version has been installed.
static void RecordStartWorkerStatus(blink::ServiceWorkerStatusCode status,
EventType purpose,
bool is_installed);
// Records the result of sending installed scripts to the renderer.
static void RecordInstalledScriptsSenderStatus(
ServiceWorkerInstalledScriptReader::FinishedReason reason);
// Records the time taken to successfully start a worker. |is_installed|
// indicates whether the version has been installed.
static void RecordStartWorkerTime(base::TimeDelta time,
bool is_installed,
StartSituation start_situation,
EventType purpose);
// Records metrics for the preparation of an activated Service Worker for a
// main frame navigation.
CONTENT_EXPORT static void RecordActivatedWorkerPreparationForMainFrame(
base::TimeDelta time,
EmbeddedWorkerStatus initial_worker_status,
StartSituation start_situation,
bool did_navigation_preload,
const GURL& url);
// Records the result of trying to stop a worker.
static void RecordWorkerStopped(StopStatus status);
// Records the time taken to successfully stop a worker.
static void RecordStopWorkerTime(base::TimeDelta time);
static void RecordActivateEventStatus(blink::ServiceWorkerStatusCode status,
bool is_shutdown);
static void RecordInstallEventStatus(blink::ServiceWorkerStatusCode status);
// Records how often a dispatched event times out.
static void RecordEventTimeout(EventType event);
// Records the amount of time spent handling an event.
static void RecordEventDuration(EventType event,
base::TimeDelta time,
bool was_handled);
// Records the time taken between sending an event IPC from the browser
// process to a Service Worker and executing the event handler in the Service
// Worker.
static void RecordEventDispatchingDelay(EventType event,
base::TimeDelta time,
Site site_for_metrics);
// Records the result of dispatching a fetch event to a service worker.
static void RecordFetchEventStatus(bool is_main_resource,
blink::ServiceWorkerStatusCode status);
// Records result of a ServiceWorkerURLRequestJob that was forwarded to
// the service worker.
static void RecordURLRequestJobResult(bool is_main_resource,
URLRequestJobResult result);
// Records the error code provided when the renderer returns a response with
// status zero to a fetch request.
static void RecordStatusZeroResponseError(
bool is_main_resource,
blink::mojom::ServiceWorkerResponseError error);
// Records the mode of request that was fallbacked to the network.
static void RecordFallbackedRequestMode(
network::mojom::FetchRequestMode mode);
// Called at the beginning of each ServiceWorkerVersion::Dispatch*Event
// function. Records the time elapsed since idle (generally the time since the
// previous event ended).
static void RecordTimeBetweenEvents(base::TimeDelta time);
// The following record steps of EmbeddedWorkerInstance's start sequence.
static void RecordProcessCreated(bool is_new_process);
static void RecordTimeToSendStartWorker(base::TimeDelta duration,
StartSituation start_situation);
static void RecordTimeToURLJob(base::TimeDelta duration,
StartSituation start_situation);
static void RecordTimeToStartThread(base::TimeDelta duration,
StartSituation start_situation);
static void RecordTimeToEvaluateScript(base::TimeDelta duration,
StartSituation start_situation);
static void RecordStartMessageLatencyType(CrossProcessTimeDelta type);
CONTENT_EXPORT static void RecordEmbeddedWorkerStartTiming(
mojom::EmbeddedWorkerStartTimingPtr start_timing,
base::TimeTicks start_worker_sent_time,
StartSituation start_situation);
// Records the result of a start attempt that occurred after the worker had
// failed |failure_count| consecutive times.
static void RecordStartStatusAfterFailure(
int failure_count,
blink::ServiceWorkerStatusCode status);
// Records the size of Service-Worker-Navigation-Preload header when the
// navigation preload request is to be sent.
static void RecordNavigationPreloadRequestHeaderSize(size_t size);
// Records timings for the navigation preload response and how
// it compares to starting the worker.
// |worker_start| is the time it took to prepare an activated and running
// worker to receive the fetch event. |initial_worker_status| and
// |start_situation| describe the preparation needed.
// |response_start| is the time it took until the navigation preload response
// started.
// |resource_type| must be RESOURCE_TYPE_MAIN_FRAME or
// RESOURCE_TYPE_SUB_FRAME.
CONTENT_EXPORT static void RecordNavigationPreloadResponse(
base::TimeDelta worker_start,
base::TimeDelta response_start,
EmbeddedWorkerStatus initial_worker_status,
StartSituation start_situation,
ResourceType resource_type);
// Records the result of trying to handle a request for a service worker
// script.
static void RecordContextRequestHandlerStatus(
ServiceWorkerContextRequestHandler::CreateJobStatus status,
bool is_installed,
bool is_main_script);
static void RecordRuntime(base::TimeDelta time);
// Records when an installed service worker imports a script that was not
// previously installed.
// TODO(falken): Remove after this is deprecated. https://crbug.com/737044
static void RecordUninstalledScriptImport(const GURL& url);
// Records the result of starting service worker for a navigation hint.
static void RecordStartServiceWorkerForNavigationHintResult(
StartServiceWorkerForNavigationHintResult result);
// Records the number of origins with a registered service worker.
static void RecordRegisteredOriginCount(size_t origin_count);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics);
};
} // namespace content
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_METRICS_H_