File: preloading_decider.h

package info (click to toggle)
chromium 140.0.7339.127-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,192,880 kB
  • sloc: cpp: 35,093,808; ansic: 7,161,670; javascript: 4,199,694; python: 1,441,797; asm: 949,904; xml: 747,503; pascal: 187,748; perl: 88,691; sh: 88,248; objc: 79,953; sql: 52,714; cs: 44,599; fortran: 24,137; makefile: 22,114; tcl: 15,277; php: 13,980; yacc: 9,000; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (258 lines) | stat: -rw-r--r-- 11,763 bytes parent folder | download | duplicates (3)
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
// 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 "base/containers/enum_set.h"
#include "base/gtest_prod_util.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"
#include "third_party/blink/public/mojom/speculation_rules/speculation_rules.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,
      blink::mojom::SpeculationEagerness target_eagerness) = 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>;
  using EagernessSet =
      base::EnumSet<blink::mojom::SpeculationEagerness,
                    blink::mojom::SpeculationEagerness::kMinValue,
                    blink::mojom::SpeculationEagerness::kMaxValue>;

  ~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,
                      blink::mojom::SpeculationEagerness target_eagerness);

  //  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,
                           EagernessSet eagerness_to_exclude);

  // Merges the tags of all suitable candidates that match the given
  // `lookup_key`.
  // Returns a vector of std::optional<string> of candidates which will be
  // enacted by the given parameter. This function is used for non-immediate
  // candidates only.
  std::vector<std::optional<std::string>>
  GetMergedSpeculationTagsFromSuitableCandidates(
      const PreloadingDecider::SpeculationCandidateKey& lookup_key,
      const PreloadingPredictor& enacting_predictor,
      PreloadingConfidence confidence,
      EagernessSet eagerness_to_exclude);

  // 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,
                     EagernessSet eagerness_to_exclude);

  // 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,
      EagernessSet eagerness_to_exclude);

  // 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,
      EagernessSet eagerness_to_exclude) 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,
                                EagernessSet eagerness_to_exclude) const;

 private:
  // Grant the test suite access to private members.
  FRIEND_TEST_ALL_PREFIXES(PreloadingDeciderTest,
                           SpeculationRulesTagsMergingForNVSMatch);
  FRIEND_TEST_ALL_PREFIXES(PreloadingDeciderTest,
                           SpeculationRulesTagsMergingForNVSMatchWithNullTags);

  // This helper function encapsulates the shared logic for finding all
  // suitable candidates matching a lookup key, including No-Vary-Search logic.
  std::vector<
      std::pair<SpeculationCandidateKey, blink::mojom::SpeculationCandidatePtr>>
  FindSuitableCandidates(const SpeculationCandidateKey& lookup_key,
                         const PreloadingPredictor& enacting_predictor,
                         PreloadingConfidence confidence,
                         EagernessSet eagerness_to_exclude) const;

  // Enumerates all candidates that match the given `lookup_key` based on
  // No-Vary-Search hint and invokes the visitor for each match.
  // If the visitor returns true, enumeration stops early; if false,
  // continues enumerating all matches.
  template <typename Visitor>
  void EnumerateNoVarySearchMatchedCandidates(
      const SpeculationCandidateKey& lookup_key,
      const PreloadingPredictor& enacting_predictor,
      PreloadingConfidence confidence,
      EagernessSet eagerness_to_exclude,
      Visitor&& visitor) const;

  // |on_standby_candidates_| stores preloading candidates for each target URL,
  // action pairs that are safe to perform but are not marked as |kImmediate|
  // 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
  // |kImmediate| 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_