blob: 64629f18d4f0e6c979bd36061dca1799a3120026 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_UTIL_H_
#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_UTIL_H_
#include <cstdint>
#include <optional>
#include <string_view>
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
#include "components/page_load_metrics/common/page_load_metrics_util.h"
#include "components/page_load_metrics/common/page_visit_final_status.h"
#include "third_party/blink/public/common/loader/loading_behavior_flag.h"
#include "url/gurl.h"
// Up to 10 minutes, with 100 buckets.
#define PAGE_LOAD_HISTOGRAM(name, sample) \
base::UmaHistogramCustomTimes(name, sample, base::Milliseconds(10), \
base::Minutes(10), 100)
// 1 ms to 1 minute, with 100 buckets.
#define PAGE_LOAD_SHORT_HISTOGRAM(name, sample) \
base::UmaHistogramCustomTimes(name, sample, base::Milliseconds(1), \
base::Minutes(1), 100)
// Up to 1 hour, with 100 buckets.
#define PAGE_LOAD_LONG_HISTOGRAM(name, sample) \
base::UmaHistogramCustomTimes(name, sample, base::Milliseconds(10), \
base::Hours(1), 100)
// Records |bytes| to |histogram_name| in kilobytes.
#define PAGE_BYTES_HISTOGRAM(histogram_name, bytes) \
base::UmaHistogramCustomCounts(histogram_name, bytes.InKiB(), 1, \
base::MiB(500).InKiB(), 50)
// Up to 1 minute with 50 buckets.
#define INPUT_DELAY_HISTOGRAM(name, sample) \
base::UmaHistogramCustomTimes(name, sample, base::Milliseconds(1), \
base::Seconds(60), 50)
#define PAGE_RESOURCE_COUNT_HISTOGRAM UMA_HISTOGRAM_COUNTS_10000
namespace page_load_metrics {
class PageLoadMetricsObserverDelegate;
namespace mojom {
class PageLoadTiming;
}
// Reasons a page load can be aborted.
enum PageAbortReason {
// Represents no abort.
ABORT_NONE,
// The page was reloaded, possibly by the user.
ABORT_RELOAD,
// The page was navigated away from, via a back or forward navigation.
ABORT_FORWARD_BACK,
// If the page load is replaced by a new navigation. This includes link
// clicks, typing in the omnibox (not a reload), and form submissions.
ABORT_NEW_NAVIGATION,
// The page load was stopped (e.g. the user presses the stop X button).
ABORT_STOP,
// Page load ended due to closing the tab or browser.
ABORT_CLOSE,
// The page load was backgrounded, e.g. the browser was minimized or the user
// switched tabs. Note that the same page may be foregrounded in the future,
// so this is not a 'terminal' abort type.
ABORT_BACKGROUND,
// We don't know why the page load ended. This is the value we assign to a
// terminated provisional load if the only signal we get is the load finished
// without committing, either without error or with net::ERR_ABORTED.
ABORT_OTHER
};
// Information related to a page load abort.
struct PageAbortInfo {
PageAbortInfo()
: reason(ABORT_NONE),
user_initiated_info(UserInitiatedInfo::NotUserInitiated()) {}
PageAbortInfo(PageAbortReason reason,
UserInitiatedInfo user_initiated_info,
base::TimeDelta time_to_abort)
: reason(reason),
user_initiated_info(user_initiated_info),
time_to_abort(time_to_abort) {}
// The reason / cause for the abort.
const PageAbortReason reason;
// The fields below are only valid if reason != ABORT_NONE.
// Information about whether the abort was initiated by a user.
const UserInitiatedInfo user_initiated_info;
// The time from navigation start to the time the page load was aborted.
const base::TimeDelta time_to_abort;
};
// UMA histogram function for logging the max cumulative shift score. Adjusts
// the layout shift score to 10000x for better bucketing at the low end in UMA.
void UmaMaxCumulativeShiftScoreHistogram10000x(
const std::string& name,
const page_load_metrics::NormalizedCLSData& normalized_cls_data);
// Returns true if:
// - We have timing information for the event.
// - The page load started while the page was in the foreground.
// - The event occurred prior to the page being moved to the background.
// When a page is backgrounded, some events (e.g. paint) are delayed. Since
// these data points can skew the mean, they should not be mixed with timing
// events that occurred in the foreground.
// If the event time delta and background time delta are equal, we still
// consider the event to be logged in the foreground histogram since any
// background specific handling would not yet have been applied to that event.
bool WasStartedInForegroundOptionalEventInForeground(
const std::optional<base::TimeDelta>& event,
const PageLoadMetricsObserverDelegate& delegate);
// Returns true if:
// - We have timing information for the event.
// - The page load was prerendered, and was later activated by a navigation that
// started in the foreground.
// - The event occurred prior to the page being moved to the background.
bool WasActivatedInForegroundOptionalEventInForeground(
const std::optional<base::TimeDelta>& event,
const PageLoadMetricsObserverDelegate& delegate);
bool WasStartedInForegroundOptionalEventInForegroundAfterBackForwardCacheRestore(
const std::optional<base::TimeDelta>& event,
const PageLoadMetricsObserverDelegate& delegate,
size_t index);
// Returns true if:
// - We have timing information for the event.
// - The page load started in the background.
// - Moved to the foreground prior to the event.
// - Not moved back to the background prior to the event.
bool WasStartedInBackgroundOptionalEventInForeground(
const std::optional<base::TimeDelta>& event,
const PageLoadMetricsObserverDelegate& delegate);
// Returns true if |delegate| started in the foreground or became foregrounded
// at some point in time.
bool WasInForeground(const PageLoadMetricsObserverDelegate& delegate);
// Returns (navigation start origined) "non prerendering background start" if
// it exists, or nullopt. Here, "non prerendering background start" is the
// minimum timing `x` satisfying:
//
// - The page is background at `x`; and
// - `x` as TimeDelta is greater than or equal to navigation start (resp.
// activation start) if the page is not prerendered (resp. is prerendered).
//
// Note that this can be different from the return value of
// `PageLoadMetricsObserverDelegate::GetTimeToFirstBackground`.
std::optional<base::TimeDelta> GetNonPrerenderingBackgroundStartTiming(
const PageLoadMetricsObserverDelegate& delegate);
// Returns true iff event occurred in prerendered before activation or before
// background start.
//
// Precondition: `HasInvalidActivationStart` must not hold.
// In this case, arbitrary value will be returned.
bool EventOccurredBeforeNonPrerenderingBackgroundStart(
const PageLoadMetricsObserverDelegate& delegate,
const base::TimeDelta& event);
bool EventOccurredBeforeNonPrerenderingBackgroundStart(
const PageLoadMetricsObserverDelegate& delegate,
const page_load_metrics::mojom::PageLoadTiming& timing,
const base::TimeDelta& event);
// Corrects an event with navigation start origin as navigation/activation
// start origin.
//
// If the page is not prerendered, returns the event as is. If the page is
// prerendered, returns activation start origined time delta. Negative values
// are truncated as zero.
base::TimeDelta CorrectEventAsNavigationOrActivationOrigined(
const PageLoadMetricsObserverDelegate& delegate,
const base::TimeDelta& event);
base::TimeDelta CorrectEventAsNavigationOrActivationOrigined(
const PageLoadMetricsObserverDelegate& delegate,
const page_load_metrics::mojom::PageLoadTiming& timing,
const base::TimeDelta& event);
PageAbortInfo GetPageAbortInfo(const PageLoadMetricsObserverDelegate& delegate);
// Get the duration of time that the page spent in the foreground, from
// navigation start until one of the following events:
// * the load of the main resource fails
// * the page load is stopped
// * the tab hosting the page is closed
// * the render process hosting the page goes away
// * a new navigation which later commits is initiated in the same tab
// * the tab hosting the page is backgrounded
std::optional<base::TimeDelta> GetInitialForegroundDuration(
const PageLoadMetricsObserverDelegate& delegate,
base::TimeTicks app_background_time);
// zstd content-coded responses.
bool IsZstdUrl(const GURL& url);
// Whether the given query string contains the given component. The query
// parameter should contain the query string of a URL (the portion following
// the question mark, excluding the question mark). The component must fully
// match a component in the query string. For example, 'foo=bar' would match
// the query string 'a=b&foo=bar&c=d' but would not match 'a=b&zzzfoo=bar&c=d'
// since, though foo=bar appears in the query string, the key specified in the
// component 'foo' does not match the full key in the query string
// 'zzzfoo'. For QueryContainsComponent, the component should of the form
// 'key=value'. For QueryContainsComponentPrefix, the component should be of
// the form 'key=' (where the value is not specified).
// Note: The heuristic used by these functions will not find a component at the
// beginning of the query string if the component starts with a delimiter
// character ('?' or '#'). For example, '?foo=bar' will match the query string
// 'a=b&?foo=bar' but not the query string '?foo=bar&a=b'.
bool QueryContainsComponent(std::string_view query, std::string_view component);
bool QueryContainsComponentPrefix(std::string_view query,
std::string_view component);
// Adjusts the layout shift score for UKM.
int64_t LayoutShiftUkmValue(float shift_score);
// Adjusts the layout shift score for UMA.
int32_t LayoutShiftUmaValue(float shift_score);
// Adjusts the layout shift score to 10000x for better bucketing at the low end
// in UMA.
int32_t LayoutShiftUmaValue10000(float shift_score);
// Helper function that determines the final status for a page visit for a given
// PageLoadTiming, records it to the appropriate UKM metric and UMA histogram,
// and returns the status in case the caller needs to use it elsewhere.
// A 'Page Visit' is a user perceived visit to a page, regardless of how the
// page was navigated to. See the UserPerceivedPageVisit event in
// tools/metrics/ukm.xml.
PageVisitFinalStatus RecordPageVisitFinalStatusForTiming(
const page_load_metrics::mojom::PageLoadTiming& timing,
const PageLoadMetricsObserverDelegate& delegate,
ukm::SourceId source_id);
// Returns the ID if `url` contains a URL param where the param name and value
// matches the prefix pattern configured by Finch (the default param name is
// "category" and the prefix pattern is an empty string / will match anything).
// Returns std::nullopt if the param value is not recognized.
//
// For example, if the valid param name is "cat" and the prefix pattern is
// "pattern", this function may return an ID for (1) but not for (2):
//
// (1) http://a.com?cat=pattern1
// (2) http://b.com?cat=invalid-pattern
//
// UKM Review:
// https://docs.google.com/document/d/1TSbtp5I5Bc1pbAKrrEHfmZlAwgeh6AlgAH7GbDMNPRQ/edit?disco=AAABe5h90jQ
std::optional<uint32_t> GetCategoryIdFromUrl(const GURL& url);
// Returns true if the page is controlled by a service worker.
bool IsServiceWorkerControlled(const PageLoadMetricsObserverDelegate& delegate);
} // namespace page_load_metrics
#endif // COMPONENTS_PAGE_LOAD_METRICS_BROWSER_PAGE_LOAD_METRICS_UTIL_H_