Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 chrome_variations::TrialsSeed seed; |
| 55 std::string seed_data; | 56 if (!LoadVariationsSeed(local_prefs, &seed)) |
| 57 return false; | |
| 56 | 58 |
| 57 // If the decode process fails, assume the pref value is corrupt, and clear | 59 for (int i = 0; i < seed.study_size(); ++i) |
| 58 // it. | 60 CreateTrialFromStudy(seed.study(i)); |
| 59 if (!base::Base64Decode(base64_seed_data, &seed_data) || | 61 |
| 60 !variations_seed_.ParseFromString(seed_data)) { | 62 return true; |
| 61 VLOG(1) << "Variations Seed data in local pref is corrupt, clearing the " | |
| 62 << "pref."; | |
| 63 local_prefs->ClearPref(prefs::kVariationsSeed); | |
| 64 } | |
| 65 } | 63 } |
| 66 | 64 |
| 67 void VariationsService::StartFetchingVariationsSeed() { | 65 void VariationsService::StartFetchingVariationsSeed() { |
| 68 pending_seed_request_.reset(content::URLFetcher::Create( | 66 pending_seed_request_.reset(content::URLFetcher::Create( |
| 69 GURL(kDefaultVariationsServer), content::URLFetcher::GET, this)); | 67 GURL(kDefaultVariationsServer), content::URLFetcher::GET, this)); |
| 70 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 68 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 71 net::LOAD_DO_NOT_SAVE_COOKIES); | 69 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 72 pending_seed_request_->SetRequestContext( | 70 pending_seed_request_->SetRequestContext( |
| 73 g_browser_process->system_request_context()); | 71 g_browser_process->system_request_context()); |
| 72 // TODO(jwd): pull max retries into a contsant | |
| 74 pending_seed_request_->SetMaxRetries(5); | 73 pending_seed_request_->SetMaxRetries(5); |
| 75 pending_seed_request_->Start(); | 74 pending_seed_request_->Start(); |
| 76 } | 75 } |
| 77 | 76 |
| 78 void VariationsService::OnURLFetchComplete(const content::URLFetcher* source) { | 77 void VariationsService::OnURLFetchComplete(const content::URLFetcher* source) { |
| 79 DCHECK_EQ(pending_seed_request_.get(), source); | 78 DCHECK_EQ(pending_seed_request_.get(), source); |
| 80 // When we're done handling the request, the fetcher will be deleted. | 79 // When we're done handling the request, the fetcher will be deleted. |
| 81 scoped_ptr<const content::URLFetcher> request( | 80 scoped_ptr<const content::URLFetcher> request( |
| 82 pending_seed_request_.release()); | 81 pending_seed_request_.release()); |
| 83 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS || | 82 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS || |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 } | 138 } |
| 140 | 139 |
| 141 DVLOG(1) << "Kept study " << study.name() << "."; | 140 DVLOG(1) << "Kept study " << study.name() << "."; |
| 142 return true; | 141 return true; |
| 143 } | 142 } |
| 144 | 143 |
| 145 // static | 144 // static |
| 146 bool VariationsService::CheckStudyChannel( | 145 bool VariationsService::CheckStudyChannel( |
| 147 const chrome_variations::Study& study, | 146 const chrome_variations::Study& study, |
| 148 chrome::VersionInfo::Channel channel) { | 147 chrome::VersionInfo::Channel channel) { |
| 148 if (study.channel_size() == 0) { | |
| 149 // An empty channel list matches all channels. | |
| 150 return true; | |
| 151 } | |
| 152 | |
| 149 for (int i = 0; i < study.channel_size(); ++i) { | 153 for (int i = 0; i < study.channel_size(); ++i) { |
| 150 if (ConvertStudyChannelToVersionChannel(study.channel(i)) == channel) | 154 if (ConvertStudyChannelToVersionChannel(study.channel(i)) == channel) |
| 151 return true; | 155 return true; |
| 152 } | 156 } |
| 153 return false; | 157 return false; |
| 154 } | 158 } |
| 155 | 159 |
| 156 // static | 160 // static |
| 157 bool VariationsService::CheckStudyVersion(const chrome_variations::Study& study, | 161 bool VariationsService::CheckStudyVersion(const chrome_variations::Study& study, |
| 158 const std::string& version_string) { | 162 const std::string& version_string) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 181 return true; | 185 return true; |
| 182 } | 186 } |
| 183 | 187 |
| 184 // static | 188 // static |
| 185 bool VariationsService::CheckStudyDate(const chrome_variations::Study& study, | 189 bool VariationsService::CheckStudyDate(const chrome_variations::Study& study, |
| 186 const base::Time& date_time) { | 190 const base::Time& date_time) { |
| 187 const base::Time epoch = base::Time::UnixEpoch(); | 191 const base::Time epoch = base::Time::UnixEpoch(); |
| 188 | 192 |
| 189 if (study.has_start_date()) { | 193 if (study.has_start_date()) { |
| 190 const base::Time start_date = | 194 const base::Time start_date = |
| 191 epoch + base::TimeDelta::FromMilliseconds(study.start_date()); | 195 epoch + base::TimeDelta::FromSeconds(study.start_date()); |
| 192 if (date_time < start_date) | 196 if (date_time < start_date) |
| 193 return false; | 197 return false; |
| 194 } | 198 } |
| 195 | 199 |
| 196 if (study.has_expiry_date()) { | 200 if (study.has_expiry_date()) { |
| 197 const base::Time expiry_date = | 201 const base::Time expiry_date = |
| 198 epoch + base::TimeDelta::FromMilliseconds(study.expiry_date()); | 202 epoch + base::TimeDelta::FromSeconds(study.expiry_date()); |
| 199 if (date_time >= expiry_date) | 203 if (date_time >= expiry_date) |
| 200 return false; | 204 return false; |
| 201 } | 205 } |
| 202 | 206 |
| 203 return true; | 207 return true; |
| 204 } | 208 } |
| 209 | |
| 210 bool VariationsService::LoadVariationsSeed( | |
| 211 PrefService* local_prefs, | |
| 212 chrome_variations::TrialsSeed* seed) { | |
| 213 std::string base64_seed_data = local_prefs->GetString(prefs::kVariationsSeed); | |
| 214 std::string seed_data; | |
| 215 | |
| 216 // If the decode process fails, assume the pref value is corrupt, and clear | |
| 217 // it. | |
| 218 if (!base::Base64Decode(base64_seed_data, &seed_data) || | |
| 219 !seed->ParseFromString(seed_data)) { | |
| 220 VLOG(1) << "Variations Seed data in local pref is corrupt, clearing the " | |
| 221 << "pref."; | |
| 222 local_prefs->ClearPref(prefs::kVariationsSeed); | |
| 223 return false; | |
| 224 } | |
| 225 return true; | |
| 226 } | |
| 227 | |
| 228 void VariationsService::CreateTrialFromStudy( | |
| 229 const chrome_variations::Study& study) { | |
| 230 if (!ShouldAddStudy(study)) | |
| 231 return; | |
| 232 | |
| 233 // At the moment, a missing default_experiment_name makes the study invalid. | |
| 234 if (!study.has_default_experiment_name()) { | |
| 235 DVLOG(1) << study.name() << " has no default experiment defined."; | |
| 236 return; | |
| 237 } | |
| 238 | |
| 239 const std::string& default_group_name = study.default_experiment_name(); | |
| 240 base::FieldTrial::Probability divisor = 0; | |
| 241 | |
| 242 bool found_default_group = false; | |
| 243 for (int i = 0; i < study.experiment_size(); ++i) { | |
| 244 divisor += study.experiment(i).probability_weight(); | |
| 245 if (study.experiment(i).name() == default_group_name) { | |
| 246 found_default_group = true; | |
| 247 } | |
| 248 } | |
| 249 if (!found_default_group){ | |
|
Alexei Svitkine (slow)
2012/05/08 03:40:13
Space before {.
jwd
2012/05/08 03:47:24
Aw man, I'm missing all of these...
Done.
| |
| 250 DVLOG(1) << study.name() << " is missing default experiment in it's " | |
| 251 << "experiment list"; | |
| 252 // The default group was not found in the list of groups. This study is not | |
| 253 // valid. | |
|
Alexei Svitkine (slow)
2012/05/08 03:40:13
Nit remove space before "valid".
jwd
2012/05/08 03:47:24
Done.
| |
| 254 return; | |
| 255 } | |
| 256 | |
| 257 const base::Time epoch = base::Time::UnixEpoch(); | |
| 258 const base::Time expiry_date = | |
| 259 epoch + base::TimeDelta::FromSeconds(study.expiry_date()); | |
| 260 base::Time::Exploded exploded_end_date; | |
| 261 expiry_date.UTCExplode(&exploded_end_date); | |
| 262 | |
| 263 scoped_refptr<base::FieldTrial> trial( | |
| 264 base::FieldTrialList::FactoryGetFieldTrial( | |
| 265 study.name(), divisor, default_group_name, exploded_end_date.year, | |
| 266 exploded_end_date.month, exploded_end_date.day_of_month, NULL)); | |
|
Alexei Svitkine (slow)
2012/05/08 03:40:13
Nit: remove space before NULL.
jwd
2012/05/08 03:47:24
Done.
| |
| 267 | |
| 268 if (study.has_consistency() && | |
| 269 study.consistency() == chrome_variations::Study_Consistency_PERMANENT) | |
|
Alexei Svitkine (slow)
2012/05/08 03:40:13
Nit: Add {'s.
jwd
2012/05/08 03:47:24
Done.
| |
| 270 trial->UseOneTimeRandomization(); | |
| 271 | |
| 272 for (int i = 0; i < study.experiment_size(); ++i) { | |
| 273 if (study.experiment(i).name() != default_group_name) | |
| 274 trial->AppendGroup(study.experiment(i).name(), | |
| 275 study.experiment(i).probability_weight()); | |
|
Alexei Svitkine (slow)
2012/05/08 03:40:13
Nit: align.
SteveT
2012/05/08 03:44:28
Nit: Braces around if body, since it spans 2 physi
jwd
2012/05/08 03:47:24
Done.
| |
| 276 } | |
| 277 | |
| 278 trial->SetForced(); | |
| 279 } | |
| OLD | NEW |