File: navigation_predictor.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (201 lines) | stat: -rw-r--r-- 7,922 bytes parent folder | download | duplicates (5)
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
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_NAVIGATION_PREDICTOR_NAVIGATION_PREDICTOR_H_
#define CHROME_BROWSER_NAVIGATION_PREDICTOR_NAVIGATION_PREDICTOR_H_

#include <set>
#include <unordered_map>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "chrome/browser/navigation_predictor/navigation_predictor_metrics_document_data.h"
#include "chrome/browser/navigation_predictor/preloading_model_keyed_service.h"
#include "chrome/browser/page_load_metrics/observers/page_anchors_metrics_observer.h"
#include "content/public/browser/document_service.h"
#include "content/public/browser/visibility.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/mojom/loader/navigation_predictor.mojom.h"
#include "url/origin.h"

namespace content {
class RenderFrameHost;
}  // namespace content

// This class gathers metrics of anchor elements from both renderer process
// and browser process. Then it uses these metrics to make predictions on what
// are the most likely anchor elements that the user will click.
//
// This class derives from WebContentsObserver so that it can keep track of when
// WebContents is being destroyed via web_contents().
class NavigationPredictor
    : public content::DocumentService<blink::mojom::AnchorElementMetricsHost> {
 public:
  using ModelScoreCallbackForTesting = base::OnceCallback<void(
      const PreloadingModelKeyedService::Inputs& inputs)>;

  // These values are persisted to logs.
  enum FontSizeBucket : uint8_t {
    kLessThanTen = 1,
    kTenToSeventeen = 2,
    kEighteenOrGreater = 3,
  };

  NavigationPredictor(const NavigationPredictor&) = delete;
  NavigationPredictor& operator=(const NavigationPredictor&) = delete;

  // Create and bind NavigationPredictor.
  static void Create(content::RenderFrameHost* render_frame_host,
                     mojo::PendingReceiver<AnchorElementMetricsHost> receiver);

  void SetModelScoreCallbackForTesting(ModelScoreCallbackForTesting callback);

  static void DisableRendererMetricSendingDelayForTesting();

 private:
  friend class MockNavigationPredictorForTesting;
  using AnchorId = base::StrongAlias<class AnchorId, uint32_t>;
  struct AnchorElementData;

  NavigationPredictor(content::RenderFrameHost& render_frame_host,
                      mojo::PendingReceiver<AnchorElementMetricsHost> receiver);
  ~NavigationPredictor() override;

  // blink::mojom::AnchorElementMetricsHost:
  void ReportAnchorElementClick(
      blink::mojom::AnchorElementClickPtr click) override;
  void ReportAnchorElementsEnteredViewport(
      std::vector<blink::mojom::AnchorElementEnteredViewportPtr> elements)
      override;
  void ReportAnchorElementsLeftViewport(
      std::vector<blink::mojom::AnchorElementLeftViewportPtr> elements)
      override;
  void ReportAnchorElementsPositionUpdate(
      std::vector<blink::mojom::AnchorElementPositionUpdatePtr> elements)
      override;
  void ReportAnchorElementPointerDataOnHoverTimerFired(
      blink::mojom::AnchorElementPointerDataOnHoverTimerFiredPtr pointer_data)
      override;
  void ReportAnchorElementPointerOver(
      blink::mojom::AnchorElementPointerOverPtr pointer_over_event) override;
  void ReportAnchorElementPointerOut(
      blink::mojom::AnchorElementPointerOutPtr hover_event) override;
  void ReportAnchorElementPointerDown(
      blink::mojom::AnchorElementPointerDownPtr pointer_down_event) override;
  void ReportNewAnchorElements(
      std::vector<blink::mojom::AnchorElementMetricsPtr> elements,
      const std::vector<uint32_t>& removed_elements) override;
  void ProcessPointerEventUsingMLModel(
      blink::mojom::AnchorElementPointerEventForMLModelPtr pointer_event)
      override;
  void ShouldSkipUpdateDelays(ShouldSkipUpdateDelaysCallback callback) override;

  void OnMLModelExecutionTimerFired();

  // Computes and stores document level metrics, including |number_of_anchors_|
  // etc.
  void ComputeDocumentMetricsOnLoad(
      const std::vector<blink::mojom::AnchorElementMetricsPtr>& metrics);

  // Record anchor element metrics on page load.
  void RecordMetricsOnLoad(
      const blink::mojom::AnchorElementMetrics& metric) const;

  // Returns `NavigationPredictorMetricsDocumentData` for the current page.
  NavigationPredictorMetricsDocumentData&
  GetNavigationPredictorMetricsDocumentData() const;

  // Called when the async preloading heuristics model is done running and the
  // returned the result.
  virtual void OnPreloadingHeuristicsModelDone(
      GURL url,
      PreloadingModelKeyedService::Result result);

  bool IsTargetURLTheSameAsDocument(const AnchorElementData& anchor);

  base::TimeTicks NowTicks() const { return clock_->NowTicks(); }

  // A count of clicks to prevent reporting more than 10 clicks to UKM.
  size_t clicked_count_ = 0;

  // Stores the anchor element metrics for each anchor ID that we track.
  struct AnchorElementData {
    AnchorElementData(blink::mojom::AnchorElementMetricsPtr metrics,
                      base::TimeTicks first_report_timestamp);
    ~AnchorElementData();

    // The following fields mirror `blink::mojom::AnchorElementMetrics`, but
    // unused fields are omitted and fields are arranged to minimize memory
    // usage.
    float ratio_distance_root_top;
    // `ratio_area` is [0,100], so we can store this more compactly than with a
    // float.
    uint8_t ratio_area;
    bool is_in_iframe : 1;
    bool contains_image : 1;
    bool is_same_host : 1;
    bool is_url_incremented_by_one : 1;
    bool has_text_sibling : 1;
    bool is_bold_font : 1;
    FontSizeBucket font_size;
    GURL target_url;

    // Following fields are used for computing timing inputs of the ML model.
    base::TimeTicks first_report_timestamp;
    std::optional<base::TimeTicks> pointer_over_timestamp;
    size_t pointer_hovering_over_count = 0u;
  };
  std::unordered_map<AnchorId, AnchorElementData> anchors_;
  // It is the anchor element that the user has recently interacted
  // with and is a good candidate for the ML model to predict the next user
  // click.
  std::optional<AnchorId> ml_model_candidate_;

  // The time between navigation start and the last time user clicked on a link.
  std::optional<base::TimeDelta> navigation_start_to_click_;

  // Mapping between the anchor ID for the anchors that we track and the index
  // that this anchor will have in the UKM logs.
  std::unordered_map<AnchorId, int> tracked_anchor_id_to_index_;

  // URLs that were sent to the prediction service.
  // We store hashes of URLs, rather than URLs themselves, to save memory.
  // TODO(mcnee): Would it be better to use a bloom filter to have a limit on
  // the memory usage needed for this?
  std::set<size_t> predicted_urls_;

  // UKM ID for navigation
  ukm::SourceId ukm_source_id_;

  // UKM recorder
  raw_ptr<ukm::UkmRecorder> ukm_recorder_ = nullptr;

  // The time at which the navigation started.
  base::TimeTicks navigation_start_;

  // Used to cancel ML model execution requests sent to
  // `PreloadingModelKeyedService`.
  base::CancelableTaskTracker scoring_model_task_tracker_;

  raw_ptr<const base::TickClock> clock_;

  static bool disable_renderer_metric_sending_delay_for_testing_;

  base::OneShotTimer ml_model_execution_timer_;

  ModelScoreCallbackForTesting model_score_callback_;

  SEQUENCE_CHECKER(sequence_checker_);

  base::WeakPtrFactory<NavigationPredictor> weak_ptr_factory_{this};
};

#endif  // CHROME_BROWSER_NAVIGATION_PREDICTOR_NAVIGATION_PREDICTOR_H_