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

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 LOG(INFO) << "Not starting seed fetch because network is probbaly off";
66 return;
67 }
68 pending_seed_request_.reset(content::URLFetcher::Create(
69 GURL(kDefaultVariationsServer), net::URLFetcher::GET, this));
70 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
71 net::LOAD_DO_NOT_SAVE_COOKIES);
72 pending_seed_request_->SetRequestContext(
73 g_browser_process->system_request_context());
74 // TODO(jwd): pull max retries into a contsant
75 pending_seed_request_->SetMaxRetries(5);
76 pending_seed_request_->Start();
77 }
78
79 void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) {
80 DCHECK_EQ(pending_seed_request_.get(), source);
81 // When we're done handling the request, the fetcher will be deleted.
82 scoped_ptr<const content::URLFetcher> request(
83 pending_seed_request_.release());
84 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS ||
85 request->GetResponseCode() != 200)
86 return;
87
88 std::string seed_data;
89 request->GetResponseAsString(&seed_data);
90
91 StoreSeedData(seed_data, g_browser_process->local_state());
92 }
93
94 // static
95 void VariationsService::RegisterPrefs(PrefService* prefs) {
96 prefs->RegisterStringPref(prefs::kVariationsSeed, std::string());
97 }
98
99 void VariationsService::StoreSeedData(const std::string& seed_data,
100 PrefService* local_prefs) {
101 // Only store the seed data if it parses correctly.
102 chrome_variations::TrialsSeed seed;
103 if (!seed.ParseFromString(seed_data)) {
104 VLOG(1) << "Variations Seed data from server is not in valid proto format, "
105 << "rejecting the seed.";
106 return;
107 }
108 std::string base64_seed_data;
109 if (!base::Base64Encode(seed_data, &base64_seed_data)) {
110 VLOG(1) << "Variations Seed data from server fails Base64Encode, rejecting "
111 << "the seed.";
112 return;
113 }
114 local_prefs->SetString(prefs::kVariationsSeed, base64_seed_data);
115 }
116
117 // static
118 bool VariationsService::ShouldAddStudy(const chrome_variations::Study& study) {
119 const chrome::VersionInfo current_version_info;
120 if (!current_version_info.is_valid())
121 return false;
122
123 if (!CheckStudyChannel(study, chrome::VersionInfo::GetChannel())) {
124 DVLOG(1) << "Filtered out study " << study.name() << " due to version.";
125 return false;
126 }
127
128 if (!CheckStudyVersion(study, current_version_info.Version())) {
129 DVLOG(1) << "Filtered out study " << study.name() << " due to version.";
130 return false;
131 }
132
133 // Use build time and not system time to match what is done in field_trial.cc.
134 if (!CheckStudyDate(study, base::GetBuildTime())) {
135 DVLOG(1) << "Filtered out study " << study.name() << " due to date.";
136 return false;
137 }
138
139 DVLOG(1) << "Kept study " << study.name() << ".";
140 return true;
141 }
142
143 // static
144 bool VariationsService::CheckStudyChannel(
145 const chrome_variations::Study& study,
146 chrome::VersionInfo::Channel channel) {
147 if (study.channel_size() == 0) {
148 // An empty channel list matches all channels.
149 return true;
150 }
151
152 for (int i = 0; i < study.channel_size(); ++i) {
153 if (ConvertStudyChannelToVersionChannel(study.channel(i)) == channel)
154 return true;
155 }
156 return false;
157 }
158
159 // static
160 bool VariationsService::CheckStudyVersion(const chrome_variations::Study& study,
161 const std::string& version_string) {
162 const Version current_version(version_string);
163 if (!current_version.IsValid()) {
164 DCHECK(false);
165 return false;
166 }
167
168 if (study.has_min_version()) {
169 const Version min_version(study.min_version());
170 if (!min_version.IsValid())
171 return false;
172 if (current_version.CompareTo(min_version) < 0)
173 return false;
174 }
175
176 if (study.has_max_version()) {
177 const Version max_version(study.max_version());
178 if (!max_version.IsValid())
179 return false;
180 if (current_version.CompareTo(max_version) > 0)
181 return false;
182 }
183
184 return true;
185 }
186
187 // static
188 bool VariationsService::CheckStudyDate(const chrome_variations::Study& study,
189 const base::Time& date_time) {
190 const base::Time epoch = base::Time::UnixEpoch();
191
192 if (study.has_start_date()) {
193 const base::Time start_date =
194 epoch + base::TimeDelta::FromSeconds(study.start_date());
195 if (date_time < start_date)
196 return false;
197 }
198
199 if (study.has_expiry_date()) {
200 const base::Time expiry_date =
201 epoch + base::TimeDelta::FromSeconds(study.expiry_date());
202 if (date_time >= expiry_date)
203 return false;
204 }
205
206 return true;
207 }
208
209 bool VariationsService::LoadTrialsSeedFromPref(
210 PrefService* local_prefs,
211 chrome_variations::TrialsSeed* seed) {
212 std::string base64_seed_data = local_prefs->GetString(prefs::kVariationsSeed);
213 std::string seed_data;
214
215 // If the decode process fails, assume the pref value is corrupt, and clear
216 // it.
217 if (!base::Base64Decode(base64_seed_data, &seed_data) ||
218 !seed->ParseFromString(seed_data)) {
219 VLOG(1) << "Variations Seed data in local pref is corrupt, clearing the "
220 << "pref.";
221 local_prefs->ClearPref(prefs::kVariationsSeed);
222 return false;
223 }
224 return true;
225 }
226
227 void VariationsService::CreateTrialFromStudy(
228 const chrome_variations::Study& study) {
229 if (!ShouldAddStudy(study))
230 return;
231
232 // At the moment, a missing default_experiment_name makes the study invalid.
233 if (!study.has_default_experiment_name()) {
234 DVLOG(1) << study.name() << " has no default experiment defined.";
235 return;
236 }
237
238 const std::string& default_group_name = study.default_experiment_name();
239 base::FieldTrial::Probability divisor = 0;
240
241 bool found_default_group = false;
242 for (int i = 0; i < study.experiment_size(); ++i) {
243 divisor += study.experiment(i).probability_weight();
244 if (study.experiment(i).name() == default_group_name)
245 found_default_group = true;
246 }
247 if (!found_default_group) {
248 DVLOG(1) << study.name() << " is missing default experiment in it's "
249 << "experiment list";
250 // The default group was not found in the list of groups. This study is not
251 // valid.
252 return;
253 }
254
255 const base::Time epoch = base::Time::UnixEpoch();
256 const base::Time expiry_date =
257 epoch + base::TimeDelta::FromSeconds(study.expiry_date());
258 base::Time::Exploded exploded_end_date;
259 expiry_date.UTCExplode(&exploded_end_date);
260
261 scoped_refptr<base::FieldTrial> trial(
262 base::FieldTrialList::FactoryGetFieldTrial(
263 study.name(), divisor, default_group_name, exploded_end_date.year,
264 exploded_end_date.month, exploded_end_date.day_of_month, NULL));
265
266 if (study.has_consistency() &&
267 study.consistency() == chrome_variations::Study_Consistency_PERMANENT) {
268 trial->UseOneTimeRandomization();
269 }
270
271 for (int i = 0; i < study.experiment_size(); ++i) {
272 if (study.experiment(i).name() != default_group_name) {
273 trial->AppendGroup(study.experiment(i).name(),
274 study.experiment(i).probability_weight());
275 }
276 }
277
278 // TODO(jwd): Add experiment_id association code.
279 trial->SetForced();
280 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698