• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "components/variations/variations_seed_processor.h"
6 
7 #include <vector>
8 
9 #include "base/command_line.h"
10 #include "base/metrics/field_trial.h"
11 #include "components/variations/processed_study.h"
12 #include "components/variations/study_filtering.h"
13 #include "components/variations/variations_associated_data.h"
14 
15 namespace chrome_variations {
16 
17 namespace {
18 
19 // Associates the variations params of |experiment|, if present.
RegisterExperimentParams(const Study & study,const Study_Experiment & experiment)20 void RegisterExperimentParams(const Study& study,
21                               const Study_Experiment& experiment) {
22   std::map<std::string, std::string> params;
23   for (int i = 0; i < experiment.param_size(); ++i) {
24     if (experiment.param(i).has_name() && experiment.param(i).has_value())
25       params[experiment.param(i).name()] = experiment.param(i).value();
26   }
27   if (!params.empty())
28     AssociateVariationParams(study.name(), experiment.name(), params);
29 }
30 
31 // If there are variation ids associated with |experiment|, register the
32 // variation ids.
RegisterVariationIds(const Study_Experiment & experiment,const std::string & trial_name)33 void RegisterVariationIds(const Study_Experiment& experiment,
34                           const std::string& trial_name) {
35   if (experiment.has_google_web_experiment_id()) {
36     const VariationID variation_id =
37         static_cast<VariationID>(experiment.google_web_experiment_id());
38     AssociateGoogleVariationIDForce(GOOGLE_WEB_PROPERTIES,
39                                     trial_name,
40                                     experiment.name(),
41                                     variation_id);
42   }
43   if (experiment.has_google_web_trigger_experiment_id()) {
44     const VariationID variation_id =
45         static_cast<VariationID>(experiment.google_web_trigger_experiment_id());
46     AssociateGoogleVariationIDForce(GOOGLE_WEB_PROPERTIES_TRIGGER,
47                                     trial_name,
48                                     experiment.name(),
49                                     variation_id);
50   }
51   if (experiment.has_google_update_experiment_id()) {
52     const VariationID variation_id =
53         static_cast<VariationID>(experiment.google_update_experiment_id());
54     AssociateGoogleVariationIDForce(GOOGLE_UPDATE_SERVICE,
55                                     trial_name,
56                                     experiment.name(),
57                                     variation_id);
58   }
59 }
60 
61 }  // namespace
62 
VariationsSeedProcessor()63 VariationsSeedProcessor::VariationsSeedProcessor() {
64 }
65 
~VariationsSeedProcessor()66 VariationsSeedProcessor::~VariationsSeedProcessor() {
67 }
68 
CreateTrialsFromSeed(const VariationsSeed & seed,const std::string & locale,const base::Time & reference_date,const base::Version & version,Study_Channel channel,Study_FormFactor form_factor,const std::string & hardware_class)69 void VariationsSeedProcessor::CreateTrialsFromSeed(
70     const VariationsSeed& seed,
71     const std::string& locale,
72     const base::Time& reference_date,
73     const base::Version& version,
74     Study_Channel channel,
75     Study_FormFactor form_factor,
76     const std::string& hardware_class) {
77   std::vector<ProcessedStudy> filtered_studies;
78   FilterAndValidateStudies(seed, locale, reference_date, version, channel,
79                            form_factor, hardware_class, &filtered_studies);
80 
81   for (size_t i = 0; i < filtered_studies.size(); ++i)
82     CreateTrialFromStudy(filtered_studies[i]);
83 }
84 
CreateTrialFromStudy(const ProcessedStudy & processed_study)85 void VariationsSeedProcessor::CreateTrialFromStudy(
86     const ProcessedStudy& processed_study) {
87   const Study& study = *processed_study.study();
88 
89   // Check if any experiments need to be forced due to a command line
90   // flag. Force the first experiment with an existing flag.
91   CommandLine* command_line = CommandLine::ForCurrentProcess();
92   for (int i = 0; i < study.experiment_size(); ++i) {
93     const Study_Experiment& experiment = study.experiment(i);
94     if (experiment.has_forcing_flag() &&
95         command_line->HasSwitch(experiment.forcing_flag())) {
96       scoped_refptr<base::FieldTrial> trial(
97           base::FieldTrialList::CreateFieldTrial(study.name(),
98                                                  experiment.name()));
99       RegisterExperimentParams(study, experiment);
100       RegisterVariationIds(experiment, study.name());
101       if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO)
102         trial->group();
103 
104       DVLOG(1) << "Trial " << study.name() << " forced by flag: "
105                << experiment.forcing_flag();
106       return;
107     }
108   }
109 
110   uint32 randomization_seed = 0;
111   base::FieldTrial::RandomizationType randomization_type =
112       base::FieldTrial::SESSION_RANDOMIZED;
113   if (study.has_consistency() &&
114       study.consistency() == Study_Consistency_PERMANENT) {
115     randomization_type = base::FieldTrial::ONE_TIME_RANDOMIZED;
116     if (study.has_randomization_seed())
117       randomization_seed = study.randomization_seed();
118   }
119 
120   // 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,
122   // the expiration check using |reference_date| is done explicitly below.
123   scoped_refptr<base::FieldTrial> trial(
124       base::FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
125           study.name(), processed_study.total_probability(),
126           study.default_experiment_name(),
127           base::FieldTrialList::kNoExpirationYear, 1, 1, randomization_type,
128           randomization_seed, NULL));
129 
130   for (int i = 0; i < study.experiment_size(); ++i) {
131     const Study_Experiment& experiment = study.experiment(i);
132     RegisterExperimentParams(study, experiment);
133 
134     // 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.
136     if (experiment.has_forcing_flag())
137       continue;
138 
139     if (experiment.name() != study.default_experiment_name())
140       trial->AppendGroup(experiment.name(), experiment.probability_weight());
141 
142     RegisterVariationIds(experiment, study.name());
143   }
144 
145   trial->SetForced();
146   if (processed_study.is_expired())
147     trial->Disable();
148   else if (study.activation_type() == Study_ActivationType_ACTIVATION_AUTO)
149     trial->group();
150 }
151 
152 }  // namespace chrome_variations
153