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 |callback| on every override defined by |experiment|. |
| 64 void ApplyUIStringOverrides( |
| 65 const Study_Experiment& experiment, |
| 66 const VariationsSeedProcessor::UIStringOverrideCallback& callback) { |
| 67 for (int i = 0; i < experiment.override_ui_string_size(); ++i) { |
| 68 const Study_Experiment_OverrideUIString& override = |
| 69 experiment.override_ui_string(i); |
| 70 callback.Run(override.name_hash(), base::UTF8ToUTF16(override.value())); |
| 71 } |
| 72 } |
| 73 |
61 } // namespace | 74 } // namespace |
62 | 75 |
63 VariationsSeedProcessor::VariationsSeedProcessor() { | 76 VariationsSeedProcessor::VariationsSeedProcessor() { |
64 } | 77 } |
65 | 78 |
66 VariationsSeedProcessor::~VariationsSeedProcessor() { | 79 VariationsSeedProcessor::~VariationsSeedProcessor() { |
67 } | 80 } |
68 | 81 |
69 void VariationsSeedProcessor::CreateTrialsFromSeed( | 82 void VariationsSeedProcessor::CreateTrialsFromSeed( |
70 const VariationsSeed& seed, | 83 const VariationsSeed& seed, |
71 const std::string& locale, | 84 const std::string& locale, |
72 const base::Time& reference_date, | 85 const base::Time& reference_date, |
73 const base::Version& version, | 86 const base::Version& version, |
74 Study_Channel channel, | 87 Study_Channel channel, |
75 Study_FormFactor form_factor, | 88 Study_FormFactor form_factor, |
76 const std::string& hardware_class) { | 89 const std::string& hardware_class, |
| 90 const UIStringOverrideCallback& override_callback) { |
77 std::vector<ProcessedStudy> filtered_studies; | 91 std::vector<ProcessedStudy> filtered_studies; |
78 FilterAndValidateStudies(seed, locale, reference_date, version, channel, | 92 FilterAndValidateStudies(seed, locale, reference_date, version, channel, |
79 form_factor, hardware_class, &filtered_studies); | 93 form_factor, hardware_class, &filtered_studies); |
80 | 94 |
81 for (size_t i = 0; i < filtered_studies.size(); ++i) | 95 for (size_t i = 0; i < filtered_studies.size(); ++i) |
82 CreateTrialFromStudy(filtered_studies[i]); | 96 CreateTrialFromStudy(filtered_studies[i], override_callback); |
83 } | 97 } |
84 | 98 |
85 void VariationsSeedProcessor::CreateTrialFromStudy( | 99 void VariationsSeedProcessor::CreateTrialFromStudy( |
86 const ProcessedStudy& processed_study) { | 100 const ProcessedStudy& processed_study, |
| 101 const UIStringOverrideCallback& override_callback) { |
87 const Study& study = *processed_study.study(); | 102 const Study& study = *processed_study.study(); |
88 | 103 |
89 // Check if any experiments need to be forced due to a command line | 104 // Check if any experiments need to be forced due to a command line |
90 // flag. Force the first experiment with an existing flag. | 105 // flag. Force the first experiment with an existing flag. |
91 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 106 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
92 for (int i = 0; i < study.experiment_size(); ++i) { | 107 for (int i = 0; i < study.experiment_size(); ++i) { |
93 const Study_Experiment& experiment = study.experiment(i); | 108 const Study_Experiment& experiment = study.experiment(i); |
94 if (experiment.has_forcing_flag() && | 109 if (experiment.has_forcing_flag() && |
95 command_line->HasSwitch(experiment.forcing_flag())) { | 110 command_line->HasSwitch(experiment.forcing_flag())) { |
96 scoped_refptr<base::FieldTrial> trial( | 111 scoped_refptr<base::FieldTrial> trial( |
97 base::FieldTrialList::CreateFieldTrial(study.name(), | 112 base::FieldTrialList::CreateFieldTrial(study.name(), |
98 experiment.name())); | 113 experiment.name())); |
99 RegisterExperimentParams(study, experiment); | 114 RegisterExperimentParams(study, experiment); |
100 RegisterVariationIds(experiment, study.name()); | 115 RegisterVariationIds(experiment, study.name()); |
101 if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) | 116 if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) { |
102 trial->group(); | 117 trial->group(); |
| 118 // UI Strings can only be overridden from ACTIVATION_AUTO experiments. |
| 119 ApplyUIStringOverrides(experiment, override_callback); |
| 120 } |
103 | 121 |
104 DVLOG(1) << "Trial " << study.name() << " forced by flag: " | 122 DVLOG(1) << "Trial " << study.name() << " forced by flag: " |
105 << experiment.forcing_flag(); | 123 << experiment.forcing_flag(); |
106 return; | 124 return; |
107 } | 125 } |
108 } | 126 } |
109 | 127 |
110 uint32 randomization_seed = 0; | 128 uint32 randomization_seed = 0; |
111 base::FieldTrial::RandomizationType randomization_type = | 129 base::FieldTrial::RandomizationType randomization_type = |
112 base::FieldTrial::SESSION_RANDOMIZED; | 130 base::FieldTrial::SESSION_RANDOMIZED; |
113 if (study.has_consistency() && | 131 if (study.has_consistency() && |
114 study.consistency() == Study_Consistency_PERMANENT) { | 132 study.consistency() == Study_Consistency_PERMANENT) { |
115 randomization_type = base::FieldTrial::ONE_TIME_RANDOMIZED; | 133 randomization_type = base::FieldTrial::ONE_TIME_RANDOMIZED; |
116 if (study.has_randomization_seed()) | 134 if (study.has_randomization_seed()) |
117 randomization_seed = study.randomization_seed(); | 135 randomization_seed = study.randomization_seed(); |
118 } | 136 } |
119 | 137 |
120 // The trial is created without specifying an expiration date because the | 138 // 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, | 139 // expiration check in field_trial.cc is based on the build date. Instead, |
122 // the expiration check using |reference_date| is done explicitly below. | 140 // the expiration check using |reference_date| is done explicitly below. |
123 scoped_refptr<base::FieldTrial> trial( | 141 scoped_refptr<base::FieldTrial> trial( |
124 base::FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed( | 142 base::FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed( |
125 study.name(), processed_study.total_probability(), | 143 study.name(), processed_study.total_probability(), |
126 study.default_experiment_name(), | 144 study.default_experiment_name(), |
127 base::FieldTrialList::kNoExpirationYear, 1, 1, randomization_type, | 145 base::FieldTrialList::kNoExpirationYear, 1, 1, randomization_type, |
128 randomization_seed, NULL)); | 146 randomization_seed, NULL)); |
129 | 147 |
| 148 bool has_overrides = false; |
130 for (int i = 0; i < study.experiment_size(); ++i) { | 149 for (int i = 0; i < study.experiment_size(); ++i) { |
131 const Study_Experiment& experiment = study.experiment(i); | 150 const Study_Experiment& experiment = study.experiment(i); |
132 RegisterExperimentParams(study, experiment); | 151 RegisterExperimentParams(study, experiment); |
133 | 152 |
134 // Groups with forcing flags have probability 0 and will never be selected. | 153 // 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. | 154 // Therefore, there's no need to add them to the field trial. |
136 if (experiment.has_forcing_flag()) | 155 if (experiment.has_forcing_flag()) |
137 continue; | 156 continue; |
138 | 157 |
139 if (experiment.name() != study.default_experiment_name()) | 158 if (experiment.name() != study.default_experiment_name()) |
140 trial->AppendGroup(experiment.name(), experiment.probability_weight()); | 159 trial->AppendGroup(experiment.name(), experiment.probability_weight()); |
141 | 160 |
142 RegisterVariationIds(experiment, study.name()); | 161 RegisterVariationIds(experiment, study.name()); |
| 162 |
| 163 has_overrides = has_overrides || experiment.override_ui_string_size() > 0; |
143 } | 164 } |
144 | 165 |
145 trial->SetForced(); | 166 trial->SetForced(); |
146 if (processed_study.is_expired()) | 167 if (processed_study.is_expired()) { |
147 trial->Disable(); | 168 trial->Disable(); |
148 else if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) | 169 } else if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) { |
149 trial->group(); | 170 const std::string& group_name = trial->group_name(); |
| 171 |
| 172 // Don't try to apply overrides if none of the experiments in this study had |
| 173 // any. |
| 174 if (!has_overrides) |
| 175 return; |
| 176 |
| 177 // UI Strings can only be overridden from ACTIVATION_AUTO experiments. |
| 178 int experiment_index = processed_study.GetExperimentIndexByName(group_name); |
| 179 |
| 180 // The field trial was defined from |study|, so the active experiment's name |
| 181 // must be in the |study|. |
| 182 DCHECK_NE(-1, experiment_index); |
| 183 |
| 184 ApplyUIStringOverrides(study.experiment(experiment_index), |
| 185 override_callback); |
| 186 } |
150 } | 187 } |
151 | 188 |
152 } // namespace chrome_variations | 189 } // namespace chrome_variations |
OLD | NEW |