// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/omnibox/omnibox_field_trial.h" #include #include "base/metrics/field_trial.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "chrome/common/metrics/metrics_util.h" #include "chrome/common/metrics/variations/variation_ids.h" #include "chrome/common/metrics/variations/variations_util.h" namespace { // Field trial names. const char kDisallowInlineHQPFieldTrialName[] = "OmniboxDisallowInlineHQP"; const char kHUPCullRedirectsFieldTrialName[] = "OmniboxHUPCullRedirects"; const char kHUPCreateShorterMatchFieldTrialName[] = "OmniboxHUPCreateShorterMatch"; const char kStopTimerFieldTrialName[] = "OmniboxStopTimer"; const char kShortcutsScoringFieldTrialName[] = "OmniboxShortcutsScoring"; // The autocomplete dynamic field trial name prefix. Each field trial is // configured dynamically and is retrieved automatically by Chrome during // the startup. const char kAutocompleteDynamicFieldTrialPrefix[] = "AutocompleteDynamicTrial_"; // The maximum number of the autocomplete dynamic field trials (aka layers). const int kMaxAutocompleteDynamicFieldTrials = 5; // Field trial experiment probabilities. // For inline History Quick Provider field trial, put 0% ( = 0/100 ) // of the users in the disallow-inline experiment group. const base::FieldTrial::Probability kDisallowInlineHQPFieldTrialDivisor = 100; const base::FieldTrial::Probability kDisallowInlineHQPFieldTrialExperimentFraction = 0; // For HistoryURL provider cull redirects field trial, put 0% ( = 0/100 ) // of the users in the don't-cull-redirects experiment group. // TODO(mpearson): Remove this field trial and the code it uses once I'm // sure it's no longer needed. const base::FieldTrial::Probability kHUPCullRedirectsFieldTrialDivisor = 100; const base::FieldTrial::Probability kHUPCullRedirectsFieldTrialExperimentFraction = 0; // For HistoryURL provider create shorter match field trial, put 0% // ( = 25/100 ) of the users in the don't-create-a-shorter-match // experiment group. // TODO(mpearson): Remove this field trial and the code it uses once I'm // sure it's no longer needed. const base::FieldTrial::Probability kHUPCreateShorterMatchFieldTrialDivisor = 100; const base::FieldTrial::Probability kHUPCreateShorterMatchFieldTrialExperimentFraction = 0; // Experiment group names. const char kStopTimerExperimentGroupName[] = "UseStopTimer"; // Field trial IDs. // Though they are not literally "const", they are set only once, in // ActivateStaticTrials() below. // Whether the static field trials have been initialized by // ActivateStaticTrials() method. bool static_field_trials_initialized = false; // Field trial ID for the disallow-inline History Quick Provider // experiment group. int disallow_inline_hqp_experiment_group = 0; // Field trial ID for the HistoryURL provider cull redirects experiment group. int hup_dont_cull_redirects_experiment_group = 0; // Field trial ID for the HistoryURL provider create shorter match // experiment group. int hup_dont_create_shorter_match_experiment_group = 0; // Concatenates the autocomplete dynamic field trial prefix with a field trial // ID to form a complete autocomplete field trial name. std::string DynamicFieldTrialName(int id) { return base::StringPrintf("%s%d", kAutocompleteDynamicFieldTrialPrefix, id); } } // namespace void OmniboxFieldTrial::ActivateStaticTrials() { DCHECK(!static_field_trials_initialized); // Create inline History Quick Provider field trial. // Make it expire on November 8, 2012. scoped_refptr trial( base::FieldTrialList::FactoryGetFieldTrial( kDisallowInlineHQPFieldTrialName, kDisallowInlineHQPFieldTrialDivisor, "Standard", 2012, 11, 8, NULL)); // Because users tend to use omnibox without attention to it--habits // get ingrained, users tend to learn that a particular suggestion is // at a particular spot in the drop-down--we're going to make these // field trials sticky. We want users to stay in them once assigned // so they have a better experience and also so we don't get weird // effects as omnibox ranking keeps changing and users learn they can't // trust the omnibox. trial->UseOneTimeRandomization(); disallow_inline_hqp_experiment_group = trial->AppendGroup("DisallowInline", kDisallowInlineHQPFieldTrialExperimentFraction); // Create the HistoryURL provider cull redirects field trial. // Make it expire on March 1, 2013. trial = base::FieldTrialList::FactoryGetFieldTrial( kHUPCullRedirectsFieldTrialName, kHUPCullRedirectsFieldTrialDivisor, "Standard", 2013, 3, 1, NULL); trial->UseOneTimeRandomization(); hup_dont_cull_redirects_experiment_group = trial->AppendGroup("DontCullRedirects", kHUPCullRedirectsFieldTrialExperimentFraction); // Create the HistoryURL provider create shorter match field trial. // Make it expire on March 1, 2013. trial = base::FieldTrialList::FactoryGetFieldTrial( kHUPCreateShorterMatchFieldTrialName, kHUPCreateShorterMatchFieldTrialDivisor, "Standard", 2013, 3, 1, NULL); trial->UseOneTimeRandomization(); hup_dont_create_shorter_match_experiment_group = trial->AppendGroup("DontCreateShorterMatch", kHUPCreateShorterMatchFieldTrialExperimentFraction); static_field_trials_initialized = true; } void OmniboxFieldTrial::ActivateDynamicTrials() { // Initialize all autocomplete dynamic field trials. This method may be // called multiple times. for (int i = 0; i < kMaxAutocompleteDynamicFieldTrials; ++i) base::FieldTrialList::FindValue(DynamicFieldTrialName(i)); } int OmniboxFieldTrial::GetDisabledProviderTypes() { // Make sure that Autocomplete dynamic field trials are activated. It's OK to // call this method multiple times. ActivateDynamicTrials(); // Look for group names in form of "DisabledProviders_" where "mask" // is a bitmap of disabled provider types (AutocompleteProvider::Type). int provider_types = 0; for (int i = 0; i < kMaxAutocompleteDynamicFieldTrials; ++i) { std::string group_name = base::FieldTrialList::FindFullName( DynamicFieldTrialName(i)); const char kDisabledProviders[] = "DisabledProviders_"; if (!StartsWithASCII(group_name, kDisabledProviders, true)) continue; int types = 0; if (!base::StringToInt(base::StringPiece( group_name.substr(strlen(kDisabledProviders))), &types)) { LOG(WARNING) << "Malformed DisabledProviders string: " << group_name; continue; } if (types == 0) LOG(WARNING) << "Expecting a non-zero bitmap; group = " << group_name; else provider_types |= types; } return provider_types; } bool OmniboxFieldTrial::InDisallowInlineHQPFieldTrial() { return base::FieldTrialList::TrialExists(kDisallowInlineHQPFieldTrialName); } bool OmniboxFieldTrial::InDisallowInlineHQPFieldTrialExperimentGroup() { if (!base::FieldTrialList::TrialExists(kDisallowInlineHQPFieldTrialName)) return false; // Return true if we're in the experiment group. const int group = base::FieldTrialList::FindValue( kDisallowInlineHQPFieldTrialName); return group == disallow_inline_hqp_experiment_group; } void OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes( std::vector* field_trial_hashes) { field_trial_hashes->clear(); for (int i = 0; i < kMaxAutocompleteDynamicFieldTrials; ++i) { const std::string& trial_name = DynamicFieldTrialName(i); if (base::FieldTrialList::TrialExists(trial_name)) field_trial_hashes->push_back(metrics::HashName(trial_name)); } } bool OmniboxFieldTrial::InHUPCullRedirectsFieldTrial() { return base::FieldTrialList::TrialExists(kHUPCullRedirectsFieldTrialName); } bool OmniboxFieldTrial::InHUPCullRedirectsFieldTrialExperimentGroup() { if (!base::FieldTrialList::TrialExists(kHUPCullRedirectsFieldTrialName)) return false; // Return true if we're in the experiment group. const int group = base::FieldTrialList::FindValue( kHUPCullRedirectsFieldTrialName); return group == hup_dont_cull_redirects_experiment_group; } bool OmniboxFieldTrial::InHUPCreateShorterMatchFieldTrial() { return base::FieldTrialList::TrialExists(kHUPCreateShorterMatchFieldTrialName); } bool OmniboxFieldTrial::InHUPCreateShorterMatchFieldTrialExperimentGroup() { if (!base::FieldTrialList::TrialExists(kHUPCreateShorterMatchFieldTrialName)) return false; // Return true if we're in the experiment group. const int group = base::FieldTrialList::FindValue( kHUPCreateShorterMatchFieldTrialName); return group == hup_dont_create_shorter_match_experiment_group; } bool OmniboxFieldTrial::InStopTimerFieldTrialExperimentGroup() { return (base::FieldTrialList::FindFullName(kStopTimerFieldTrialName) == kStopTimerExperimentGroupName); } bool OmniboxFieldTrial::InZeroSuggestFieldTrial() { // Make sure that Autocomplete dynamic field trials are activated. It's OK to // call this method multiple times. ActivateDynamicTrials(); // Look for group names starting with "EnableZeroSuggest" for (int i = 0; i < kMaxAutocompleteDynamicFieldTrials; ++i) { const std::string& group_name = base::FieldTrialList::FindFullName( DynamicFieldTrialName(i)); const char kEnableZeroSuggest[] = "EnableZeroSuggest"; if (StartsWithASCII(group_name, kEnableZeroSuggest, true)) return true; } return false; } // If the active group name starts with "MaxRelevance_", extract the // int that immediately following that, returning true on success. bool OmniboxFieldTrial::ShortcutsScoringMaxRelevance(int* max_relevance) { std::string group_name = base::FieldTrialList::FindFullName(kShortcutsScoringFieldTrialName); const char kMaxRelevanceGroupPrefix[] = "MaxRelevance_"; if (!StartsWithASCII(group_name, kMaxRelevanceGroupPrefix, true)) return false; if (!base::StringToInt(base::StringPiece( group_name.substr(strlen(kMaxRelevanceGroupPrefix))), max_relevance)) { LOG(WARNING) << "Malformed MaxRelevance string: " << group_name; return false; } return true; }