Roll src/third_party/WebKit 8b42d1d:744641d (svn 186770:186771)
[chromium-blink-merge.git] / chrome / browser / prerender / prerender_field_trial.cc
blob02ed0222a9c73bcb760f9243749b1d3e5fc8ffaf
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/prerender/prerender_field_trial.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_split.h"
14 #include "chrome/browser/net/prediction_options.h"
15 #include "chrome/browser/predictors/autocomplete_action_predictor.h"
16 #include "chrome/browser/prerender/prerender_manager.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/sync/profile_sync_service.h"
19 #include "chrome/browser/sync/profile_sync_service_factory.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/chrome_version_info.h"
22 #include "components/metrics/metrics_service.h"
23 #include "components/variations/variations_associated_data.h"
25 using base::FieldTrial;
26 using base::FieldTrialList;
27 using base::StringToInt;
28 using std::string;
29 using std::vector;
31 namespace prerender {
33 namespace {
35 const char kDisabledGroup[] = "Disabled";
36 const char kEnabledGroup[] = "Enabled";
38 const char kLocalPredictorSpecTrialName[] = "PrerenderLocalPredictorSpec";
39 const char kLocalPredictorKeyName[] = "LocalPredictor";
40 const char kLocalPredictorUnencryptedSyncOnlyKeyName[] =
41 "LocalPredictorUnencryptedSyncOnly";
42 const char kLocalPredictorNetworkPredictionEnabledOnly[] =
43 "LocalPredictorNetworkPredictionEnabledOnly";
44 const char kLocalPredictorOnCellularOnly[] = "LocalPredictorOnCellularOnly";
45 const char kSideEffectFreeWhitelistKeyName[] = "SideEffectFreeWhitelist";
46 const char kPrerenderLaunchKeyName[] = "PrerenderLaunch";
47 const char kPrerenderAlwaysControlKeyName[] = "PrerenderAlwaysControl";
48 const char kPrerenderPrefetchKeyName[] = "PrerenderPrefetch";
49 const char kPrerenderQueryPrerenderServiceKeyName[] =
50 "PrerenderQueryPrerenderService";
51 const char kPrerenderQueryPrerenderServiceCurrentURLKeyName[] =
52 "PrerenderQueryPrerenderServiceCurrentURL";
53 const char kPrerenderQueryPrerenderServiceCandidateURLsKeyName[] =
54 "PrerenderQueryPrerenderServiceCandidateURLs";
55 const char kPrerenderServiceBehaviorIDKeyName[] = "PrerenderServiceBehaviorID";
56 const char kPrerenderServiceFetchTimeoutKeyName[] =
57 "PrerenderServiceFetchTimeoutMs";
58 const char kPrefetchListTimeoutKeyName[] = "PrefetchListTimeoutSeconds";
59 const char kPrerenderTTLKeyName[] = "PrerenderTTLSeconds";
60 const char kPrerenderPriorityHalfLifeTimeKeyName[] =
61 "PrerenderPriorityHalfLifeTimeSeconds";
62 const char kMaxConcurrentPrerenderKeyName[] = "MaxConcurrentPrerenders";
63 const char kMaxLaunchPrerenderKeyName[] = "MaxLaunchPrerenders";
64 const char kSkipFragment[] = "SkipFragment";
65 const char kSkipHTTPS[] = "SkipHTTPS";
66 const char kSkipWhitelist[] = "SkipWhitelist";
67 const char kSkipServiceWhitelist[] = "SkipServiceWhitelist";
68 const char kSkipLoggedIn[] = "SkipLoggedIn";
69 const char kSkipDefaultNoPrerender[] = "SkipDefaultNoPrerender";
70 const char kPrerenderServiceURLPrefixParameterName[] =
71 "PrerenderServiceURLPrefix";
72 const char kDefaultPrerenderServiceURLPrefix[] =
73 "https://clients4.google.com/prerenderservice/?q=";
74 const int kMinPrerenderServiceTimeoutMs = 1;
75 const int kMaxPrerenderServiceTimeoutMs = 10000;
76 const int kDefaultPrerenderServiceTimeoutMs = 1000;
77 const int kMinPrefetchListTimeoutSeconds = 1;
78 const int kMaxPrefetchListTimeoutSeconds = 1800;
79 const int kDefaultPrefetchListTimeoutSeconds = 300;
80 const char kSkipPrerenderLocalCanadidates[] = "SkipPrerenderLocalCandidates";
81 const char kSkipPrerenderServiceCanadidates[] =
82 "SkipPrerenderServiceCandidates";
83 const char kDisableSessionStorageNamespaceMerging[] =
84 "DisableSessionStorageNamespaceMerging";
85 const char kPrerenderCookieStore[] = "PrerenderCookieStore";
87 void SetupPrerenderFieldTrial() {
88 const FieldTrial::Probability divisor = 1000;
90 FieldTrial::Probability control_probability;
91 FieldTrial::Probability experiment_multi_prerender_probability;
92 FieldTrial::Probability experiment_15min_ttl_probability;
93 FieldTrial::Probability experiment_no_use_probability;
94 FieldTrial::Probability experiment_match_complete_probability;
96 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
97 if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
98 channel == chrome::VersionInfo::CHANNEL_BETA) {
99 // Use very conservatives and stable settings in beta and stable.
100 const FieldTrial::Probability release_prerender_enabled_probability = 970;
101 const FieldTrial::Probability release_control_probability = 10;
102 const FieldTrial::Probability
103 release_experiment_multi_prerender_probability = 0;
104 const FieldTrial::Probability release_experiment_15min_ttl_probability = 10;
105 const FieldTrial::Probability release_experiment_no_use_probability = 0;
106 const FieldTrial::Probability
107 release_experiment_match_complete_probability = 10;
108 COMPILE_ASSERT(
109 release_prerender_enabled_probability +
110 release_control_probability +
111 release_experiment_multi_prerender_probability +
112 release_experiment_15min_ttl_probability +
113 release_experiment_no_use_probability +
114 release_experiment_match_complete_probability == divisor,
115 release_experiment_probabilities_must_equal_divisor);
117 control_probability = release_control_probability;
118 experiment_multi_prerender_probability =
119 release_experiment_multi_prerender_probability;
120 experiment_15min_ttl_probability = release_experiment_15min_ttl_probability;
121 experiment_no_use_probability = release_experiment_no_use_probability;
122 experiment_match_complete_probability =
123 release_experiment_match_complete_probability;
124 } else {
125 // In testing channels, use more experiments and a larger control group to
126 // improve quality of data.
127 const FieldTrial::Probability dev_prerender_enabled_probability = 200;
128 const FieldTrial::Probability dev_control_probability = 200;
129 const FieldTrial::Probability
130 dev_experiment_multi_prerender_probability = 200;
131 const FieldTrial::Probability dev_experiment_15min_ttl_probability = 100;
132 const FieldTrial::Probability dev_experiment_no_use_probability = 100;
133 const FieldTrial::Probability
134 dev_experiment_match_complete_probability = 200;
135 COMPILE_ASSERT(dev_prerender_enabled_probability +
136 dev_control_probability +
137 dev_experiment_multi_prerender_probability +
138 dev_experiment_15min_ttl_probability +
139 dev_experiment_no_use_probability +
140 dev_experiment_match_complete_probability == divisor,
141 dev_experiment_probabilities_must_equal_divisor);
143 control_probability = dev_control_probability;
144 experiment_multi_prerender_probability =
145 dev_experiment_multi_prerender_probability;
146 experiment_15min_ttl_probability = dev_experiment_15min_ttl_probability;
147 experiment_no_use_probability = dev_experiment_no_use_probability;
148 experiment_match_complete_probability =
149 dev_experiment_match_complete_probability;
152 int prerender_enabled_group = -1;
153 scoped_refptr<FieldTrial> trial(
154 FieldTrialList::FactoryGetFieldTrial(
155 "Prerender", divisor, "PrerenderEnabled",
156 2014, 12, 31, FieldTrial::SESSION_RANDOMIZED,
157 &prerender_enabled_group));
158 const int control_group =
159 trial->AppendGroup("PrerenderControl",
160 control_probability);
161 const int experiment_multi_prerender_group =
162 trial->AppendGroup("PrerenderMulti",
163 experiment_multi_prerender_probability);
164 const int experiment_15_min_TTL_group =
165 trial->AppendGroup("Prerender15minTTL",
166 experiment_15min_ttl_probability);
167 const int experiment_no_use_group =
168 trial->AppendGroup("PrerenderNoUse",
169 experiment_no_use_probability);
170 const int experiment_match_complete_group =
171 trial->AppendGroup("MatchComplete",
172 experiment_match_complete_probability);
174 const int trial_group = trial->group();
175 if (trial_group == prerender_enabled_group) {
176 PrerenderManager::SetMode(
177 PrerenderManager::PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP);
178 } else if (trial_group == control_group) {
179 PrerenderManager::SetMode(
180 PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
181 } else if (trial_group == experiment_multi_prerender_group) {
182 PrerenderManager::SetMode(
183 PrerenderManager::PRERENDER_MODE_EXPERIMENT_MULTI_PRERENDER_GROUP);
184 } else if (trial_group == experiment_15_min_TTL_group) {
185 PrerenderManager::SetMode(
186 PrerenderManager::PRERENDER_MODE_EXPERIMENT_15MIN_TTL_GROUP);
187 } else if (trial_group == experiment_no_use_group) {
188 PrerenderManager::SetMode(
189 PrerenderManager::PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP);
190 } else if (trial_group == experiment_match_complete_group) {
191 PrerenderManager::SetMode(
192 PrerenderManager::PRERENDER_MODE_EXPERIMENT_MATCH_COMPLETE_GROUP);
193 } else {
194 NOTREACHED();
198 } // end namespace
200 void ConfigurePrerender(const CommandLine& command_line) {
201 enum PrerenderOption {
202 PRERENDER_OPTION_AUTO,
203 PRERENDER_OPTION_DISABLED,
204 PRERENDER_OPTION_ENABLED,
207 PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
208 if (command_line.HasSwitch(switches::kPrerenderMode)) {
209 const string switch_value =
210 command_line.GetSwitchValueASCII(switches::kPrerenderMode);
212 if (switch_value == switches::kPrerenderModeSwitchValueAuto) {
213 prerender_option = PRERENDER_OPTION_AUTO;
214 } else if (switch_value == switches::kPrerenderModeSwitchValueDisabled) {
215 prerender_option = PRERENDER_OPTION_DISABLED;
216 } else if (switch_value.empty() ||
217 switch_value == switches::kPrerenderModeSwitchValueEnabled) {
218 // The empty string means the option was provided with no value, and that
219 // means enable.
220 prerender_option = PRERENDER_OPTION_ENABLED;
221 } else {
222 prerender_option = PRERENDER_OPTION_DISABLED;
223 LOG(ERROR) << "Invalid --prerender option received on command line: "
224 << switch_value;
225 LOG(ERROR) << "Disabling prerendering!";
229 switch (prerender_option) {
230 case PRERENDER_OPTION_AUTO:
231 SetupPrerenderFieldTrial();
232 break;
233 case PRERENDER_OPTION_DISABLED:
234 PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
235 break;
236 case PRERENDER_OPTION_ENABLED:
237 PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
238 break;
239 default:
240 NOTREACHED();
244 bool IsOmniboxEnabled(Profile* profile) {
245 if (!profile)
246 return false;
248 if (!PrerenderManager::IsPrerenderingPossible())
249 return false;
251 // Override any field trial groups if the user has set a command line flag.
252 if (CommandLine::ForCurrentProcess()->HasSwitch(
253 switches::kPrerenderFromOmnibox)) {
254 const string switch_value =
255 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
256 switches::kPrerenderFromOmnibox);
258 if (switch_value == switches::kPrerenderFromOmniboxSwitchValueEnabled)
259 return true;
261 if (switch_value == switches::kPrerenderFromOmniboxSwitchValueDisabled)
262 return false;
264 DCHECK_EQ(switches::kPrerenderFromOmniboxSwitchValueAuto, switch_value);
267 return (FieldTrialList::FindFullName("PrerenderFromOmnibox") !=
268 "OmniboxPrerenderDisabled");
272 PrerenderLocalPredictorSpec is a field trial, and its value must have the
273 following format:
274 key1=value1:key2=value2:key3=value3
275 eg "LocalPredictor=Enabled:SideEffectFreeWhitelist=Enabled"
276 The function below extracts the value corresponding to a key provided from the
277 LocalPredictorSpec.
279 string GetLocalPredictorSpecValue(string spec_key) {
280 vector<string> elements;
281 base::SplitString(FieldTrialList::FindFullName(kLocalPredictorSpecTrialName),
282 ':', &elements);
283 for (int i = 0; i < static_cast<int>(elements.size()); i++) {
284 vector<string> key_value;
285 base::SplitString(elements[i], '=', &key_value);
286 if (key_value.size() == 2 && key_value[0] == spec_key)
287 return key_value[1];
289 return string();
292 bool IsUnencryptedSyncEnabled(Profile* profile) {
293 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()->
294 GetForProfile(profile);
295 return service && service->GetOpenTabsUIDelegate() &&
296 !service->EncryptEverythingEnabled();
299 // Indicates whether the Local Predictor is enabled based on field trial
300 // selection.
301 bool IsLocalPredictorEnabled() {
302 #if defined(OS_ANDROID) || defined(OS_IOS)
303 return false;
304 #endif
305 return
306 !CommandLine::ForCurrentProcess()->HasSwitch(
307 switches::kDisablePrerenderLocalPredictor) &&
308 GetLocalPredictorSpecValue(kLocalPredictorKeyName) == kEnabledGroup;
311 bool ShouldDisableLocalPredictorBasedOnSyncAndConfiguration(Profile* profile) {
312 return
313 GetLocalPredictorSpecValue(kLocalPredictorUnencryptedSyncOnlyKeyName) ==
314 kEnabledGroup &&
315 !IsUnencryptedSyncEnabled(profile);
318 bool ShouldDisableLocalPredictorDueToPreferencesAndNetwork(Profile* profile) {
319 bool on_cellular =
320 net::NetworkChangeNotifier::IsConnectionCellular(
321 net::NetworkChangeNotifier::GetConnectionType());
322 // If the user is not on a cellular connection, but we require a cellular
323 // connection, we must temporarily disable our local predictions.
324 if (!on_cellular &&
325 GetLocalPredictorSpecValue(kLocalPredictorOnCellularOnly) ==
326 kEnabledGroup) {
327 return true;
330 // If we don't care whether or not network prediction will actually be
331 // exercised, we do not need to temporarily disable our predictions.
332 if (GetLocalPredictorSpecValue(kLocalPredictorNetworkPredictionEnabledOnly) !=
333 kEnabledGroup) {
334 return false;
337 // We should temporarily disable iff the predictive network action would
338 // not be exercised.
340 return !chrome_browser_net::CanPrefetchAndPrerenderUI(profile->GetPrefs());
343 bool IsLoggedInPredictorEnabled() {
344 return IsLocalPredictorEnabled();
347 bool IsSideEffectFreeWhitelistEnabled() {
348 return IsLocalPredictorEnabled() &&
349 GetLocalPredictorSpecValue(kSideEffectFreeWhitelistKeyName) !=
350 kDisabledGroup;
353 bool IsLocalPredictorPrerenderLaunchEnabled() {
354 return GetLocalPredictorSpecValue(kPrerenderLaunchKeyName) != kDisabledGroup;
357 bool IsLocalPredictorPrerenderAlwaysControlEnabled() {
358 // If we prefetch rather than prerender, we automatically also prerender
359 // as a control group only.
360 return (GetLocalPredictorSpecValue(kPrerenderAlwaysControlKeyName) ==
361 kEnabledGroup) || IsLocalPredictorPrerenderPrefetchEnabled();
364 bool IsLocalPredictorPrerenderPrefetchEnabled() {
365 return GetLocalPredictorSpecValue(kPrerenderPrefetchKeyName) ==
366 kEnabledGroup;
369 bool ShouldQueryPrerenderService(Profile* profile) {
370 return IsUnencryptedSyncEnabled(profile) &&
371 GetLocalPredictorSpecValue(kPrerenderQueryPrerenderServiceKeyName) ==
372 kEnabledGroup;
375 bool ShouldQueryPrerenderServiceForCurrentURL() {
376 return GetLocalPredictorSpecValue(
377 kPrerenderQueryPrerenderServiceCurrentURLKeyName) != kDisabledGroup;
380 bool ShouldQueryPrerenderServiceForCandidateURLs() {
381 return GetLocalPredictorSpecValue(
382 kPrerenderQueryPrerenderServiceCandidateURLsKeyName) != kDisabledGroup;
385 string GetPrerenderServiceURLPrefix() {
386 string prefix = variations::GetVariationParamValue(
387 kLocalPredictorSpecTrialName,
388 kPrerenderServiceURLPrefixParameterName);
389 return prefix.empty() ? kDefaultPrerenderServiceURLPrefix : prefix;
392 int GetPrerenderServiceBehaviorID() {
393 int id;
394 StringToInt(GetLocalPredictorSpecValue(kPrerenderServiceBehaviorIDKeyName),
395 &id);
396 // The behavior ID must be non-negative.
397 return std::max(id, 0);
400 int GetPrerenderServiceFetchTimeoutMs() {
401 int result;
402 StringToInt(GetLocalPredictorSpecValue(kPrerenderServiceFetchTimeoutKeyName),
403 &result);
404 // If the value is outside the valid range, use the default value.
405 return (result < kMinPrerenderServiceTimeoutMs ||
406 result > kMaxPrerenderServiceTimeoutMs) ?
407 kDefaultPrerenderServiceTimeoutMs : result;
410 int GetPrerenderPrefetchListTimeoutSeconds() {
411 int result;
412 StringToInt(GetLocalPredictorSpecValue(kPrefetchListTimeoutKeyName), &result);
413 // If the value is outside the valid range, use the default value.
414 return (result < kMinPrefetchListTimeoutSeconds ||
415 result > kMaxPrefetchListTimeoutSeconds) ?
416 kDefaultPrefetchListTimeoutSeconds : result;
419 int GetLocalPredictorTTLSeconds() {
420 int ttl;
421 StringToInt(GetLocalPredictorSpecValue(kPrerenderTTLKeyName), &ttl);
422 // If the value is outside of 10s or 600s, use a default value of 180s.
423 return (ttl < 10 || ttl > 600) ? 180 : ttl;
426 int GetLocalPredictorPrerenderPriorityHalfLifeTimeSeconds() {
427 int half_life_time;
428 StringToInt(GetLocalPredictorSpecValue(kPrerenderPriorityHalfLifeTimeKeyName),
429 &half_life_time);
430 // Sanity check: Ensure the half life time is non-negative.
431 return std::max(half_life_time, 0);
434 int GetLocalPredictorMaxConcurrentPrerenders() {
435 int num_prerenders;
436 StringToInt(GetLocalPredictorSpecValue(kMaxConcurrentPrerenderKeyName),
437 &num_prerenders);
438 // Sanity check: Ensure the number of prerenders is between 1 and 10.
439 return std::min(std::max(num_prerenders, 1), 10);
442 int GetLocalPredictorMaxLaunchPrerenders() {
443 int num_prerenders;
444 StringToInt(GetLocalPredictorSpecValue(kMaxLaunchPrerenderKeyName),
445 &num_prerenders);
446 // Sanity check: Ensure the number of prerenders is between 1 and 10.
447 return std::min(std::max(num_prerenders, 1), 10);
450 bool SkipLocalPredictorFragment() {
451 return GetLocalPredictorSpecValue(kSkipFragment) == kEnabledGroup;
454 bool SkipLocalPredictorHTTPS() {
455 return GetLocalPredictorSpecValue(kSkipHTTPS) == kEnabledGroup;
458 bool SkipLocalPredictorWhitelist() {
459 return GetLocalPredictorSpecValue(kSkipWhitelist) == kEnabledGroup;
462 bool SkipLocalPredictorServiceWhitelist() {
463 return GetLocalPredictorSpecValue(kSkipServiceWhitelist) == kEnabledGroup;
466 bool SkipLocalPredictorLoggedIn() {
467 return GetLocalPredictorSpecValue(kSkipLoggedIn) == kEnabledGroup;
470 bool SkipLocalPredictorDefaultNoPrerender() {
471 return GetLocalPredictorSpecValue(kSkipDefaultNoPrerender) == kEnabledGroup;
474 bool SkipLocalPredictorLocalCandidates() {
475 return GetLocalPredictorSpecValue(kSkipPrerenderLocalCanadidates) ==
476 kEnabledGroup;
479 bool SkipLocalPredictorServiceCandidates() {
480 return GetLocalPredictorSpecValue(kSkipPrerenderServiceCanadidates) ==
481 kEnabledGroup;
484 bool ShouldMergeSessionStorageNamespaces() {
485 return GetLocalPredictorSpecValue(kDisableSessionStorageNamespaceMerging) !=
486 kDisabledGroup;
489 bool IsPrerenderCookieStoreEnabled() {
490 return GetLocalPredictorSpecValue(kPrerenderCookieStore) != kDisabledGroup &&
491 FieldTrialList::FindFullName(kPrerenderCookieStore) != kDisabledGroup;
494 } // namespace prerender