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/variations_service.h" | 5 #include "chrome/browser/metrics/variations/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" | |
| 15 #include "base/version.h" | 14 #include "base/version.h" |
| 16 #include "chrome/browser/browser_process.h" | 15 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/metrics/proto/trials_seed.pb.h" | 16 #include "chrome/browser/metrics/proto/trials_seed.pb.h" |
| 18 #include "chrome/browser/prefs/pref_service.h" | 17 #include "chrome/browser/prefs/pref_service.h" |
| 19 #include "chrome/common/chrome_switches.h" | 18 #include "chrome/common/chrome_switches.h" |
| 20 #include "chrome/common/metrics/variations/variations_util.h" | 19 #include "chrome/common/metrics/variations/variations_util.h" |
| 21 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
| 22 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
| 23 #include "content/public/common/url_fetcher.h" | 22 #include "content/public/common/url_fetcher.h" |
| 24 #include "googleurl/src/gurl.h" | 23 #include "googleurl/src/gurl.h" |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 91 if (server_url.empty()) | 90 if (server_url.empty()) |
| 92 server_url = kDefaultVariationsServerURL; | 91 server_url = kDefaultVariationsServerURL; |
| 93 GURL url_as_gurl = GURL(server_url); | 92 GURL url_as_gurl = GURL(server_url); |
| 94 DCHECK(url_as_gurl.is_valid()); | 93 DCHECK(url_as_gurl.is_valid()); |
| 95 return url_as_gurl; | 94 return url_as_gurl; |
| 96 } | 95 } |
| 97 | 96 |
| 98 } // namespace | 97 } // namespace |
| 99 | 98 |
| 100 VariationsService::VariationsService() | 99 VariationsService::VariationsService() |
| 101 : variations_server_url_(GetVariationsServerURL()), | 100 : create_trials_from_seed_called_(false), |
| 102 create_trials_from_seed_called_(false), | 101 variations_server_url_(GetVariationsServerURL()), |
| 103 was_offline_during_last_request_attempt_(false) { | 102 resource_request_allowed_notifier_(new ResourceRequestAllowedNotifier) { |
| 104 net::NetworkChangeNotifier::AddConnectionTypeObserver(this); | 103 resource_request_allowed_notifier_->SetObserver(this); |
| 105 } | 104 } |
| 106 | 105 |
| 107 VariationsService::~VariationsService() { | 106 VariationsService::~VariationsService() { |
| 108 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | 107 resource_request_allowed_notifier_->ClearObserver(); |
| 109 } | 108 } |
| 110 | 109 |
| 111 bool VariationsService::CreateTrialsFromSeed(PrefService* local_prefs) { | 110 bool VariationsService::CreateTrialsFromSeed(PrefService* local_prefs) { |
| 112 create_trials_from_seed_called_ = true; | 111 create_trials_from_seed_called_ = true; |
| 113 | 112 |
| 114 TrialsSeed seed; | 113 TrialsSeed seed; |
| 115 if (!LoadTrialsSeedFromPref(local_prefs, &seed)) | 114 if (!LoadTrialsSeedFromPref(local_prefs, &seed)) |
| 116 return false; | 115 return false; |
| 117 | 116 |
| 118 const int64 date_value = local_prefs->GetInt64(prefs::kVariationsSeedDate); | 117 const int64 date_value = local_prefs->GetInt64(prefs::kVariationsSeedDate); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 147 FetchVariationsSeed(); | 146 FetchVariationsSeed(); |
| 148 | 147 |
| 149 // Repeat this periodically. | 148 // Repeat this periodically. |
| 150 timer_.Start(FROM_HERE, base::TimeDelta::FromHours(kSeedFetchPeriodHours), | 149 timer_.Start(FROM_HERE, base::TimeDelta::FromHours(kSeedFetchPeriodHours), |
| 151 this, &VariationsService::FetchVariationsSeed); | 150 this, &VariationsService::FetchVariationsSeed); |
| 152 } | 151 } |
| 153 | 152 |
| 154 void VariationsService::FetchVariationsSeed() { | 153 void VariationsService::FetchVariationsSeed() { |
| 155 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 154 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 156 | 155 |
| 157 was_offline_during_last_request_attempt_ = | 156 if (!resource_request_allowed_notifier_->ResourceRequestsAllowed()) { |
| 158 net::NetworkChangeNotifier::IsOffline(); | 157 DVLOG(1) << "Resource requests were not allowed. Waiting for notification."; |
| 159 UMA_HISTOGRAM_BOOLEAN("Variations.NetworkAvailability", | |
| 160 !was_offline_during_last_request_attempt_); | |
| 161 if (was_offline_during_last_request_attempt_) { | |
| 162 DVLOG(1) << "Network was offline."; | |
| 163 return; | 158 return; |
| 164 } | 159 } |
| 165 | 160 |
| 161 DoActualFetch(); | |
| 162 } | |
| 163 | |
| 164 // static | |
| 165 void VariationsService::RegisterPrefs(PrefService* prefs) { | |
| 166 prefs->RegisterStringPref(prefs::kVariationsSeed, std::string()); | |
| 167 prefs->RegisterInt64Pref(prefs::kVariationsSeedDate, | |
| 168 base::Time().ToInternalValue()); | |
| 169 } | |
| 170 | |
| 171 void VariationsService::DoActualFetch() { | |
| 166 pending_seed_request_.reset(net::URLFetcher::Create( | 172 pending_seed_request_.reset(net::URLFetcher::Create( |
| 167 variations_server_url_, net::URLFetcher::GET, this)); | 173 variations_server_url_, net::URLFetcher::GET, this)); |
| 168 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 174 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 169 net::LOAD_DO_NOT_SAVE_COOKIES); | 175 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 170 pending_seed_request_->SetRequestContext( | 176 pending_seed_request_->SetRequestContext( |
| 171 g_browser_process->system_request_context()); | 177 g_browser_process->system_request_context()); |
| 172 pending_seed_request_->SetMaxRetries(kMaxRetrySeedFetch); | 178 pending_seed_request_->SetMaxRetries(kMaxRetrySeedFetch); |
| 173 if (!variations_serial_number_.empty()) { | 179 if (!variations_serial_number_.empty()) { |
| 174 pending_seed_request_->AddExtraRequestHeader("If-Match:" + | 180 pending_seed_request_->AddExtraRequestHeader("If-Match:" + |
| 175 variations_serial_number_); | 181 variations_serial_number_); |
| 176 } | 182 } |
| 177 pending_seed_request_->Start(); | 183 pending_seed_request_->Start(); |
| 178 } | 184 } |
| 179 | 185 |
| 180 void VariationsService::SetWasOfflineDuringLastRequestAttemptForTesting( | 186 void VariationsService::SetResourceRequestAllowedNotifierForTesting( |
| 181 bool offline) { | 187 ResourceRequestAllowedNotifier* notifier) { |
| 182 was_offline_during_last_request_attempt_ = offline; | 188 DCHECK(notifier); |
| 183 } | 189 resource_request_allowed_notifier_->ClearObserver(); |
|
Alexei Svitkine (slow)
2012/09/19 19:44:28
The destructor of the notifier should do the sane
SteveT
2012/09/20 19:40:18
This is no longer applicable.
| |
| 184 | 190 resource_request_allowed_notifier_.reset(notifier); |
| 185 // static | 191 notifier->SetObserver(this); |
| 186 void VariationsService::RegisterPrefs(PrefService* prefs) { | |
| 187 prefs->RegisterStringPref(prefs::kVariationsSeed, std::string()); | |
| 188 prefs->RegisterInt64Pref(prefs::kVariationsSeedDate, | |
| 189 base::Time().ToInternalValue()); | |
| 190 } | 192 } |
| 191 | 193 |
| 192 void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) { | 194 void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) { |
| 193 DCHECK_EQ(pending_seed_request_.get(), source); | 195 DCHECK_EQ(pending_seed_request_.get(), source); |
| 194 // The fetcher will be deleted when the request is handled. | 196 // The fetcher will be deleted when the request is handled. |
| 195 scoped_ptr<const net::URLFetcher> request( | 197 scoped_ptr<const net::URLFetcher> request( |
| 196 pending_seed_request_.release()); | 198 pending_seed_request_.release()); |
| 197 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS) { | 199 if (request->GetStatus().status() != net::URLRequestStatus::SUCCESS) { |
| 198 DVLOG(1) << "Variations server request failed."; | 200 DVLOG(1) << "Variations server request failed."; |
| 199 return; | 201 return; |
| 200 } | 202 } |
| 201 | 203 |
| 202 if (request->GetResponseCode() != 200) { | 204 if (request->GetResponseCode() != 200) { |
| 203 DVLOG(1) << "Variations server request returned non-200 response code: " | 205 DVLOG(1) << "Variations server request returned non-200 response code: " |
| 204 << request->GetResponseCode(); | 206 << request->GetResponseCode(); |
| 205 return; | 207 return; |
| 206 } | 208 } |
| 207 | 209 |
| 208 std::string seed_data; | 210 std::string seed_data; |
| 209 bool success = request->GetResponseAsString(&seed_data); | 211 bool success = request->GetResponseAsString(&seed_data); |
| 210 DCHECK(success); | 212 DCHECK(success); |
| 211 | 213 |
| 212 base::Time response_date; | 214 base::Time response_date; |
| 213 success = request->GetResponseHeaders()->GetDateValue(&response_date); | 215 success = request->GetResponseHeaders()->GetDateValue(&response_date); |
| 214 DCHECK(success || response_date.is_null()); | 216 DCHECK(success || response_date.is_null()); |
| 215 | 217 |
| 216 StoreSeedData(seed_data, response_date, g_browser_process->local_state()); | 218 StoreSeedData(seed_data, response_date, g_browser_process->local_state()); |
| 217 } | 219 } |
| 218 | 220 |
| 219 void VariationsService::OnConnectionTypeChanged( | 221 void VariationsService::OnResourceRequestsAllowed() { |
| 220 net::NetworkChangeNotifier::ConnectionType type) { | 222 // Note that this only attempts to fetch the seed at most once per period |
| 221 // If the connection type is back online, start a request if the last request | 223 // (kSeedFetchPeriodHours). This works because |
| 222 // failed due to being offline. | 224 // |resource_request_allowed_notifier_| only calls this method if an |
| 223 if (was_offline_during_last_request_attempt_ && | 225 // attempt was made earlier that fails (which implies that the period had |
| 224 type != net::NetworkChangeNotifier::CONNECTION_NONE) { | 226 // elapsed). After a successful attempt is made, the notifier will know not |
| 225 VLOG(1) << "Retrying fetch due to network reconnect."; | 227 // to call this method again until another failed attempt occurs. |
| 226 FetchVariationsSeed(); | 228 DVLOG(1) << "Retrying fetch."; |
| 227 | 229 FetchVariationsSeed(); |
| 228 // Since FetchVariationsSeed was explicitly called here, reset the timer to | 230 if (timer_.IsRunning()) |
| 229 // avoid retrying for a full period. | 231 timer_.Reset(); |
| 230 // net::NetworkChangeNotifier::IsOffline may be inconsistent with |type|, so | |
| 231 // we check if FetchVariationsSeed set | |
| 232 // |was_offline_during_last_request_attempt_| to true before we reset the | |
| 233 // timer. | |
| 234 if (!was_offline_during_last_request_attempt_ && timer_.IsRunning()) | |
| 235 timer_.Reset(); | |
| 236 } | |
| 237 } | 232 } |
| 238 | 233 |
| 239 bool VariationsService::StoreSeedData(const std::string& seed_data, | 234 bool VariationsService::StoreSeedData(const std::string& seed_data, |
| 240 const base::Time& seed_date, | 235 const base::Time& seed_date, |
| 241 PrefService* local_prefs) { | 236 PrefService* local_prefs) { |
| 242 // Only store the seed data if it parses correctly. | 237 // Only store the seed data if it parses correctly. |
| 243 TrialsSeed seed; | 238 TrialsSeed seed; |
| 244 if (!seed.ParseFromString(seed_data)) { | 239 if (!seed.ParseFromString(seed_data)) { |
| 245 VLOG(1) << "Variations Seed data from server is not in valid proto format, " | 240 VLOG(1) << "Variations Seed data from server is not in valid proto format, " |
| 246 << "rejecting the seed."; | 241 << "rejecting the seed."; |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 495 variation_id); | 490 variation_id); |
| 496 } | 491 } |
| 497 } | 492 } |
| 498 | 493 |
| 499 trial->SetForced(); | 494 trial->SetForced(); |
| 500 if (IsStudyExpired(study, reference_date)) | 495 if (IsStudyExpired(study, reference_date)) |
| 501 trial->Disable(); | 496 trial->Disable(); |
| 502 } | 497 } |
| 503 | 498 |
| 504 } // namespace chrome_variations | 499 } // namespace chrome_variations |
| OLD | NEW |