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

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

Issue 10375043: Variations Service now creates field trials from variations seed. (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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 "chrome/browser/metrics/variations_service.h" 5 #include "chrome/browser/metrics/variations_service.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/build_time.h" 8 #include "base/build_time.h"
9 #include "base/version.h" 9 #include "base/version.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
11 #include "base/memory/singleton.h" 11 #include "base/memory/singleton.h"
12 #include "base/metrics/field_trial.h"
12 #include "chrome/browser/browser_process.h" 13 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/metrics/proto/trials_seed.pb.h" 14 #include "chrome/browser/metrics/proto/trials_seed.pb.h"
14 #include "chrome/browser/prefs/pref_service.h" 15 #include "chrome/browser/prefs/pref_service.h"
15 #include "chrome/common/pref_names.h" 16 #include "chrome/common/pref_names.h"
16 #include "content/public/common/url_fetcher.h" 17 #include "content/public/common/url_fetcher.h"
17 #include "googleurl/src/gurl.h" 18 #include "googleurl/src/gurl.h"
18 #include "net/base/load_flags.h" 19 #include "net/base/load_flags.h"
19 #include "net/url_request/url_request_status.h" 20 #include "net/url_request/url_request_status.h"
20 21
21 namespace { 22 namespace {
(...skipping 21 matching lines...) Expand all
43 return chrome::VersionInfo::CHANNEL_UNKNOWN; 44 return chrome::VersionInfo::CHANNEL_UNKNOWN;
44 } 45 }
45 46
46 } // namespace 47 } // namespace
47 48
48 // Static 49 // Static
49 VariationsService* VariationsService::GetInstance() { 50 VariationsService* VariationsService::GetInstance() {
50 return Singleton<VariationsService>::get(); 51 return Singleton<VariationsService>::get();
51 } 52 }
52 53
53 void VariationsService::LoadVariationsSeed(PrefService* local_prefs) { 54 bool VariationsService::CreateTrialsFromSeed(PrefService* local_prefs) {
54 std::string base64_seed_data = local_prefs->GetString(prefs::kVariationsSeed); 55 LOG(INFO) << "Creating trials from seed";
MAD 2012/05/08 03:09:00 Either remove all LOGs or use DVLOG(1)s
jwd 2012/05/08 03:30:01 Done.
55 std::string seed_data; 56 chrome_variations::TrialsSeed seed;
57 if (!LoadVariationsSeed(local_prefs, seed))
58 return false;
56 59
57 // If the decode process fails, assume the pref value is corrupt, and clear 60 LOG(INFO) << "about to loop through studies " << seed.study_size();
58 // it. 61 for (int i = 0; i<seed.study_size(); ++i) {
Alexei Svitkine (slow) 2012/05/08 03:22:54 Put spaces around the <.
jwd 2012/05/08 03:35:18 Done.
59 if (!base::Base64Decode(base64_seed_data, &seed_data) || 62 CreateTrialFromStudy(seed.study(i));
MAD 2012/05/08 03:09:00 For single line block, we don't use {}
jwd 2012/05/08 03:30:01 Done.
60 !variations_seed_.ParseFromString(seed_data)) {
61 VLOG(1) << "Variations Seed data in local pref is corrupt, clearing the "
62 << "pref.";
63 local_prefs->ClearPref(prefs::kVariationsSeed);
64 } 63 }
64 return true;
65 } 65 }
66 66
67 void VariationsService::StartFetchingVariationsSeed() { 67 void VariationsService::StartFetchingVariationsSeed() {
68 LOG(INFO) << "start fetching " << kDefaultVariationsServer;
68 pending_seed_request_.reset(content::URLFetcher::Create( 69 pending_seed_request_.reset(content::URLFetcher::Create(
69 GURL(kDefaultVariationsServer), content::URLFetcher::GET, this)); 70 GURL(kDefaultVariationsServer), content::URLFetcher::GET, this));
70 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | 71 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
71 net::LOAD_DO_NOT_SAVE_COOKIES); 72 net::LOAD_DO_NOT_SAVE_COOKIES);
72 pending_seed_request_->SetRequestContext( 73 pending_seed_request_->SetRequestContext(
73 g_browser_process->system_request_context()); 74 g_browser_process->system_request_context());
75 // TODO(jwd): pull max retries into a contsant
74 pending_seed_request_->SetMaxRetries(5); 76 pending_seed_request_->SetMaxRetries(5);
75 pending_seed_request_->Start(); 77 pending_seed_request_->Start();
76 } 78 }
77 79
78 void VariationsService::OnURLFetchComplete(const content::URLFetcher* source) { 80 void VariationsService::OnURLFetchComplete(const content::URLFetcher* source) {
81 LOG(INFO) << "got server response";
79 DCHECK_EQ(pending_seed_request_.get(), source); 82 DCHECK_EQ(pending_seed_request_.get(), source);
80 // When we're done handling the request, the fetcher will be deleted. 83 // When we're done handling the request, the fetcher will be deleted.
81 scoped_ptr<const content::URLFetcher> request( 84 scoped_ptr<const content::URLFetcher> request(
82 pending_seed_request_.release()); 85 pending_seed_request_.release());
83 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS || 86 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS ||
84 request->GetResponseCode() != 200) 87 request->GetResponseCode() != 200) {
88 LOG(INFO) << "not a success";
85 return; 89 return;
86 90 }
91 LOG(INFO) << " response was success";
87 std::string seed_data; 92 std::string seed_data;
88 request->GetResponseAsString(&seed_data); 93 request->GetResponseAsString(&seed_data);
89 94
90 StoreSeedData(seed_data, g_browser_process->local_state()); 95 StoreSeedData(seed_data, g_browser_process->local_state());
91 } 96 }
92 97
93 // static 98 // static
94 void VariationsService::RegisterPrefs(PrefService* prefs) { 99 void VariationsService::RegisterPrefs(PrefService* prefs) {
95 prefs->RegisterStringPref(prefs::kVariationsSeed, std::string()); 100 prefs->RegisterStringPref(prefs::kVariationsSeed, std::string());
96 } 101 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 } 144 }
140 145
141 DVLOG(1) << "Kept study " << study.name() << "."; 146 DVLOG(1) << "Kept study " << study.name() << ".";
142 return true; 147 return true;
143 } 148 }
144 149
145 // static 150 // static
146 bool VariationsService::CheckStudyChannel( 151 bool VariationsService::CheckStudyChannel(
147 const chrome_variations::Study& study, 152 const chrome_variations::Study& study,
148 chrome::VersionInfo::Channel channel) { 153 chrome::VersionInfo::Channel channel) {
149 for (int i = 0; i < study.channel_size(); ++i) { 154 if (study.channel_size()==0)
Alexei Svitkine (slow) 2012/05/08 03:22:54 Put spaces around the ==.
jwd 2012/05/08 03:35:18 Done.
155 // An empty channel list matches all channels.
MAD 2012/05/08 03:09:00 Add {} if you have more than one line, including c
jwd 2012/05/08 03:35:18 Done.
156 return true;
157
158 for (int i = 0; i < study.channel_size(); i++) {
MAD 2012/05/08 03:09:00 i++ -> ++i
jwd 2012/05/08 03:30:01 Done.
150 if (ConvertStudyChannelToVersionChannel(study.channel(i)) == channel) 159 if (ConvertStudyChannelToVersionChannel(study.channel(i)) == channel)
151 return true; 160 return true;
152 } 161 }
153 return false; 162 return false;
154 } 163 }
155 164
156 // static 165 // static
157 bool VariationsService::CheckStudyVersion(const chrome_variations::Study& study, 166 bool VariationsService::CheckStudyVersion(const chrome_variations::Study& study,
158 const std::string& version_string) { 167 const std::string& version_string) {
159 const Version current_version(version_string); 168 const Version current_version(version_string);
160 if (!current_version.IsValid()) { 169 if (!current_version.IsValid()) {
161 DCHECK(false); 170 DCHECK(false);
162 return false; 171 return false;
163 } 172 }
164 173
165 if (study.has_min_version()) { 174 if (study.has_min_version()) {
166 const Version min_version(study.min_version()); 175 const Version min_version(study.min_version());
167 if (!min_version.IsValid()) 176 if (!min_version.IsValid()){
177 LOG(INFO) << 1;
168 return false; 178 return false;
169 if (current_version.CompareTo(min_version) < 0) 179 }
180 if (current_version.CompareTo(min_version) < 0){
181 LOG(INFO) << 2;
170 return false; 182 return false;
183 }
171 } 184 }
172 185
173 if (study.has_max_version()) { 186 if (study.has_max_version()) {
174 const Version max_version(study.max_version()); 187 const Version max_version(study.max_version());
175 if (!max_version.IsValid()) 188 if (!max_version.IsValid()){
189 LOG(INFO) << 3;
176 return false; 190 return false;
177 if (current_version.CompareTo(max_version) > 0) 191 }
192 if (current_version.CompareTo(max_version) > 0){
193 LOG(INFO) << 4;
178 return false; 194 return false;
195 }
179 } 196 }
180 197
181 return true; 198 return true;
182 } 199 }
183 200
184 // static 201 // static
185 bool VariationsService::CheckStudyDate(const chrome_variations::Study& study, 202 bool VariationsService::CheckStudyDate(const chrome_variations::Study& study,
186 const base::Time& date_time) { 203 const base::Time& date_time) {
187 const base::Time epoch = base::Time::UnixEpoch(); 204 const base::Time epoch = base::Time::UnixEpoch();
188 205
189 if (study.has_start_date()) { 206 if (study.has_start_date()) {
190 const base::Time start_date = 207 const base::Time start_date =
191 epoch + base::TimeDelta::FromMilliseconds(study.start_date()); 208 epoch + base::TimeDelta::FromSeconds(study.start_date());
MAD 2012/05/08 03:09:00 Good catch, thanks for fixing...
192 if (date_time < start_date) 209 if (date_time < start_date){
210 LOG(INFO) << "fail1 ";
193 return false; 211 return false;
212 }
194 } 213 }
195 214
196 if (study.has_expiry_date()) { 215 if (study.has_expiry_date()) {
197 const base::Time expiry_date = 216 const base::Time expiry_date =
198 epoch + base::TimeDelta::FromMilliseconds(study.expiry_date()); 217 epoch + base::TimeDelta::FromSeconds(study.expiry_date());
199 if (date_time >= expiry_date) 218 if (date_time >= expiry_date){
219 LOG(INFO) << "fail2 ";
200 return false; 220 return false;
221 }
201 } 222 }
202 223
203 return true; 224 return true;
204 } 225 }
226
227 bool VariationsService::LoadVariationsSeed(
228 PrefService* local_prefs,
229 chrome_variations::TrialsSeed& seed) {
230 std::string base64_seed_data = local_prefs->GetString(prefs::kVariationsSeed);
231 std::string seed_data;
232
233 // If the decode process fails, assume the pref value is corrupt, and clear
234 // it.
235 if (!base::Base64Decode(base64_seed_data, &seed_data) ||
236 !seed.ParseFromString(seed_data)) {
237 VLOG(1) << "Variations Seed data in local pref is corrupt, clearing the "
238 << "pref.";
239 local_prefs->ClearPref(prefs::kVariationsSeed);
240 return false;
241 }
242 return true;
243 }
244
245 void VariationsService::CreateTrialFromStudy(
246 const chrome_variations::Study& study) {
247 LOG(INFO) << study.name();
248 if (!ShouldAddStudy(study)){
249 LOG(INFO) << "study rejected";
250 return;
251 }
252 // At the moment, a missing default_experiment_name makes the study invalid.
253 if (!study.has_default_experiment_name()){
Alexei Svitkine (slow) 2012/05/08 03:22:54 Put a space before {.
jwd 2012/05/08 03:35:18 Done.
254 DVLOG(1) << study.name() << " has no default experiment defined.";
255 return;
256 }
257 LOG(INFO) << "study accepted";
258
259 const std::string& default_group_name = study.default_experiment_name();
260 base::FieldTrial::Probability divisor = 0;
261
262 bool found_default_group = false;
263 LOG(INFO) << "looping through groups " << study.experiment_size();
264 LOG(INFO) << "looking for " << default_group_name;
265 int default_group_number;
266 bool has_default_group_number;
MAD 2012/05/08 03:09:00 Please initialize these two variables in case we d
267 for (int i = 0; i<study.experiment_size(); ++i) {
Alexei Svitkine (slow) 2012/05/08 03:22:54 Put spaces around the <.
jwd 2012/05/08 03:35:18 Done.
268 LOG(INFO) << study.experiment(i).name();
269 divisor += study.experiment(i).probability_weight();
270 if (study.experiment(i).name() == default_group_name){
271 LOG(INFO) << "default found " << default_group_name;
272 found_default_group = true;
273 has_default_group_number = study.experiment(i).has_experiment_id();
274 if (has_default_group_number)
275 default_group_number = study.experiment(i).experiment_id();
MAD 2012/05/08 03:09:00 These are not related, the experiment_id, is the G
jwd 2012/05/08 03:30:01 Ya, I think I was confused about this when I wrote
Alexei Svitkine (slow) 2012/05/08 03:31:27 That parameter is an "out" parameter, so no need t
jwd 2012/05/08 03:35:18 Ya, I was very confused when I wrote that.
276 }
277 }
278 if (!found_default_group){
279 LOG(INFO) << study.name() << " is missing default experiment from "
280 << "experiment list";
281 // The default group was not found in the list of groups. This study is not
282 // valid.
283 return;
284 }
285
286 const base::Time epoch = base::Time::UnixEpoch();
287 const base::Time expiry_date =
288 epoch + base::TimeDelta::FromSeconds(study.expiry_date());
289 base::Time::Exploded exploded_end_date;
290 expiry_date.UTCExplode(&exploded_end_date);
291
292 scoped_refptr<base::FieldTrial> trial(
293 base::FieldTrialList::FactoryGetFieldTrial(
294 study.name(), divisor, default_group_name, exploded_end_date.year,
295 exploded_end_date.month, exploded_end_date.day_of_month,
296 has_default_group_number ? &default_group_number : NULL));
MAD 2012/05/08 03:09:00 This is not needed, you don't use it, and you won'
jwd 2012/05/08 03:30:01 Ya, got rid of this now. Done.
297
298 if (study.has_consistency() &&
299 study.consistency()==chrome_variations::Study_Consistency_PERMANENT)
Alexei Svitkine (slow) 2012/05/08 03:22:54 Put spaces around the ==.
jwd 2012/05/08 03:35:18 Done.
300 trial->UseOneTimeRandomization();
301
302 for (int i = 0; i<study.experiment_size(); ++i)
Alexei Svitkine (slow) 2012/05/08 03:22:54 Put spaces around the <.
jwd 2012/05/08 03:35:18 Done.
303 if (study.experiment(i).name() != default_group_name)
MAD 2012/05/08 03:09:00 Please use {} (for both the for and the if) when t
jwd 2012/05/08 03:35:18 Done.
304 trial->AppendGroup(study.experiment(i).name(),
305 study.experiment(i).probability_weight());
Alexei Svitkine (slow) 2012/05/08 03:25:26 You also need to associate the study.experiment(i)
jwd 2012/05/08 03:35:18 MAD says that that's not important for M20, but ye
306
307 trial->SetForced();
308 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698