| 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 <map> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/metrics/field_trial.h" | 12 #include "base/metrics/field_trial.h" |
| 13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 14 #include "base/version.h" | 14 #include "base/version.h" |
| 15 #include "components/variations/processed_study.h" |
| 15 #include "components/variations/variations_associated_data.h" | 16 #include "components/variations/variations_associated_data.h" |
| 16 | 17 |
| 17 namespace chrome_variations { | 18 namespace chrome_variations { |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| 21 Study_Platform GetCurrentPlatform() { | 22 Study_Platform GetCurrentPlatform() { |
| 22 #if defined(OS_WIN) | 23 #if defined(OS_WIN) |
| 23 return Study_Platform_PLATFORM_WINDOWS; | 24 return Study_Platform_PLATFORM_WINDOWS; |
| 24 #elif defined(OS_IOS) | 25 #elif defined(OS_IOS) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 | 63 |
| 63 VariationsSeedProcessor::~VariationsSeedProcessor() { | 64 VariationsSeedProcessor::~VariationsSeedProcessor() { |
| 64 } | 65 } |
| 65 | 66 |
| 66 void VariationsSeedProcessor::CreateTrialsFromSeed( | 67 void VariationsSeedProcessor::CreateTrialsFromSeed( |
| 67 const VariationsSeed& seed, | 68 const VariationsSeed& seed, |
| 68 const std::string& locale, | 69 const std::string& locale, |
| 69 const base::Time& reference_date, | 70 const base::Time& reference_date, |
| 70 const base::Version& version, | 71 const base::Version& version, |
| 71 Study_Channel channel) { | 72 Study_Channel channel) { |
| 73 std::vector<ProcessedStudy> filtered_studies; |
| 74 FilterAndValidateStudies(seed, locale, reference_date, version, channel, |
| 75 &filtered_studies); |
| 76 |
| 77 for (size_t i = 0; i < filtered_studies.size(); ++i) |
| 78 CreateTrialFromStudy(filtered_studies[i]); |
| 79 } |
| 80 |
| 81 void VariationsSeedProcessor::FilterAndValidateStudies( |
| 82 const VariationsSeed& seed, |
| 83 const std::string& locale, |
| 84 const base::Time& reference_date, |
| 85 const base::Version& version, |
| 86 Study_Channel channel, |
| 87 std::vector<ProcessedStudy>* filtered_studies) { |
| 72 DCHECK(version.IsValid()); | 88 DCHECK(version.IsValid()); |
| 73 | 89 |
| 74 // Add expired studies (in a disabled state) only after all the non-expired | 90 // Add expired studies (in a disabled state) only after all the non-expired |
| 75 // studies have been added (and do not add an expired study if a corresponding | 91 // studies have been added (and do not add an expired study if a corresponding |
| 76 // non-expired study got added). This way, if there's both an expired and a | 92 // non-expired study got added). This way, if there's both an expired and a |
| 77 // non-expired study that applies, the non-expired study takes priority. | 93 // non-expired study that applies, the non-expired study takes priority. |
| 78 std::set<std::string> created_studies; | 94 std::set<std::string> created_studies; |
| 79 std::vector<const Study*> expired_studies; | 95 std::vector<const Study*> expired_studies; |
| 80 | 96 |
| 81 for (int i = 0; i < seed.study_size(); ++i) { | 97 for (int i = 0; i < seed.study_size(); ++i) { |
| 82 const Study& study = seed.study(i); | 98 const Study& study = seed.study(i); |
| 83 if (!ShouldAddStudy(study, locale, reference_date, version, channel)) | 99 if (!ShouldAddStudy(study, locale, reference_date, version, channel)) |
| 84 continue; | 100 continue; |
| 85 | 101 |
| 86 if (IsStudyExpired(study, reference_date)) { | 102 if (IsStudyExpired(study, reference_date)) { |
| 87 expired_studies.push_back(&study); | 103 expired_studies.push_back(&study); |
| 88 } else { | 104 } else if (!ContainsKey(created_studies, study.name())) { |
| 89 CreateTrialFromStudy(study, false); | 105 ValidateAndAddStudy(study, false, filtered_studies); |
| 90 created_studies.insert(study.name()); | 106 created_studies.insert(study.name()); |
| 91 } | 107 } |
| 92 } | 108 } |
| 93 | 109 |
| 94 for (size_t i = 0; i < expired_studies.size(); ++i) { | 110 for (size_t i = 0; i < expired_studies.size(); ++i) { |
| 95 if (!ContainsKey(created_studies, expired_studies[i]->name())) | 111 if (!ContainsKey(created_studies, expired_studies[i]->name())) |
| 96 CreateTrialFromStudy(*expired_studies[i], true); | 112 ValidateAndAddStudy(*expired_studies[i], true, filtered_studies); |
| 97 } | 113 } |
| 98 } | 114 } |
| 99 | 115 |
| 116 void VariationsSeedProcessor::ValidateAndAddStudy( |
| 117 const Study& study, |
| 118 bool is_expired, |
| 119 std::vector<ProcessedStudy>* filtered_studies) { |
| 120 base::FieldTrial::Probability total_probability = 0; |
| 121 if (!ValidateStudyAndComputeTotalProbability(study, &total_probability)) |
| 122 return; |
| 123 filtered_studies->push_back(ProcessedStudy(&study, total_probability, |
| 124 is_expired)); |
| 125 } |
| 126 |
| 100 bool VariationsSeedProcessor::CheckStudyChannel(const Study_Filter& filter, | 127 bool VariationsSeedProcessor::CheckStudyChannel(const Study_Filter& filter, |
| 101 Study_Channel channel) { | 128 Study_Channel channel) { |
| 102 // An empty channel list matches all channels. | 129 // An empty channel list matches all channels. |
| 103 if (filter.channel_size() == 0) | 130 if (filter.channel_size() == 0) |
| 104 return true; | 131 return true; |
| 105 | 132 |
| 106 for (int i = 0; i < filter.channel_size(); ++i) { | 133 for (int i = 0; i < filter.channel_size(); ++i) { |
| 107 if (filter.channel(i) == channel) | 134 if (filter.channel(i) == channel) |
| 108 return true; | 135 return true; |
| 109 } | 136 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 } | 186 } |
| 160 | 187 |
| 161 if (filter.has_max_version()) { | 188 if (filter.has_max_version()) { |
| 162 if (version.CompareToWildcardString(filter.max_version()) > 0) | 189 if (version.CompareToWildcardString(filter.max_version()) > 0) |
| 163 return false; | 190 return false; |
| 164 } | 191 } |
| 165 | 192 |
| 166 return true; | 193 return true; |
| 167 } | 194 } |
| 168 | 195 |
| 169 void VariationsSeedProcessor::CreateTrialFromStudy(const Study& study, | 196 void VariationsSeedProcessor::CreateTrialFromStudy( |
| 170 bool is_expired) { | 197 const ProcessedStudy& processed_study) { |
| 171 base::FieldTrial::Probability total_probability = 0; | 198 const Study& study = *processed_study.study; |
| 172 if (!ValidateStudyAndComputeTotalProbability(study, &total_probability)) | |
| 173 return; | |
| 174 | 199 |
| 175 // Check if any experiments need to be forced due to a command line | 200 // Check if any experiments need to be forced due to a command line |
| 176 // flag. Force the first experiment with an existing flag. | 201 // flag. Force the first experiment with an existing flag. |
| 177 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 202 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 178 for (int i = 0; i < study.experiment_size(); ++i) { | 203 for (int i = 0; i < study.experiment_size(); ++i) { |
| 179 const Study_Experiment& experiment = study.experiment(i); | 204 const Study_Experiment& experiment = study.experiment(i); |
| 180 if (experiment.has_forcing_flag() && | 205 if (experiment.has_forcing_flag() && |
| 181 command_line->HasSwitch(experiment.forcing_flag())) { | 206 command_line->HasSwitch(experiment.forcing_flag())) { |
| 182 base::FieldTrialList::CreateFieldTrial(study.name(), experiment.name()); | 207 base::FieldTrialList::CreateFieldTrial(study.name(), experiment.name()); |
| 183 RegisterExperimentParams(study, experiment); | 208 RegisterExperimentParams(study, experiment); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 195 randomization_type = base::FieldTrial::ONE_TIME_RANDOMIZED; | 220 randomization_type = base::FieldTrial::ONE_TIME_RANDOMIZED; |
| 196 if (study.has_randomization_seed()) | 221 if (study.has_randomization_seed()) |
| 197 randomization_seed = study.randomization_seed(); | 222 randomization_seed = study.randomization_seed(); |
| 198 } | 223 } |
| 199 | 224 |
| 200 // The trial is created without specifying an expiration date because the | 225 // The trial is created without specifying an expiration date because the |
| 201 // expiration check in field_trial.cc is based on the build date. Instead, | 226 // expiration check in field_trial.cc is based on the build date. Instead, |
| 202 // the expiration check using |reference_date| is done explicitly below. | 227 // the expiration check using |reference_date| is done explicitly below. |
| 203 scoped_refptr<base::FieldTrial> trial( | 228 scoped_refptr<base::FieldTrial> trial( |
| 204 base::FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed( | 229 base::FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed( |
| 205 study.name(), total_probability, study.default_experiment_name(), | 230 study.name(), processed_study.total_probability, |
| 231 study.default_experiment_name(), |
| 206 base::FieldTrialList::kNoExpirationYear, 1, 1, randomization_type, | 232 base::FieldTrialList::kNoExpirationYear, 1, 1, randomization_type, |
| 207 randomization_seed, NULL)); | 233 randomization_seed, NULL)); |
| 208 | 234 |
| 209 for (int i = 0; i < study.experiment_size(); ++i) { | 235 for (int i = 0; i < study.experiment_size(); ++i) { |
| 210 const Study_Experiment& experiment = study.experiment(i); | 236 const Study_Experiment& experiment = study.experiment(i); |
| 211 RegisterExperimentParams(study, experiment); | 237 RegisterExperimentParams(study, experiment); |
| 212 | 238 |
| 213 // Groups with flags can't be selected randomly, so we don't add them to | 239 // Groups with flags can't be selected randomly, so we don't add them to |
| 214 // the field trial. | 240 // the field trial. |
| 215 if (experiment.has_forcing_flag()) | 241 if (experiment.has_forcing_flag()) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 230 const VariationID variation_id = | 256 const VariationID variation_id = |
| 231 static_cast<VariationID>(experiment.google_update_experiment_id()); | 257 static_cast<VariationID>(experiment.google_update_experiment_id()); |
| 232 AssociateGoogleVariationIDForce(GOOGLE_UPDATE_SERVICE, | 258 AssociateGoogleVariationIDForce(GOOGLE_UPDATE_SERVICE, |
| 233 study.name(), | 259 study.name(), |
| 234 experiment.name(), | 260 experiment.name(), |
| 235 variation_id); | 261 variation_id); |
| 236 } | 262 } |
| 237 } | 263 } |
| 238 | 264 |
| 239 trial->SetForced(); | 265 trial->SetForced(); |
| 240 if (is_expired) | 266 if (processed_study.is_expired) |
| 241 trial->Disable(); | 267 trial->Disable(); |
| 242 else if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) | 268 else if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO) |
| 243 trial->group(); | 269 trial->group(); |
| 244 } | 270 } |
| 245 | 271 |
| 246 bool VariationsSeedProcessor::IsStudyExpired(const Study& study, | 272 bool VariationsSeedProcessor::IsStudyExpired(const Study& study, |
| 247 const base::Time& date_time) { | 273 const base::Time& date_time) { |
| 248 if (study.has_expiry_date()) { | 274 if (study.has_expiry_date()) { |
| 249 const base::Time expiry_date = | 275 const base::Time expiry_date = |
| 250 ConvertStudyDateToBaseTime(study.expiry_date()); | 276 ConvertStudyDateToBaseTime(study.expiry_date()); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 // The default group was not found in the list of groups. This study is not | 367 // The default group was not found in the list of groups. This study is not |
| 342 // valid. | 368 // valid. |
| 343 return false; | 369 return false; |
| 344 } | 370 } |
| 345 | 371 |
| 346 *total_probability = divisor; | 372 *total_probability = divisor; |
| 347 return true; | 373 return true; |
| 348 } | 374 } |
| 349 | 375 |
| 350 } // namespace chrome_variations | 376 } // namespace chrome_variations |
| OLD | NEW |