Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/variations/variations_seed_processor.h" | 5 #include "components/variations/variations_seed_processor.h" |
| 6 | 6 |
| 7 #include <map> | |
| 7 #include <vector> | 8 #include <vector> |
| 8 | 9 |
| 9 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 10 #include "base/metrics/field_trial.h" | 11 #include "base/metrics/field_trial.h" |
| 12 #include "base/strings/utf_string_conversions.h" | |
| 11 #include "components/variations/processed_study.h" | 13 #include "components/variations/processed_study.h" |
| 12 #include "components/variations/study_filtering.h" | 14 #include "components/variations/study_filtering.h" |
| 13 #include "components/variations/variations_associated_data.h" | 15 #include "components/variations/variations_associated_data.h" |
| 14 | 16 |
| 15 namespace chrome_variations { | 17 namespace chrome_variations { |
| 16 | 18 |
| 17 namespace { | 19 namespace { |
| 18 | 20 |
| 19 // Associates the variations params of |experiment|, if present. | 21 // Associates the variations params of |experiment|, if present. |
| 20 void RegisterExperimentParams(const Study& study, | 22 void RegisterExperimentParams(const Study& study, |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 51 if (experiment.has_google_update_experiment_id()) { | 53 if (experiment.has_google_update_experiment_id()) { |
| 52 const VariationID variation_id = | 54 const VariationID variation_id = |
| 53 static_cast<VariationID>(experiment.google_update_experiment_id()); | 55 static_cast<VariationID>(experiment.google_update_experiment_id()); |
| 54 AssociateGoogleVariationIDForce(GOOGLE_UPDATE_SERVICE, | 56 AssociateGoogleVariationIDForce(GOOGLE_UPDATE_SERVICE, |
| 55 trial_name, | 57 trial_name, |
| 56 experiment.name(), | 58 experiment.name(), |
| 57 variation_id); | 59 variation_id); |
| 58 } | 60 } |
| 59 } | 61 } |
| 60 | 62 |
| 63 // Executes |override_string| on every override defined by |experiment|. | |
| 64 void ApplyUIStringOverrides( | |
| 65 const Study_Experiment& experiment, | |
| 66 const VariationsSeedProcessor::UIStringOverrideCallback& override_string) { | |
|
Alexei Svitkine (slow)
2014/07/15 16:44:52
Nit: Maybe clearer to rename this |override_callba
jwd
2014/07/16 21:33:05
Done.
| |
| 67 for (int i = 0; i < experiment.override_ui_string_size(); ++i) { | |
| 68 Study_Experiment_OverrideUIString experiment_overrides = | |
|
Alexei Svitkine (slow)
2014/07/15 16:44:52
Nit: const ref, to avoid copying - also this is a
jwd
2014/07/16 21:33:05
Done.
| |
| 69 experiment.override_ui_string(i); | |
| 70 override_string.Run(experiment_overrides.name_hash(), | |
| 71 base::UTF8ToUTF16(experiment_overrides.value())); | |
| 72 } | |
| 73 } | |
| 74 | |
| 61 } // namespace | 75 } // namespace |
| 62 | 76 |
| 63 VariationsSeedProcessor::VariationsSeedProcessor() { | 77 VariationsSeedProcessor::VariationsSeedProcessor() { |
| 64 } | 78 } |
| 65 | 79 |
| 66 VariationsSeedProcessor::~VariationsSeedProcessor() { | 80 VariationsSeedProcessor::~VariationsSeedProcessor() { |
| 67 } | 81 } |
| 68 | 82 |
| 69 void VariationsSeedProcessor::CreateTrialsFromSeed( | 83 void VariationsSeedProcessor::CreateTrialsFromSeed( |
| 70 const VariationsSeed& seed, | 84 const VariationsSeed& seed, |
| 71 const std::string& locale, | 85 const std::string& locale, |
| 72 const base::Time& reference_date, | 86 const base::Time& reference_date, |
| 73 const base::Version& version, | 87 const base::Version& version, |
| 74 Study_Channel channel, | 88 Study_Channel channel, |
| 75 Study_FormFactor form_factor, | 89 Study_FormFactor form_factor, |
| 76 const std::string& hardware_class) { | 90 const std::string& hardware_class, |
| 91 const UIStringOverrideCallback& override_string) { | |
| 77 std::vector<ProcessedStudy> filtered_studies; | 92 std::vector<ProcessedStudy> filtered_studies; |
| 78 FilterAndValidateStudies(seed, locale, reference_date, version, channel, | 93 FilterAndValidateStudies(seed, locale, reference_date, version, channel, |
| 79 form_factor, hardware_class, &filtered_studies); | 94 form_factor, hardware_class, &filtered_studies); |
| 80 | 95 |
| 81 for (size_t i = 0; i < filtered_studies.size(); ++i) | 96 for (size_t i = 0; i < filtered_studies.size(); ++i) |
| 82 CreateTrialFromStudy(filtered_studies[i]); | 97 CreateTrialFromStudy(filtered_studies[i], override_string); |
| 83 } | 98 } |
| 84 | 99 |
| 85 void VariationsSeedProcessor::CreateTrialFromStudy( | 100 void VariationsSeedProcessor::CreateTrialFromStudy( |
| 86 const ProcessedStudy& processed_study) { | 101 const ProcessedStudy& processed_study, |
| 102 const UIStringOverrideCallback& override_string) { | |
| 87 const Study& study = *processed_study.study(); | 103 const Study& study = *processed_study.study(); |
| 88 | 104 |
| 89 // Check if any experiments need to be forced due to a command line | 105 // Check if any experiments need to be forced due to a command line |
| 90 // flag. Force the first experiment with an existing flag. | 106 // flag. Force the first experiment with an existing flag. |
| 91 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 107 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 92 for (int i = 0; i < study.experiment_size(); ++i) { | 108 for (int i = 0; i < study.experiment_size(); ++i) { |
| 93 const Study_Experiment& experiment = study.experiment(i); | 109 const Study_Experiment& experiment = study.experiment(i); |
| 94 if (experiment.has_forcing_flag() && | 110 if (experiment.has_forcing_flag() && |
| 95 command_line->HasSwitch(experiment.forcing_flag())) { | 111 command_line->HasSwitch(experiment.forcing_flag())) { |
| 96 scoped_refptr<base::FieldTrial> trial( | 112 scoped_refptr<base::FieldTrial> trial( |
| 97 base::FieldTrialList::CreateFieldTrial(study.name(), | 113 base::FieldTrialList::CreateFieldTrial(study.name(), |
| 98 experiment.name())); | 114 experiment.name())); |
| 99 RegisterExperimentParams(study, experiment); | 115 RegisterExperimentParams(study, experiment); |
| 100 RegisterVariationIds(experiment, study.name()); | 116 RegisterVariationIds(experiment, study.name()); |
| 101 if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) | 117 if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) { |
| 102 trial->group(); | 118 trial->group(); |
| 119 // UI Strings can only be overridden from ACTIVATION_AUTO experiments. | |
| 120 ApplyUIStringOverrides(experiment, override_string); | |
| 121 } | |
| 103 | 122 |
| 104 DVLOG(1) << "Trial " << study.name() << " forced by flag: " | 123 DVLOG(1) << "Trial " << study.name() << " forced by flag: " |
| 105 << experiment.forcing_flag(); | 124 << experiment.forcing_flag(); |
| 106 return; | 125 return; |
| 107 } | 126 } |
| 108 } | 127 } |
| 109 | 128 |
| 110 uint32 randomization_seed = 0; | 129 uint32 randomization_seed = 0; |
| 111 base::FieldTrial::RandomizationType randomization_type = | 130 base::FieldTrial::RandomizationType randomization_type = |
| 112 base::FieldTrial::SESSION_RANDOMIZED; | 131 base::FieldTrial::SESSION_RANDOMIZED; |
| 113 if (study.has_consistency() && | 132 if (study.has_consistency() && |
| 114 study.consistency() == Study_Consistency_PERMANENT) { | 133 study.consistency() == Study_Consistency_PERMANENT) { |
| 115 randomization_type = base::FieldTrial::ONE_TIME_RANDOMIZED; | 134 randomization_type = base::FieldTrial::ONE_TIME_RANDOMIZED; |
| 116 if (study.has_randomization_seed()) | 135 if (study.has_randomization_seed()) |
| 117 randomization_seed = study.randomization_seed(); | 136 randomization_seed = study.randomization_seed(); |
| 118 } | 137 } |
| 119 | 138 |
| 120 // The trial is created without specifying an expiration date because the | 139 // The trial is created without specifying an expiration date because the |
| 121 // expiration check in field_trial.cc is based on the build date. Instead, | 140 // expiration check in field_trial.cc is based on the build date. Instead, |
| 122 // the expiration check using |reference_date| is done explicitly below. | 141 // the expiration check using |reference_date| is done explicitly below. |
| 123 scoped_refptr<base::FieldTrial> trial( | 142 scoped_refptr<base::FieldTrial> trial( |
| 124 base::FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed( | 143 base::FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed( |
| 125 study.name(), processed_study.total_probability(), | 144 study.name(), processed_study.total_probability(), |
| 126 study.default_experiment_name(), | 145 study.default_experiment_name(), |
| 127 base::FieldTrialList::kNoExpirationYear, 1, 1, randomization_type, | 146 base::FieldTrialList::kNoExpirationYear, 1, 1, randomization_type, |
| 128 randomization_seed, NULL)); | 147 randomization_seed, NULL)); |
| 129 | 148 |
| 149 bool hasOverrides = false; | |
|
Alexei Svitkine (slow)
2014/07/15 16:44:52
Nit: has_overrides
jwd
2014/07/16 21:33:05
Done.
| |
| 130 for (int i = 0; i < study.experiment_size(); ++i) { | 150 for (int i = 0; i < study.experiment_size(); ++i) { |
| 131 const Study_Experiment& experiment = study.experiment(i); | 151 const Study_Experiment& experiment = study.experiment(i); |
| 132 RegisterExperimentParams(study, experiment); | 152 RegisterExperimentParams(study, experiment); |
| 133 | 153 |
| 134 // Groups with forcing flags have probability 0 and will never be selected. | 154 // Groups with forcing flags have probability 0 and will never be selected. |
| 135 // Therefore, there's no need to add them to the field trial. | 155 // Therefore, there's no need to add them to the field trial. |
| 136 if (experiment.has_forcing_flag()) | 156 if (experiment.has_forcing_flag()) |
| 137 continue; | 157 continue; |
| 138 | 158 |
| 139 if (experiment.name() != study.default_experiment_name()) | 159 if (experiment.name() != study.default_experiment_name()) |
| 140 trial->AppendGroup(experiment.name(), experiment.probability_weight()); | 160 trial->AppendGroup(experiment.name(), experiment.probability_weight()); |
| 141 | 161 |
| 142 RegisterVariationIds(experiment, study.name()); | 162 RegisterVariationIds(experiment, study.name()); |
| 163 | |
| 164 hasOverrides = hasOverrides || experiment.override_ui_string_size() > 0; | |
| 143 } | 165 } |
| 144 | 166 |
| 145 trial->SetForced(); | 167 trial->SetForced(); |
| 146 if (processed_study.is_expired()) | 168 if (processed_study.is_expired()) { |
| 147 trial->Disable(); | 169 trial->Disable(); |
| 148 else if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) | 170 } else if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) { |
| 149 trial->group(); | 171 const std::string& group_name = trial->group_name(); |
| 172 | |
| 173 // Don't try to apply overrides if none of the experiments in this study had | |
| 174 // any. | |
| 175 if (!hasOverrides) | |
| 176 return; | |
| 177 | |
| 178 // UI Strings can only be overridden from ACTIVATION_AUTO experiments. | |
| 179 int experiment_index = processed_study.GetExperimentIndexByName(group_name); | |
| 180 | |
| 181 // The field trial was defined from |study|, so the active experiment's name | |
| 182 // must be in the |study|. | |
| 183 DCHECK_NE(experiment_index, -1); | |
|
Alexei Svitkine (slow)
2014/07/15 16:44:52
Nit: Swap params.
jwd
2014/07/16 21:33:05
Done.
| |
| 184 | |
| 185 ApplyUIStringOverrides(study.experiment(experiment_index), override_string); | |
| 186 } | |
| 150 } | 187 } |
| 151 | 188 |
| 152 } // namespace chrome_variations | 189 } // namespace chrome_variations |
| OLD | NEW |