blob: 9014b99383a09d9d30c6e25fbaaa0cdf869b2c3f [file] [log] [blame]
Simon Pelchat9ed3e992023-02-17 01:16:161// Copyright 2023 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/preloading/preloading_config.h"
6
Md Hasibul Hasana963a9342024-04-03 10:15:147#include <string_view>
8
Simon Pelchat9ed3e992023-02-17 01:16:169#include "base/json/json_reader.h"
10#include "base/metrics/field_trial_params.h"
Simon Pelchat9ed3e992023-02-17 01:16:1611#include "base/values.h"
12#include "content/browser/preloading/preloading.h"
Arthur Sonzognibdeca8e2023-09-11 08:32:1213#include "content/common/features.h"
Simon Pelchat9ed3e992023-02-17 01:16:1614#include "content/public/browser/preloading.h"
15
16namespace content {
17
Simon Pelchat9ed3e992023-02-17 01:16:1618namespace {
19
20// Allows configuring preloading features via a JSON string. This string should
21// contain a JSON array of objects. Each object should specify a preloading_type
22// key (a string to specify which preloading type is being configured) and a
23// predictor key (a string to specify which predictor is being configured). Then
24// each object can specify some parameters to tune. Supported parameters are:
25// * holdback: whether this preloading_type, predictor combination should be
26// held back for counterfactual evaluation.
27// * sampling_likelihood: the fraction of preloading attempts that will be
Simon Pelchatefb7e7f2023-04-04 01:20:4828// logged in UKM. See crbug.com/1411841#c3 to see how the sampling_likelihood
29// default values are determined.
Simon Pelchat9ed3e992023-02-17 01:16:1630constexpr base::FeatureParam<std::string> kPreloadingConfigParam{
Simon Pelchatefb7e7f2023-04-04 01:20:4831 &features::kPreloadingConfig, "preloading_config", R"(
32[{
Simon Pelchat396a94e92023-08-03 03:28:5833 "preloading_type": "NoStatePrefetch",
34 "preloading_predictor": "LinkRel",
Domenic Denicola4229f402025-05-09 01:38:5735 "sampling_likelihood": 0.005689
Simon Pelchatefb7e7f2023-04-04 01:20:4836}, {
37 "preloading_type": "Preconnect",
38 "preloading_predictor": "PointerDownOnAnchor",
Domenic Denicola4229f402025-05-09 01:38:5739 "sampling_likelihood": 0.000100
Domenic Denicolaf868a2162023-11-10 06:43:2640}, {
41 "preloading_type": "Prefetch",
42 "preloading_predictor": "DefaultSearchEngine",
Domenic Denicola4229f402025-05-09 01:38:5743 "sampling_likelihood": 0.005785
Domenic Denicolae9def0e2024-10-23 04:42:5944}, {
45 "preloading_type": "Prefetch",
46 "preloading_predictor": "OmniboxMousePredictor",
Domenic Denicola4229f402025-05-09 01:38:5747 "sampling_likelihood": 0.357184
Domenic Denicolae9def0e2024-10-23 04:42:5948}, {
49 "preloading_type": "Prefetch",
50 "preloading_predictor": "OmniboxSearchPredictor",
Domenic Denicola4229f402025-05-09 01:38:5751 "sampling_likelihood": 0.670228
Domenic Denicolaf868a2162023-11-10 06:43:2652}, {
53 "preloading_type": "Prefetch",
Domenic Denicolaf2b4d3a2024-01-31 10:59:0854 "preloading_predictor": "OmniboxTouchDownPredirector",
Domenic Denicola4229f402025-05-09 01:38:5755 "sampling_likelihood": 0.010079
Domenic Denicolaf2b4d3a2024-01-31 10:59:0856}, {
57 "preloading_type": "Prefetch",
Domenic Denicolaf868a2162023-11-10 06:43:2658 "preloading_predictor": "SpeculationRules",
Domenic Denicola4229f402025-05-09 01:38:5759 "sampling_likelihood": 0.000892
Domenic Denicolaf2b4d3a2024-01-31 10:59:0860}, {
61 "preloading_type": "Prefetch",
62 "preloading_predictor": "SpeculationRulesFromIsolatedWorld",
Domenic Denicolae2d56682024-06-05 07:18:4563 "sampling_likelihood": 1.000000
Domenic Denicolaf868a2162023-11-10 06:43:2664}, {
Domenic Denicolaa7ea9c72024-06-03 08:28:2365 "preloading_type": "Prefetch",
66 "preloading_predictor": "UrlPointerDownOnAnchor",
Domenic Denicola4229f402025-05-09 01:38:5767 "sampling_likelihood": 0.002821
Domenic Denicolaa7ea9c72024-06-03 08:28:2368}, {
69 "preloading_type": "Prefetch",
70 "preloading_predictor": "UrlPointerHoverOnAnchor",
Domenic Denicola4229f402025-05-09 01:38:5771 "sampling_likelihood": 0.033897
72}, {
73 "preloading_type": "Prefetch",
74 "preloading_predictor": "ViewportHeuristic",
75 "sampling_likelihood": 1.000000
Domenic Denicolaa7ea9c72024-06-03 08:28:2376}, {
Domenic Denicolaf868a2162023-11-10 06:43:2677 "preloading_type": "Prerender",
78 "preloading_predictor": "BackButtonHover",
Domenic Denicola4229f402025-05-09 01:38:5779 "sampling_likelihood": 0.006551
Domenic Denicolaf868a2162023-11-10 06:43:2680}, {
81 "preloading_type": "Prerender",
82 "preloading_predictor": "BackGestureNavigation",
Domenic Denicola4229f402025-05-09 01:38:5783 "sampling_likelihood": 0.209279
Domenic Denicolaf868a2162023-11-10 06:43:2684}, {
85 "preloading_type": "Prerender",
86 "preloading_predictor": "DefaultSearchEngine",
Domenic Denicola4229f402025-05-09 01:38:5787 "sampling_likelihood": 0.005771
Domenic Denicolaf868a2162023-11-10 06:43:2688}, {
89 "preloading_type": "Prerender",
90 "preloading_predictor": "MouseBackButton",
Domenic Denicola4229f402025-05-09 01:38:5791 "sampling_likelihood": 0.070962
Domenic Denicola02479122024-02-28 01:30:0892}, {
93 "preloading_type": "Prerender",
94 "preloading_predictor": "MouseHoverOrMouseDownOnBookmarkBar",
Domenic Denicola4229f402025-05-09 01:38:5795 "sampling_likelihood": 0.022187
Domenic Denicola60892842024-11-26 05:03:4796}, {
97 "preloading_type": "Prerender",
98 "preloading_predictor": "MouseHoverOrMouseDownOnNewTabPage",
Domenic Denicola4229f402025-05-09 01:38:5799 "sampling_likelihood": 0.030196
Domenic Denicolaf868a2162023-11-10 06:43:26100}, {
101 "preloading_type": "Prerender",
102 "preloading_predictor": "OmniboxDirectURLInput",
Domenic Denicola4229f402025-05-09 01:38:57103 "sampling_likelihood": 0.005348
Domenic Denicolaf868a2162023-11-10 06:43:26104}, {
105 "preloading_type": "Prerender",
106 "preloading_predictor": "SpeculationRules",
Domenic Denicola4229f402025-05-09 01:38:57107 "sampling_likelihood": 0.046348
Domenic Denicolaf868a2162023-11-10 06:43:26108}, {
109 "preloading_type": "Prerender",
110 "preloading_predictor": "SpeculationRulesFromIsolatedWorld",
Domenic Denicolae2d56682024-06-05 07:18:45111 "sampling_likelihood": 1.000000
Domenic Denicolaa7ea9c72024-06-03 08:28:23112}, {
113 "preloading_type": "Prerender",
Domenic Denicola91f1daf92024-08-30 05:10:15114 "preloading_predictor": "TouchOnNewTabPage",
Domenic Denicola4229f402025-05-09 01:38:57115 "sampling_likelihood": 0.028625
Domenic Denicola91f1daf92024-08-30 05:10:15116}, {
117 "preloading_type": "Prerender",
Domenic Denicolaa7ea9c72024-06-03 08:28:23118 "preloading_predictor": "UrlPointerDownOnAnchor",
Domenic Denicola4229f402025-05-09 01:38:57119 "sampling_likelihood": 0.132505
Domenic Denicolaa7ea9c72024-06-03 08:28:23120}, {
121 "preloading_type": "Prerender",
122 "preloading_predictor": "UrlPointerHoverOnAnchor",
Domenic Denicola4229f402025-05-09 01:38:57123 "sampling_likelihood": 0.525988
124}, {
125 "preloading_type": "Prerender",
126 "preloading_predictor": "ViewportHeuristic",
127 "sampling_likelihood": 1.000000
Simon Pelchatefb7e7f2023-04-04 01:20:48128}]
129)"};
Simon Pelchatb2ce6df2023-07-26 21:48:37130
131static PreloadingConfig* g_config_override = nullptr;
132
Simon Pelchat9ed3e992023-02-17 01:16:16133} // namespace
134
135PreloadingConfig& PreloadingConfig::GetInstance() {
136 static base::NoDestructor<PreloadingConfig> config;
Simon Pelchatb2ce6df2023-07-26 21:48:37137 static bool initialized = false;
138 if (!initialized) {
139 config->ParseConfig();
140 initialized = true;
141 }
142
143 if (g_config_override) {
144 return *g_config_override;
145 }
Simon Pelchat9ed3e992023-02-17 01:16:16146 return *config;
147}
148
Simon Pelchatb2ce6df2023-07-26 21:48:37149PreloadingConfig::PreloadingConfig() = default;
150
151PreloadingConfig* PreloadingConfig::OverrideForTesting(
152 PreloadingConfig* config_override) {
153 raw_ptr<PreloadingConfig> old_override = g_config_override;
154 g_config_override = config_override;
155 return old_override;
Simon Pelchat9ed3e992023-02-17 01:16:16156}
157
158void PreloadingConfig::ParseConfig() {
159 entries_.clear();
160
161 if (!base::FeatureList::IsEnabled(features::kPreloadingConfig)) {
162 return;
163 }
164 // Throughout parsing the config, if we fail to parse, we silently skip the
165 // config and use the default values.
Arthur Sonzognic686e8f2024-01-11 08:36:37166 std::optional<base::Value> config_value =
Simon Pelchat9ed3e992023-02-17 01:16:16167 base::JSONReader::Read(kPreloadingConfigParam.Get());
168 if (!config_value) {
169 return;
170 }
171 base::Value::List* entries = config_value->GetIfList();
172 if (!entries) {
173 return;
174 }
175
176 for (const base::Value& entry : *entries) {
177 const base::Value::Dict* config_dict = entry.GetIfDict();
178 DCHECK(config_dict);
179 if (!config_dict) {
180 continue;
181 }
182
183 const std::string* preloading_type =
184 config_dict->FindString("preloading_type");
185 DCHECK(preloading_type);
186 if (!preloading_type) {
187 continue;
188 }
189
190 const std::string* preloading_predictor =
191 config_dict->FindString("preloading_predictor");
192 DCHECK(preloading_predictor);
193 if (!preloading_predictor) {
194 continue;
195 }
196
197 entries_.emplace(Key(*preloading_type, *preloading_predictor),
198 Entry::FromDict(config_dict));
199 }
200}
201
202PreloadingConfig::~PreloadingConfig() = default;
203
204bool PreloadingConfig::ShouldHoldback(PreloadingType preloading_type,
205 PreloadingPredictor predictor) {
206 Entry entry = entries_[Key::FromEnums(preloading_type, predictor)];
207 return entry.holdback_;
208}
209
Simon Pelchatb2ce6df2023-07-26 21:48:37210void PreloadingConfig::SetHoldbackForTesting(PreloadingType preloading_type,
211 PreloadingPredictor predictor,
212 bool holdback) {
213 Entry entry;
214 entry.holdback_ = holdback;
215 entries_.emplace(
216 Key(PreloadingTypeToString(preloading_type), predictor.name()), entry);
217}
218
Md Hasibul Hasana963a9342024-04-03 10:15:14219void PreloadingConfig::SetHoldbackForTesting(std::string_view preloading_type,
220 std::string_view predictor,
Simon Pelchatb2ce6df2023-07-26 21:48:37221 bool holdback) {
222 Entry entry;
223 entry.holdback_ = holdback;
224 entries_.emplace(Key(preloading_type, predictor), entry);
225}
226
Simon Pelchat9ed3e992023-02-17 01:16:16227double PreloadingConfig::SamplingLikelihood(PreloadingType preloading_type,
228 PreloadingPredictor predictor) {
229 Entry entry = entries_[Key::FromEnums(preloading_type, predictor)];
230 return entry.sampling_likelihood_;
231}
232
Md Hasibul Hasana963a9342024-04-03 10:15:14233PreloadingConfig::Key::Key(std::string_view preloading_type,
234 std::string_view predictor)
Simon Pelchat9ed3e992023-02-17 01:16:16235 : preloading_type_(preloading_type), predictor_(predictor) {}
236
237PreloadingConfig::Key PreloadingConfig::Key::FromEnums(
238 PreloadingType preloading_type,
239 PreloadingPredictor predictor) {
240 return Key(PreloadingTypeToString(preloading_type), predictor.name());
241}
242
243PreloadingConfig::Entry PreloadingConfig::Entry::FromDict(
244 const base::Value::Dict* dict) {
245 Entry entry;
Arthur Sonzognic686e8f2024-01-11 08:36:37246 std::optional<bool> holdback = dict->FindBool("holdback");
Simon Pelchat9ed3e992023-02-17 01:16:16247 if (holdback) {
248 entry.holdback_ = *holdback;
249 }
Arthur Sonzognic686e8f2024-01-11 08:36:37250 std::optional<double> sampling_likelihood =
Simon Pelchat9ed3e992023-02-17 01:16:16251 dict->FindDouble("sampling_likelihood");
252 if (sampling_likelihood) {
253 entry.sampling_likelihood_ = *sampling_likelihood;
254 }
255 return entry;
256}
257
258bool PreloadingConfig::KeyCompare::operator()(
259 const PreloadingConfig::Key& lhs,
260 const PreloadingConfig::Key& rhs) const {
261 return std::tie(lhs.preloading_type_, lhs.predictor_) <
262 std::tie(rhs.preloading_type_, rhs.predictor_);
263}
264
265} // namespace content