Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(615)

Side by Side Diff: chrome/browser/metrics/variations_service.cc

Issue 10392007: Restoring the chrome variatioons client, with a fix for browser_test failures caused by it. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "chrome/browser/metrics/variations_service.h"
6
7 #include "base/base64.h"
8 #include "base/build_time.h"
9 #include "base/version.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/metrics/field_trial.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/metrics/proto/trials_seed.pb.h"
14 #include "chrome/browser/prefs/pref_service.h"
15 #include "chrome/common/pref_names.h"
16 #include "content/public/common/url_fetcher.h"
17 #include "googleurl/src/gurl.h"
18 #include "net/base/load_flags.h"
19 #include "net/base/network_change_notifier.h"
20 #include "net/url_request/url_request_status.h"
21
22 namespace {
23
24 // Default server of Variations seed info.
25 const char kDefaultVariationsServer[] =
26 "https://clients4.google.com/chrome-variations/seed";
27
28 // Maps chrome_variations::Study_Channel enum values to corresponding
29 // chrome::VersionInfo::Channel enum values.
30 chrome::VersionInfo::Channel ConvertStudyChannelToVersionChannel(
31 chrome_variations::Study_Channel study_channel) {
32 switch (study_channel) {
33 case chrome_variations::Study_Channel_CANARY:
34 return chrome::VersionInfo::CHANNEL_CANARY;
35 case chrome_variations::Study_Channel_DEV:
36 return chrome::VersionInfo::CHANNEL_DEV;
37 case chrome_variations::Study_Channel_BETA:
38 return chrome::VersionInfo::CHANNEL_BETA;
39 case chrome_variations::Study_Channel_STABLE:
40 return chrome::VersionInfo::CHANNEL_STABLE;
41 }
42 // All enum values of |study_channel| were handled above.
43 NOTREACHED();
44 return chrome::VersionInfo::CHANNEL_UNKNOWN;
45 }
46
47 } // namespace
48
49 VariationsService::VariationsService() {}
50 VariationsService::~VariationsService() {}
51
52 bool VariationsService::CreateTrialsFromSeed(PrefService* local_prefs) {
53 chrome_variations::TrialsSeed seed;
54 if (!LoadTrialsSeedFromPref(local_prefs, &seed))
55 return false;
56
57 for (int i = 0; i < seed.study_size(); ++i)
58 CreateTrialFromStudy(seed.study(i));
59
60 return true;
61 }
62
63 void VariationsService::StartFetchingVariationsSeed() {
64 if (net::NetworkChangeNotifier::IsOffline())
65 return;
66
67 pending_seed_request_.reset(content::URLFetcher::Create(
68 GURL(kDefaultVariationsServer), net::URLFetcher::GET, this));
69 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
70 net::LOAD_DO_NOT_SAVE_COOKIES);
71 pending_seed_request_->SetRequestContext(
72 g_browser_process->system_request_context());
73 // TODO(jwd): pull max retries into a contsant
74 pending_seed_request_->SetMaxRetries(5);
SteveT 2012/05/15 16:56:47 nit: Might as well do it now and stick it in the a
jwd 2012/05/15 18:31:23 Done.
75 pending_seed_request_->Start();
76 }
77
78 void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) {
79 DCHECK_EQ(pending_seed_request_.get(), source);
80 // When we're done handling the request, the fetcher will be deleted.
81 scoped_ptr<const content::URLFetcher> request(
82 pending_seed_request_.release());
83 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS ||
84 request->GetResponseCode() != 200)
85 return;
86
87 std::string seed_data;
88 request->GetResponseAsString(&seed_data);
89
90 StoreSeedData(seed_data, g_browser_process->local_state());
91 }
92
93 // static
94 void VariationsService::RegisterPrefs(PrefService* prefs) {
95 prefs->RegisterStringPref(prefs::kVariationsSeed, std::string());
96 }
97
98 void VariationsService::StoreSeedData(const std::string& seed_data,
99 PrefService* local_prefs) {
100 // Only store the seed data if it parses correctly.
101 chrome_variations::TrialsSeed seed;
102 if (!seed.ParseFromString(seed_data)) {
103 VLOG(1) << "Variations Seed data from server is not in valid proto format, "
104 << "rejecting the seed.";
105 return;
106 }
107 std::string base64_seed_data;
108 if (!base::Base64Encode(seed_data, &base64_seed_data)) {
109 VLOG(1) << "Variations Seed data from server fails Base64Encode, rejecting "
110 << "the seed.";
111 return;
112 }
113 local_prefs->SetString(prefs::kVariationsSeed, base64_seed_data);
114 }
115
116 // static
117 bool VariationsService::ShouldAddStudy(const chrome_variations::Study& study) {
118 const chrome::VersionInfo current_version_info;
119 if (!current_version_info.is_valid())
120 return false;
121
122 if (!CheckStudyChannel(study, chrome::VersionInfo::GetChannel())) {
123 DVLOG(1) << "Filtered out study " << study.name() << " due to version.";
124 return false;
125 }
126
127 if (!CheckStudyVersion(study, current_version_info.Version())) {
128 DVLOG(1) << "Filtered out study " << study.name() << " due to version.";
129 return false;
130 }
131
132 // Use build time and not system time to match what is done in field_trial.cc.
133 if (!CheckStudyDate(study, base::GetBuildTime())) {
134 DVLOG(1) << "Filtered out study " << study.name() << " due to date.";
135 return false;
136 }
137
138 DVLOG(1) << "Kept study " << study.name() << ".";
139 return true;
140 }
141
142 // static
143 bool VariationsService::CheckStudyChannel(
144 const chrome_variations::Study& study,
145 chrome::VersionInfo::Channel channel) {
146 if (study.channel_size() == 0) {
147 // An empty channel list matches all channels.
148 return true;
149 }
150
151 for (int i = 0; i < study.channel_size(); ++i) {
152 if (ConvertStudyChannelToVersionChannel(study.channel(i)) == channel)
153 return true;
154 }
155 return false;
156 }
157
158 // static
159 bool VariationsService::CheckStudyVersion(const chrome_variations::Study& study,
160 const std::string& version_string) {
161 const Version current_version(version_string);
162 if (!current_version.IsValid()) {
163 DCHECK(false);
164 return false;
165 }
166
167 if (study.has_min_version()) {
168 const Version min_version(study.min_version());
169 if (!min_version.IsValid())
170 return false;
171 if (current_version.CompareTo(min_version) < 0)
172 return false;
173 }
174
175 if (study.has_max_version()) {
176 const Version max_version(study.max_version());
177 if (!max_version.IsValid())
178 return false;
179 if (current_version.CompareTo(max_version) > 0)
180 return false;
181 }
182
183 return true;
184 }
185
186 // static
187 bool VariationsService::CheckStudyDate(const chrome_variations::Study& study,
188 const base::Time& date_time) {
189 const base::Time epoch = base::Time::UnixEpoch();
190
191 if (study.has_start_date()) {
192 const base::Time start_date =
193 epoch + base::TimeDelta::FromSeconds(study.start_date());
194 if (date_time < start_date)
195 return false;
196 }
197
198 if (study.has_expiry_date()) {
199 const base::Time expiry_date =
200 epoch + base::TimeDelta::FromSeconds(study.expiry_date());
201 if (date_time >= expiry_date)
202 return false;
203 }
204
205 return true;
206 }
207
208 bool VariationsService::LoadTrialsSeedFromPref(
209 PrefService* local_prefs,
210 chrome_variations::TrialsSeed* seed) {
211 std::string base64_seed_data = local_prefs->GetString(prefs::kVariationsSeed);
212 std::string seed_data;
213
214 // If the decode process fails, assume the pref value is corrupt, and clear
215 // it.
216 if (!base::Base64Decode(base64_seed_data, &seed_data) ||
217 !seed->ParseFromString(seed_data)) {
218 VLOG(1) << "Variations Seed data in local pref is corrupt, clearing the "
219 << "pref.";
220 local_prefs->ClearPref(prefs::kVariationsSeed);
221 return false;
222 }
223 return true;
224 }
225
226 void VariationsService::CreateTrialFromStudy(
227 const chrome_variations::Study& study) {
228 if (!ShouldAddStudy(study))
229 return;
230
231 // At the moment, a missing default_experiment_name makes the study invalid.
232 if (!study.has_default_experiment_name()) {
233 DVLOG(1) << study.name() << " has no default experiment defined.";
234 return;
235 }
236
237 const std::string& default_group_name = study.default_experiment_name();
238 base::FieldTrial::Probability divisor = 0;
239
240 bool found_default_group = false;
241 for (int i = 0; i < study.experiment_size(); ++i) {
242 divisor += study.experiment(i).probability_weight();
243 if (study.experiment(i).name() == default_group_name)
244 found_default_group = true;
245 }
246 if (!found_default_group) {
247 DVLOG(1) << study.name() << " is missing default experiment in it's "
248 << "experiment list";
249 // The default group was not found in the list of groups. This study is not
250 // valid.
251 return;
252 }
253
254 const base::Time epoch = base::Time::UnixEpoch();
255 const base::Time expiry_date =
256 epoch + base::TimeDelta::FromSeconds(study.expiry_date());
257 base::Time::Exploded exploded_end_date;
258 expiry_date.UTCExplode(&exploded_end_date);
259
260 scoped_refptr<base::FieldTrial> trial(
261 base::FieldTrialList::FactoryGetFieldTrial(
262 study.name(), divisor, default_group_name, exploded_end_date.year,
263 exploded_end_date.month, exploded_end_date.day_of_month, NULL));
264
265 if (study.has_consistency() &&
266 study.consistency() == chrome_variations::Study_Consistency_PERMANENT) {
267 trial->UseOneTimeRandomization();
268 }
269
270 for (int i = 0; i < study.experiment_size(); ++i) {
271 if (study.experiment(i).name() != default_group_name) {
272 trial->AppendGroup(study.experiment(i).name(),
273 study.experiment(i).probability_weight());
274 }
275 }
276
277 // TODO(jwd): Add experiment_id association code.
278 trial->SetForced();
279 }
OLDNEW
« no previous file with comments | « chrome/browser/metrics/variations_service.h ('k') | chrome/browser/metrics/variations_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698