| 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 <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/build_time.h" | 10 #include "base/build_time.h" |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/metrics/field_trial.h" | 13 #include "base/metrics/field_trial.h" |
| 14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "base/version.h" | 15 #include "base/version.h" |
| 16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/metrics/proto/trials_seed.pb.h" | 17 #include "chrome/browser/metrics/proto/trials_seed.pb.h" |
| 18 #include "chrome/browser/prefs/pref_service.h" | 18 #include "chrome/browser/prefs/pref_service.h" |
| 19 #include "chrome/browser/upgrade_detector.h" |
| 20 #include "chrome/common/chrome_notification_types.h" |
| 19 #include "chrome/common/chrome_switches.h" | 21 #include "chrome/common/chrome_switches.h" |
| 20 #include "chrome/common/metrics/experiments_helper.h" | 22 #include "chrome/common/metrics/experiments_helper.h" |
| 21 #include "chrome/common/pref_names.h" | 23 #include "chrome/common/pref_names.h" |
| 22 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
| 25 #include "content/public/browser/notification_service.h" |
| 23 #include "content/public/common/url_fetcher.h" | 26 #include "content/public/common/url_fetcher.h" |
| 24 #include "googleurl/src/gurl.h" | 27 #include "googleurl/src/gurl.h" |
| 25 #include "net/base/load_flags.h" | 28 #include "net/base/load_flags.h" |
| 26 #include "net/base/network_change_notifier.h" | 29 #include "net/base/network_change_notifier.h" |
| 27 #include "net/http/http_response_headers.h" | 30 #include "net/http/http_response_headers.h" |
| 28 #include "net/url_request/url_fetcher.h" | 31 #include "net/url_request/url_fetcher.h" |
| 29 #include "net/url_request/url_request_status.h" | 32 #include "net/url_request/url_request_status.h" |
| 30 | 33 |
| 31 namespace chrome_variations { | 34 namespace chrome_variations { |
| 32 | 35 |
| 33 namespace { | 36 namespace { |
| 34 | 37 |
| 35 // Default server of Variations seed info. | 38 // Default server of variations seed info. |
| 36 const char kDefaultVariationsServerURL[] = | 39 const char kDefaultVariationsServerURL[] = |
| 37 "https://clients4.google.com/chrome-variations/seed"; | 40 "https://clients4.google.com/chrome-variations/seed"; |
| 38 const int kMaxRetrySeedFetch = 5; | 41 const int kMaxRetrySeedFetch = 5; |
| 39 | 42 |
| 40 // Time between seed fetches, in hours. | 43 // Time between seed fetches, in hours. |
| 41 const int kSeedFetchPeriodHours = 5; | 44 const int kSeedFetchPeriodHours = 5; |
| 42 | 45 |
| 43 // Maps Study_Channel enum values to corresponding chrome::VersionInfo::Channel | 46 // Maps Study_Channel enum values to corresponding chrome::VersionInfo::Channel |
| 44 // enum values. | 47 // enum values. |
| 45 chrome::VersionInfo::Channel ConvertStudyChannelToVersionChannel( | 48 chrome::VersionInfo::Channel ConvertStudyChannelToVersionChannel( |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 #else | 80 #else |
| 78 #error Unknown platform | 81 #error Unknown platform |
| 79 #endif | 82 #endif |
| 80 } | 83 } |
| 81 | 84 |
| 82 // Converts |date_time| in Study date format to base::Time. | 85 // Converts |date_time| in Study date format to base::Time. |
| 83 base::Time ConvertStudyDateToBaseTime(int64 date_time) { | 86 base::Time ConvertStudyDateToBaseTime(int64 date_time) { |
| 84 return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(date_time); | 87 return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(date_time); |
| 85 } | 88 } |
| 86 | 89 |
| 87 // Determine and return the variations server URL. | 90 // Determine and return the Variations server URL. |
| 88 GURL GetVariationsServerURL() { | 91 GURL GetVariationsServerURL() { |
| 89 std::string server_url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 92 std::string server_url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 90 switches::kVariationsServerURL)); | 93 switches::kVariationsServerURL)); |
| 91 if (server_url.empty()) | 94 if (server_url.empty()) |
| 92 server_url = kDefaultVariationsServerURL; | 95 server_url = kDefaultVariationsServerURL; |
| 93 GURL url_as_gurl = GURL(server_url); | 96 GURL url_as_gurl = GURL(server_url); |
| 94 DCHECK(url_as_gurl.is_valid()); | 97 DCHECK(url_as_gurl.is_valid()); |
| 95 return url_as_gurl; | 98 return url_as_gurl; |
| 96 } | 99 } |
| 97 | 100 |
| 98 } // namespace | 101 } // namespace |
| 99 | 102 |
| 100 VariationsService::VariationsService() | 103 VariationsService::VariationsService() |
| 101 : variations_server_url_(GetVariationsServerURL()), | 104 : variations_server_url_(GetVariationsServerURL()), |
| 102 create_trials_from_seed_called_(false) { | 105 create_trials_from_seed_called_(false) { |
| 106 registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED, |
| 107 content::Source<UpgradeDetector>(UpgradeDetector::GetInstance())); |
| 103 } | 108 } |
| 104 | 109 |
| 105 VariationsService::~VariationsService() {} | 110 VariationsService::~VariationsService() {} |
| 106 | 111 |
| 107 bool VariationsService::CreateTrialsFromSeed(PrefService* local_prefs) { | 112 bool VariationsService::CreateTrialsFromSeed(PrefService* local_prefs) { |
| 108 create_trials_from_seed_called_ = true; | 113 create_trials_from_seed_called_ = true; |
| 109 | 114 |
| 110 TrialsSeed seed; | 115 TrialsSeed seed; |
| 111 if (!LoadTrialsSeedFromPref(local_prefs, &seed)) | 116 if (!LoadTrialsSeedFromPref(local_prefs, &seed)) |
| 112 return false; | 117 return false; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 126 | 131 |
| 127 for (int i = 0; i < seed.study_size(); ++i) { | 132 for (int i = 0; i < seed.study_size(); ++i) { |
| 128 if (ShouldAddStudy(seed.study(i), current_version_info, reference_date)) | 133 if (ShouldAddStudy(seed.study(i), current_version_info, reference_date)) |
| 129 CreateTrialFromStudy(seed.study(i), reference_date); | 134 CreateTrialFromStudy(seed.study(i), reference_date); |
| 130 } | 135 } |
| 131 | 136 |
| 132 return true; | 137 return true; |
| 133 } | 138 } |
| 134 | 139 |
| 135 void VariationsService::StartRepeatedVariationsSeedFetch() { | 140 void VariationsService::StartRepeatedVariationsSeedFetch() { |
| 136 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 141 DCHECK(CalledOnValidThread()); |
| 137 | 142 |
| 138 // Check that |CreateTrialsFromSeed| was called, which is necessary to | 143 // Check that |CreateTrialsFromSeed| was called, which is necessary to |
| 139 // retrieve the serial number that will be sent to the server. | 144 // retrieve the serial number that will be sent to the server. |
| 140 DCHECK(create_trials_from_seed_called_); | 145 DCHECK(create_trials_from_seed_called_); |
| 141 | 146 |
| 142 // Perform the first fetch. | 147 // Perform the first fetch. |
| 143 FetchVariationsSeed(); | 148 FetchVariationsSeed(); |
| 144 | 149 |
| 145 // Repeat this periodically. | 150 // Repeat this periodically. |
| 146 timer_.Start(FROM_HERE, base::TimeDelta::FromHours(kSeedFetchPeriodHours), | 151 timer_.Start(FROM_HERE, base::TimeDelta::FromHours(kSeedFetchPeriodHours), |
| 147 this, &VariationsService::FetchVariationsSeed); | 152 this, &VariationsService::FetchVariationsSeed); |
| 148 } | 153 } |
| 149 | 154 |
| 155 // static |
| 156 void VariationsService::RegisterPrefs(PrefService* prefs) { |
| 157 prefs->RegisterStringPref(prefs::kVariationsSeed, std::string()); |
| 158 prefs->RegisterInt64Pref(prefs::kVariationsSeedDate, |
| 159 base::Time().ToInternalValue()); |
| 160 } |
| 161 |
| 150 void VariationsService::FetchVariationsSeed() { | 162 void VariationsService::FetchVariationsSeed() { |
| 151 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 163 DCHECK(CalledOnValidThread()); |
| 152 | 164 |
| 153 const bool is_offline = net::NetworkChangeNotifier::IsOffline(); | 165 const bool is_offline = net::NetworkChangeNotifier::IsOffline(); |
| 154 UMA_HISTOGRAM_BOOLEAN("Variations.NetworkAvailability", !is_offline); | 166 UMA_HISTOGRAM_BOOLEAN("Variations.NetworkAvailability", !is_offline); |
| 155 if (is_offline) { | 167 if (is_offline) { |
| 156 DVLOG(1) << "Network was offline."; | 168 DVLOG(1) << "Network was offline."; |
| 157 return; | 169 return; |
| 158 } | 170 } |
| 159 | 171 |
| 160 pending_seed_request_.reset(net::URLFetcher::Create( | 172 pending_seed_request_.reset(net::URLFetcher::Create( |
| 161 variations_server_url_, net::URLFetcher::GET, this)); | 173 variations_server_url_, net::URLFetcher::GET, this)); |
| 162 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 174 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 163 net::LOAD_DO_NOT_SAVE_COOKIES); | 175 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 164 pending_seed_request_->SetRequestContext( | 176 pending_seed_request_->SetRequestContext( |
| 165 g_browser_process->system_request_context()); | 177 g_browser_process->system_request_context()); |
| 166 pending_seed_request_->SetMaxRetries(kMaxRetrySeedFetch); | 178 pending_seed_request_->SetMaxRetries(kMaxRetrySeedFetch); |
| 167 if (!variations_serial_number_.empty()) { | 179 if (!variations_serial_number_.empty()) { |
| 168 pending_seed_request_->AddExtraRequestHeader("If-Match:" + | 180 pending_seed_request_->AddExtraRequestHeader("If-Match:" + |
| 169 variations_serial_number_); | 181 variations_serial_number_); |
| 170 } | 182 } |
| 171 pending_seed_request_->Start(); | 183 pending_seed_request_->Start(); |
| 172 } | 184 } |
| 173 | 185 |
| 186 void VariationsService::Observe(int type, |
| 187 const content::NotificationSource& source, |
| 188 const content::NotificationDetails& details) { |
| 189 DCHECK(CalledOnValidThread()); |
| 190 DCHECK_EQ(chrome::NOTIFICATION_UPGRADE_RECOMMENDED, type); |
| 191 |
| 192 // An upgrade is ready, so attempt to fetch the Variations seed in case there |
| 193 // were updates. |
| 194 FetchVariationsSeed(); |
| 195 |
| 196 // Since we explicitly call FetchVariationsSeed here, we can reset the timer |
| 197 // so that we don't retry for another full period. |
| 198 if (timer_.IsRunning()) |
| 199 timer_.Reset(); |
| 200 } |
| 201 |
| 174 void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) { | 202 void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) { |
| 175 DCHECK_EQ(pending_seed_request_.get(), source); | 203 DCHECK_EQ(pending_seed_request_.get(), source); |
| 176 // When we're done handling the request, the fetcher will be deleted. | 204 // When we're done handling the request, the fetcher will be deleted. |
| 177 scoped_ptr<const net::URLFetcher> request( | 205 scoped_ptr<const net::URLFetcher> request( |
| 178 pending_seed_request_.release()); | 206 pending_seed_request_.release()); |
| 179 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS) { | 207 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS) { |
| 180 DVLOG(1) << "Variations server request failed."; | 208 DVLOG(1) << "Variations server request failed."; |
| 181 return; | 209 return; |
| 182 } | 210 } |
| 183 | 211 |
| 184 if (request->GetResponseCode() != 200) { | 212 if (request->GetResponseCode() != 200) { |
| 185 DVLOG(1) << "Variations server request returned non-200 response code: " | 213 DVLOG(1) << "Variations server request returned non-200 response code: " |
| 186 << request->GetResponseCode(); | 214 << request->GetResponseCode(); |
| 187 return; | 215 return; |
| 188 } | 216 } |
| 189 | 217 |
| 190 std::string seed_data; | 218 std::string seed_data; |
| 191 bool success = request->GetResponseAsString(&seed_data); | 219 bool success = request->GetResponseAsString(&seed_data); |
| 192 DCHECK(success); | 220 DCHECK(success); |
| 193 | 221 |
| 194 base::Time response_date; | 222 base::Time response_date; |
| 195 success = request->GetResponseHeaders()->GetDateValue(&response_date); | 223 success = request->GetResponseHeaders()->GetDateValue(&response_date); |
| 196 DCHECK(success || response_date.is_null()); | 224 DCHECK(success || response_date.is_null()); |
| 197 | 225 |
| 198 StoreSeedData(seed_data, response_date, g_browser_process->local_state()); | 226 StoreSeedData(seed_data, response_date, g_browser_process->local_state()); |
| 199 } | 227 } |
| 200 | 228 |
| 201 // static | |
| 202 void VariationsService::RegisterPrefs(PrefService* prefs) { | |
| 203 prefs->RegisterStringPref(prefs::kVariationsSeed, std::string()); | |
| 204 prefs->RegisterInt64Pref(prefs::kVariationsSeedDate, | |
| 205 base::Time().ToInternalValue()); | |
| 206 } | |
| 207 | |
| 208 bool VariationsService::StoreSeedData(const std::string& seed_data, | 229 bool VariationsService::StoreSeedData(const std::string& seed_data, |
| 209 const base::Time& seed_date, | 230 const base::Time& seed_date, |
| 210 PrefService* local_prefs) { | 231 PrefService* local_prefs) { |
| 211 // Only store the seed data if it parses correctly. | 232 // Only store the seed data if it parses correctly. |
| 212 TrialsSeed seed; | 233 TrialsSeed seed; |
| 213 if (!seed.ParseFromString(seed_data)) { | 234 if (!seed.ParseFromString(seed_data)) { |
| 214 VLOG(1) << "Variations Seed data from server is not in valid proto format, " | 235 VLOG(1) << "Variations Seed data from server is not in valid proto format, " |
| 215 << "rejecting the seed."; | 236 << "rejecting the seed."; |
| 216 return false; | 237 return false; |
| 217 } | 238 } |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 variation_id); | 485 variation_id); |
| 465 } | 486 } |
| 466 } | 487 } |
| 467 | 488 |
| 468 trial->SetForced(); | 489 trial->SetForced(); |
| 469 if (IsStudyExpired(study, reference_date)) | 490 if (IsStudyExpired(study, reference_date)) |
| 470 trial->Disable(); | 491 trial->Disable(); |
| 471 } | 492 } |
| 472 | 493 |
| 473 } // namespace chrome_variations | 494 } // namespace chrome_variations |
| OLD | NEW |