blob: 72e6367189cfbc8cb85b362a11f6aeba95026a8d [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_PUBLIC_BROWSER_PRELOADING_DATA_H_
#define CONTENT_PUBLIC_BROWSER_PRELOADING_DATA_H_
#include <optional>
#include "base/functional/callback.h"
#include "content/common/content_export.h"
#include "content/public/browser/preloading.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/gurl.h"
namespace content {
class WebContents;
class NavigationHandle;
using PreloadingURLMatchCallback = base::RepeatingCallback<bool(const GURL&)>;
using PredictorDomainCallback =
base::RepeatingCallback<bool(NavigationHandle*)>;
// PreloadingPrediction and PreloadingAttempt are the preloading logging APIs
// which allows us to set various metrics and log the values.
// All these metrics are logged into the UKM after the page navigates or when
// the WebContents is being destroyed. This API will be used by features both
// inside and outside //content.
// Both PreloadingPrediction and PreloadingAttempt are owned by PreloadingData
// class and that is associated with WebContentsUserData. PreloadingAttempt is
// cleared when either
// - A WebContents is deleted/ destroyed.
// - Primary page of the WebContents changes.
// PreloadingAttempt keeps track of every preloading attempt associated with
// various preloading features defined in preloading.h (please see the comments
// there for more details); whether it is eligible, whether it is triggered or
// not, specifies the failure reason on failing and others.
class CONTENT_EXPORT PreloadingAttempt {
public:
// Sets whether preloading is eligible to be triggered. This should only be
// called once per preloading attempt.
virtual void SetEligibility(PreloadingEligibility eligibility) = 0;
// Whether this preloading attempt should be held back in order to
// counterfactually evaluate how well this type of preloading is performing.
// This is controlled via field trial configuration. Users of preloading
// attempt should always call this before triggering an eligible preloading
// attempt. Note that individual features can also use their own field
// trial-controlled holdbacks, in which case preloading should be disabled if
// either the feature's holdback is enabled or if ShouldHoldback returns true.
// Features implementing their own holdback to should record held back
// preloading attempts by calling SetHoldbackStatus (declared below).
virtual bool ShouldHoldback() = 0;
// Sets the outcome of the holdback check used to implement counterfactual
// experiments. This is not part of eligibility status to clarify that this
// check needs to happen after we are done verifying the eligibility of a
// preloading attempt. In general, eligibility checks can be reordered, but
// the holdback check always needs to come after verifying that the preloading
// attempt was eligible. This must only be called after calling
// SetEligibility(kEligible) and should not be called more than once.
virtual void SetHoldbackStatus(PreloadingHoldbackStatus holdback_status) = 0;
// Updates the preload outcome after it was triggered. This should only be
// called for eligible attempts with a kAllowed holdback status.
// - Initially set to kUnspecified.
// - After triggering this if there is already a preloading attempt available
// for the same URL we set to kDuplicate, or
// - kRunning (for preloading methods with given enough time, we expect to
// update with kReady/ kSuccess/ kFailure).
virtual void SetTriggeringOutcome(
PreloadingTriggeringOutcome triggering_outcome) = 0;
// Sets the specific failure reason specific to the PreloadingType. This also
// sets the PreloadingTriggeringOutcome to kFailure.
virtual void SetFailureReason(PreloadingFailureReason failure_reason) = 0;
virtual base::WeakPtr<PreloadingAttempt> GetWeakPtr() = 0;
protected:
virtual ~PreloadingAttempt() = default;
};
// PreloadingData holds the data associated with all the PreloadingAttempts
// and PreloadingPredictions. This class is responsible for notifying all the
// PreloadingAttempts and PreloadingPredictions about logging the UKMs and
// maintaining its lifetime.
// Lifetime of PreloadingData is associated with WebContentsUserData.
class CONTENT_EXPORT PreloadingData {
public:
// This static function is implemented in PreloadingDataImpl.
// Please see content/browser/preloading/preloading_data_impl.cc for more
// details.
static PreloadingData* GetOrCreateForWebContents(WebContents* web_contents);
static PreloadingData* GetForWebContents(WebContents* web_contents);
// Helper method to return the PreloadingURLMatchCallback for
// `destination_url`. This method will return true only for exact matches to
// `destination_url`.
static PreloadingURLMatchCallback GetSameURLMatcher(
const GURL& destination_url);
// Creates a new PreloadingAttempt and returns a pointer associated with the
// PreloadingAttempt class. Here callers pass the `url_predicate_callback` to
// verify if the navigated and triggered URLs match based on callers logic.
//
// A caller can pass `planned_max_preloading_type` (defaults to
// `preloading_type`) different from `preloading_type` if the caller expects
// this preloading attempt will be consumed by other preloadings. For
// example, a caller can start from triggering prefetch and then proceed
// with triggering prerender. `preloading_type` must be upgradable to
// `planned_max_preloading_type`. See `IsPreloadingTypeUpgradableTo()` in
// //content/browser/preloading/preloading_attempt_impl.cc.
//
// `triggering_primary_page_source_id` is a UKM source ID of the page that
// triggered preloading. This is used for recording the metrics for user
// visible primary pages (Preloading_Attempt_PreviousPrimaryPage) to measure
// the impact of PreloadingAttempt on the page user is viewing.
// TODO(crbug.com/40227283): Extend this for non-primary page and inner
// WebContents preloading attempts.
virtual PreloadingAttempt* AddPreloadingAttempt(
PreloadingPredictor predictor,
PreloadingType preloading_type,
PreloadingURLMatchCallback url_match_predicate,
std::optional<PreloadingType> planned_max_preloading_type,
ukm::SourceId triggering_primary_page_source_id) = 0;
// Creates a new PreloadingPrediction. Same as above `url_predicate_callback`
// is passed by the caller to verify that both predicted and navigated URLs
// match. `confidence` signifies the confidence percentage of correct
// predictor's preloading prediction.
//
// `triggering_primary_page_source_id` is a UKM source ID of the page that
// triggered preloading. This is used for recording the metrics for user
// visible primary pages (Preloading_Prediction_PreviousPrimaryPage) to
// measure the impact of PreloadingPrediction on the page user is viewing.
virtual void AddPreloadingPrediction(
PreloadingPredictor predictor,
int confidence,
PreloadingURLMatchCallback url_match_predicate,
ukm::SourceId triggering_primary_page_source_id) = 0;
// To calculate the recall score of the `predictor`, we need to know if the
// `predictor` is potentially responsible for predicting the next navigation
// or not. Here, if caller provided `is_navigation_in_domain_callback`
// callback returns true for the navigation, it will be considered in the
// predictor's domain. The predictor's domain is the set of navigations a
// predictor is meant to handle (predict). For example, for Omnibox DUI, this
// is the set of navigations to history URLs started from the Omnibox
// (navigations where the user ends up choosing a Search query or where the
// user closes the Omnibox and clicks on a link in the page are not part of
// the domain of the Omnibox DUI predictor).
virtual void SetIsNavigationInDomainCallback(
PreloadingPredictor predictor,
PredictorDomainCallback is_navigation_in_domain_callback) = 0;
// This flag will be true if there's been at least 1 attempt to do a
// speculation-rules based prerender.
virtual bool HasSpeculationRulesPrerender() = 0;
// Called when the embedder is making a prediction with an ML model about
// whether a navigation to `url` will occur. The provided callback will be
// invoked on navigation with the result of whether the prediction would be
// accurate. If downsampling occurs, some callbacks may not be invoked, and
// the ones that are invoked will have the amount of sampling indicated in the
// `sampling_likelihood`.
virtual void OnPreloadingHeuristicsModelInput(
const GURL& url,
base::OnceCallback<void(std::optional<double> sampling_likelihood,
bool is_accurate_prediction)>
on_record_outcome) = 0;
protected:
virtual ~PreloadingData() = default;
};
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_PRELOADING_DATA_H_