1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
// Copyright 2023 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_BROWSER_PRELOADING_PRELOADING_DECIDER_H_
#define CONTENT_BROWSER_PRELOADING_PRELOADING_DECIDER_H_
#include "content/browser/preloading/preconnector.h"
#include "content/browser/preloading/prefetcher.h"
#include "content/browser/preloading/preloading_confidence.h"
#include "content/browser/preloading/prerenderer.h"
#include "content/public/browser/document_user_data.h"
#include "third_party/blink/public/mojom/preloading/anchor_element_interaction_host.mojom-forward.h"
namespace content {
class RenderFrameHost;
class PreloadingPredictor;
class PreloadingDeciderObserverForTesting {
public:
virtual ~PreloadingDeciderObserverForTesting() = default;
virtual void UpdateSpeculationCandidates(
const std::vector<blink::mojom::SpeculationCandidatePtr>& candidates) = 0;
virtual void OnPointerDown(const GURL& url) = 0;
virtual void OnPointerHover(const GURL& url) = 0;
};
// Processes user interaction events and developer provided speculation-rules
// and based on some heuristics decides which preloading actions are safe and
// worth executing.
// TODO(isaboori): implement the preloading link selection heuristics logic
class CONTENT_EXPORT PreloadingDecider
: public DocumentUserData<PreloadingDecider> {
public:
using SpeculationCandidateKey =
std::pair<GURL, blink::mojom::SpeculationAction>;
~PreloadingDecider() override;
// Receives and processes on pointer down event for 'url' target link.
void OnPointerDown(const GURL& url);
// Receives and processes on pointer hover event for 'url' target link.
void OnPointerHover(const GURL& url,
blink::mojom::AnchorElementPointerDataPtr mouse_data);
// Receives and processes ML model score for 'url' target link.
void OnPreloadingHeuristicsModelDone(const GURL& url, float score);
// Receives and processes 'url' selected by viewport heuristic.
void OnViewportHeuristicTriggered(const GURL& url);
// Sets the new preloading decider observer for testing and returns the old
// one.
PreloadingDeciderObserverForTesting* SetObserverForTesting(
PreloadingDeciderObserverForTesting* observer);
// Returns subcomponents for testing.
Prefetcher& GetPrefetcherForTesting() { return prefetcher_; }
Prerenderer& GetPrerendererForTesting();
// Sets the new prerenderer for testing and returns the old one.
std::unique_ptr<Prerenderer> SetPrerendererForTesting(
std::unique_ptr<Prerenderer> prerenderer);
// Processes the received speculation rules candidates list.
void UpdateSpeculationCandidates(
std::vector<blink::mojom::SpeculationCandidatePtr>& candidates);
// Called when LCP is predicted.
// This is used to defer starting prerenders until LCP timing and is only
// used under LCPTimingPredictorPrerender2.
void OnLCPPredicted();
// Returns true if the |url|, |action| pair is in the on-standby list.
bool IsOnStandByForTesting(const GURL& url,
blink::mojom::SpeculationAction action) const;
// Returns true if there are any candidates.
bool HasCandidatesForTesting() const;
// Called by PrefetchService/PrerendererImpl when a prefetch/prerender is
// evicted/canceled.
void OnPreloadDiscarded(const SpeculationCandidateKey key);
private:
explicit PreloadingDecider(RenderFrameHost* rfh);
friend class DocumentUserData<PreloadingDecider>;
DOCUMENT_USER_DATA_KEY_DECL();
// Attempts preloading actions starting from the most advanced (prerendering)
// to least (preconnect), in response to `enacting_predictor` predicting a
// navigation to `url`. If `fallback_to_preconnect` is true, we preconnect if
// no other action is taken.
void MaybeEnactCandidate(const GURL& url,
const PreloadingPredictor& enacting_predictor,
PreloadingConfidence confidence,
bool fallback_to_preconnect);
// TODO(crbug.com/381687257): 1. Inline the logic in
// `GetMatchedPreloadingCandidate` to reduce redundant code. 2. Support NVS
// matching logic.
// Returns a vector of std::optional<string> of candidates which will be
// enacted by the given parameter. This function is used for non-eager
// candidates only.
std::vector<std::optional<std::string>>
GetMergedSpeculationTagsFromSuitableCandidates(
const PreloadingDecider::SpeculationCandidateKey& lookup_key,
const PreloadingPredictor& enacting_predictor,
PreloadingConfidence confidence);
// Prefetches the |url| if it is safe and eligible to be prefetched.
// Returns false if no suitable (given |enacting_predictor|) on-standby
// candidate is found for the given |url|, or the Prefetcher does not
// accept the candidate.
bool MaybePrefetch(const GURL& url,
const PreloadingPredictor& enacting_predictor,
PreloadingConfidence confidence);
// Returns true if a prefetch was attempted for the |url| and is not failed or
// discarded by Prefetcher yet, and we should wait for it to finish.
bool ShouldWaitForPrefetchResult(const GURL& url);
// Prerenders the |url| if it is safe and eligible to be prerendered. Returns
// false for the first bool if no suitable (given |enacting_predictor|)
// on-standby candidate is found for the given |url|, or the Prerenderer does
// not accept the candidate. Returns true for the second bool if a
// PreloadingPrediction has been added.
std::pair<bool, bool> MaybePrerender(
const GURL& url,
const PreloadingPredictor& enacting_predictor,
PreloadingConfidence confidence);
// Returns true if a prerender was attempted for the |url| and is not failed
// or discarded by Prerenderer yet, and we should wait for it to finish.
bool ShouldWaitForPrerenderResult(const GURL& url);
// Helper function to add a preloading prediction for the |url|
void AddPreloadingPrediction(const GURL& url,
PreloadingPredictor predictor,
PreloadingConfidence confidence);
// Return true if |candidate| can be selected in response to a prediction by
// |predictor|.
bool IsSuitableCandidate(
const blink::mojom::SpeculationCandidatePtr& candidate,
const PreloadingPredictor& predictor,
PreloadingConfidence confidence,
blink::mojom::SpeculationAction action) const;
// Helper functions to add/remove a preloading candidate to
// |on_standby_candidates_| and to reset |on_standby_candidates_|. Use these
// methods to make sure |on_standby_candidates_| and
// |no_vary_search_hint_on_standby_candidates_| are kept in sync
void AddStandbyCandidate(
const blink::mojom::SpeculationCandidatePtr& candidate);
void RemoveStandbyCandidate(const SpeculationCandidateKey key);
void ClearStandbyCandidates();
// Helper functions to select a prerender/prefetch candidate to be
// triggered.
std::optional<
std::pair<SpeculationCandidateKey, blink::mojom::SpeculationCandidatePtr>>
GetMatchedPreloadingCandidate(const SpeculationCandidateKey& lookup_key,
const PreloadingPredictor& enacting_predictor,
PreloadingConfidence confidence) const;
std::optional<
std::pair<SpeculationCandidateKey, blink::mojom::SpeculationCandidatePtr>>
GetMatchedPreloadingCandidateByNoVarySearchHint(
const SpeculationCandidateKey& lookup_key,
const PreloadingPredictor& enacting_predictor,
PreloadingConfidence confidence) const;
// |on_standby_candidates_| stores preloading candidates for each target URL,
// action pairs that are safe to perform but are not marked as |kEager| and
// should be performed when we are confident enough that the user will most
// likely navigate to the target URL.
std::map<SpeculationCandidateKey,
std::vector<blink::mojom::SpeculationCandidatePtr>>
on_standby_candidates_;
// |nvs_hint_on_standby_candidates_| stores for a URL without query and
// fragment, action pairs that are safe to perform but are not marked as
// |kEager| and should be performed when we are confident enough that the user
// will most likely navigate to a URL that matches based on the presence
// of No-Vary-Search hint the candidate's URL.
// This map needs to be kept in sync with the |on_standby_candidates_| map.
std::map<SpeculationCandidateKey, std::set<SpeculationCandidateKey>>
no_vary_search_hint_on_standby_candidates_;
// |processed_candidates_| stores all target URL, action pairs that are
// already processed by prefetcher or prerenderer, and maps them to all
// candidates with the same URL, action pair. Right now it is needed to avoid
// adding such candidates back to |on_standby_candidates_| whenever there is
// an update in speculation rules.
std::map<SpeculationCandidateKey,
std::vector<blink::mojom::SpeculationCandidatePtr>>
processed_candidates_;
// Behavior determined dynamically. Stored on this object rather than globally
// so that it does not span unit tests.
class BehaviorConfig;
std::unique_ptr<const BehaviorConfig> behavior_config_;
// Whether this page has ever received an ML model prediction. Once it has,
// the model predictions supersede the hover heuristic. We store this here,
// rather than per-BrowserContext, since even if the model is loaded, it may
// not run for some pages (e.g. insecure http).
bool ml_model_available_ = false;
raw_ptr<PreloadingDeciderObserverForTesting> observer_for_testing_;
Preconnector preconnector_;
Prefetcher prefetcher_;
std::unique_ptr<Prerenderer> prerenderer_;
};
} // namespace content
#endif // CONTENT_BROWSER_PRELOADING_PRELOADING_DECIDER_H_
|