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 "base/build_time.h" | 7 #include "base/build_time.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/metrics/sparse_histogram.h" | 10 #include "base/metrics/sparse_histogram.h" |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 const base::Time seed_date = base::Time::FromInternalValue(date_value); | 213 const base::Time seed_date = base::Time::FromInternalValue(date_value); |
214 const base::Time build_time = base::GetBuildTime(); | 214 const base::Time build_time = base::GetBuildTime(); |
215 // Use the build time for date checks if either the seed date is invalid or | 215 // Use the build time for date checks if either the seed date is invalid or |
216 // the build time is newer than the seed date. | 216 // the build time is newer than the seed date. |
217 base::Time reference_date = seed_date; | 217 base::Time reference_date = seed_date; |
218 if (seed_date.is_null() || seed_date < build_time) | 218 if (seed_date.is_null() || seed_date < build_time) |
219 reference_date = build_time; | 219 reference_date = build_time; |
220 return reference_date; | 220 return reference_date; |
221 } | 221 } |
222 | 222 |
| 223 // Returns the header value for |name| from |headers| or an empty string if not |
| 224 // set. |
| 225 std::string GetHeaderValue(const net::HttpResponseHeaders* headers, |
| 226 const base::StringPiece& name) { |
| 227 std::string value; |
| 228 headers->EnumerateHeader(NULL, name, &value); |
| 229 return value; |
| 230 } |
| 231 |
223 // Overrides the string resource sepecified by |hash| with |string| in the | 232 // Overrides the string resource sepecified by |hash| with |string| in the |
224 // resource bundle. Used as a callback passed to the variations seed processor. | 233 // resource bundle. Used as a callback passed to the variations seed processor. |
225 void OverrideUIString(uint32_t hash, const base::string16& string) { | 234 void OverrideUIString(uint32_t hash, const base::string16& string) { |
226 int resource_id = GetResourceIndex(hash); | 235 int resource_id = GetResourceIndex(hash); |
227 if (resource_id == -1) | 236 if (resource_id == -1) |
228 return; | 237 return; |
229 | 238 |
230 ui::ResourceBundle::GetSharedInstance().OverrideLocaleStringResource( | 239 ui::ResourceBundle::GetSharedInstance().OverrideLocaleStringResource( |
231 resource_id, string); | 240 resource_id, string); |
232 } | 241 } |
233 | 242 |
234 } // namespace | 243 } // namespace |
235 | 244 |
236 VariationsService::VariationsService( | 245 VariationsService::VariationsService( |
237 web_resource::ResourceRequestAllowedNotifier* notifier, | 246 web_resource::ResourceRequestAllowedNotifier* notifier, |
238 PrefService* local_state, | 247 PrefService* local_state, |
239 metrics::MetricsStateManager* state_manager) | 248 metrics::MetricsStateManager* state_manager) |
240 : local_state_(local_state), | 249 : local_state_(local_state), |
241 state_manager_(state_manager), | 250 state_manager_(state_manager), |
242 policy_pref_service_(local_state), | 251 policy_pref_service_(local_state), |
243 seed_store_(local_state), | 252 seed_store_(local_state), |
244 create_trials_from_seed_called_(false), | 253 create_trials_from_seed_called_(false), |
245 initial_request_completed_(false), | 254 initial_request_completed_(false), |
| 255 disable_deltas_for_next_request_(false), |
246 resource_request_allowed_notifier_(notifier), | 256 resource_request_allowed_notifier_(notifier), |
247 request_count_(0), | 257 request_count_(0), |
248 weak_ptr_factory_(this) { | 258 weak_ptr_factory_(this) { |
249 resource_request_allowed_notifier_->Init(this); | 259 resource_request_allowed_notifier_->Init(this); |
250 } | 260 } |
251 | 261 |
252 VariationsService::~VariationsService() { | 262 VariationsService::~VariationsService() { |
253 } | 263 } |
254 | 264 |
255 bool VariationsService::CreateTrialsFromSeed() { | 265 bool VariationsService::CreateTrialsFromSeed() { |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 #endif | 464 #endif |
455 result.reset(new VariationsService( | 465 result.reset(new VariationsService( |
456 new web_resource::ResourceRequestAllowedNotifier( | 466 new web_resource::ResourceRequestAllowedNotifier( |
457 local_state, switches::kDisableBackgroundNetworking), | 467 local_state, switches::kDisableBackgroundNetworking), |
458 local_state, state_manager)); | 468 local_state, state_manager)); |
459 return result.Pass(); | 469 return result.Pass(); |
460 } | 470 } |
461 | 471 |
462 void VariationsService::DoActualFetch() { | 472 void VariationsService::DoActualFetch() { |
463 DCHECK(thread_checker_.CalledOnValidThread()); | 473 DCHECK(thread_checker_.CalledOnValidThread()); |
| 474 DCHECK(!pending_seed_request_); |
464 | 475 |
465 pending_seed_request_ = net::URLFetcher::Create(0, variations_server_url_, | 476 pending_seed_request_ = net::URLFetcher::Create(0, variations_server_url_, |
466 net::URLFetcher::GET, this); | 477 net::URLFetcher::GET, this); |
467 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 478 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
468 net::LOAD_DO_NOT_SAVE_COOKIES); | 479 net::LOAD_DO_NOT_SAVE_COOKIES); |
469 pending_seed_request_->SetRequestContext( | 480 pending_seed_request_->SetRequestContext( |
470 g_browser_process->system_request_context()); | 481 g_browser_process->system_request_context()); |
471 pending_seed_request_->SetMaxRetriesOn5xx(kMaxRetrySeedFetch); | 482 pending_seed_request_->SetMaxRetriesOn5xx(kMaxRetrySeedFetch); |
472 if (!seed_store_.variations_serial_number().empty()) { | 483 if (!seed_store_.variations_serial_number().empty() && |
| 484 !disable_deltas_for_next_request_) { |
| 485 // If the current seed includes a country code, deltas are not supported (as |
| 486 // the serial number doesn't take into account the country code). The server |
| 487 // will update us with a seed that doesn't include a country code which will |
| 488 // enable deltas to work. |
| 489 // TODO(asvitkine): Remove the check in M50+ when the percentage of clients |
| 490 // that have an old seed with a country code becomes miniscule. |
| 491 if (!seed_store_.seed_has_country_code()) { |
| 492 // Tell the server that delta-compressed seeds are supported. |
| 493 pending_seed_request_->AddExtraRequestHeader("A-IM:x-bm"); |
| 494 } |
| 495 // Get the seed only if its serial number doesn't match what we have. |
473 pending_seed_request_->AddExtraRequestHeader( | 496 pending_seed_request_->AddExtraRequestHeader( |
474 "If-Match:" + seed_store_.variations_serial_number()); | 497 "If-None-Match:" + seed_store_.variations_serial_number()); |
475 } | 498 } |
476 pending_seed_request_->Start(); | 499 pending_seed_request_->Start(); |
477 | 500 |
478 const base::TimeTicks now = base::TimeTicks::Now(); | 501 const base::TimeTicks now = base::TimeTicks::Now(); |
479 base::TimeDelta time_since_last_fetch; | 502 base::TimeDelta time_since_last_fetch; |
480 // Record a time delta of 0 (default value) if there was no previous fetch. | 503 // Record a time delta of 0 (default value) if there was no previous fetch. |
481 if (!last_request_started_time_.is_null()) | 504 if (!last_request_started_time_.is_null()) |
482 time_since_last_fetch = now - last_request_started_time_; | 505 time_since_last_fetch = now - last_request_started_time_; |
483 UMA_HISTOGRAM_CUSTOM_COUNTS("Variations.TimeSinceLastFetchAttempt", | 506 UMA_HISTOGRAM_CUSTOM_COUNTS("Variations.TimeSinceLastFetchAttempt", |
484 time_since_last_fetch.InMinutes(), 0, | 507 time_since_last_fetch.InMinutes(), 0, |
485 base::TimeDelta::FromDays(7).InMinutes(), 50); | 508 base::TimeDelta::FromDays(7).InMinutes(), 50); |
486 UMA_HISTOGRAM_COUNTS_100("Variations.RequestCount", request_count_); | 509 UMA_HISTOGRAM_COUNTS_100("Variations.RequestCount", request_count_); |
487 ++request_count_; | 510 ++request_count_; |
488 last_request_started_time_ = now; | 511 last_request_started_time_ = now; |
| 512 disable_deltas_for_next_request_ = false; |
489 } | 513 } |
490 | 514 |
491 void VariationsService::StoreSeed(const std::string& seed_data, | 515 bool VariationsService::StoreSeed(const std::string& seed_data, |
492 const std::string& seed_signature, | 516 const std::string& seed_signature, |
493 const base::Time& date_fetched) { | 517 const std::string& country_code, |
| 518 const base::Time& date_fetched, |
| 519 bool is_delta_compressed) { |
494 DCHECK(thread_checker_.CalledOnValidThread()); | 520 DCHECK(thread_checker_.CalledOnValidThread()); |
495 | 521 |
496 scoped_ptr<variations::VariationsSeed> seed(new variations::VariationsSeed); | 522 scoped_ptr<variations::VariationsSeed> seed(new variations::VariationsSeed); |
497 if (!seed_store_.StoreSeedData(seed_data, seed_signature, date_fetched, | 523 if (!seed_store_.StoreSeedData(seed_data, seed_signature, country_code, |
| 524 date_fetched, is_delta_compressed, |
498 seed.get())) { | 525 seed.get())) { |
499 return; | 526 return false; |
500 } | 527 } |
501 RecordLastFetchTime(); | 528 RecordLastFetchTime(); |
502 | 529 |
503 // Perform seed simulation only if |state_manager_| is not-NULL. The state | 530 // Perform seed simulation only if |state_manager_| is not-NULL. The state |
504 // manager may be NULL for some unit tests. | 531 // manager may be NULL for some unit tests. |
505 if (!state_manager_) | 532 if (!state_manager_) |
506 return; | 533 return true; |
507 | 534 |
508 base::PostTaskAndReplyWithResult( | 535 base::PostTaskAndReplyWithResult( |
509 content::BrowserThread::GetBlockingPool(), | 536 content::BrowserThread::GetBlockingPool(), |
510 FROM_HERE, | 537 FROM_HERE, |
511 base::Bind(&GetVersionForSimulation), | 538 base::Bind(&GetVersionForSimulation), |
512 base::Bind(&VariationsService::PerformSimulationWithVersion, | 539 base::Bind(&VariationsService::PerformSimulationWithVersion, |
513 weak_ptr_factory_.GetWeakPtr(), base::Passed(&seed))); | 540 weak_ptr_factory_.GetWeakPtr(), base::Passed(&seed))); |
| 541 return true; |
514 } | 542 } |
515 | 543 |
516 void VariationsService::FetchVariationsSeed() { | 544 void VariationsService::FetchVariationsSeed() { |
517 DCHECK(thread_checker_.CalledOnValidThread()); | 545 DCHECK(thread_checker_.CalledOnValidThread()); |
518 | 546 |
519 const web_resource::ResourceRequestAllowedNotifier::State state = | 547 const web_resource::ResourceRequestAllowedNotifier::State state = |
520 resource_request_allowed_notifier_->GetResourceRequestsAllowedState(); | 548 resource_request_allowed_notifier_->GetResourceRequestsAllowedState(); |
521 RecordRequestsAllowedHistogram(ResourceRequestStateToHistogramValue(state)); | 549 RecordRequestsAllowedHistogram(ResourceRequestStateToHistogramValue(state)); |
522 if (state != web_resource::ResourceRequestAllowedNotifier::ALLOWED) { | 550 if (state != web_resource::ResourceRequestAllowedNotifier::ALLOWED) { |
523 DVLOG(1) << "Resource requests were not allowed. Waiting for notification."; | 551 DVLOG(1) << "Resource requests were not allowed. Waiting for notification."; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 // next start up), since 304 is a successful response. | 624 // next start up), since 304 is a successful response. |
597 seed_store_.UpdateSeedDateAndLogDayChange(response_date); | 625 seed_store_.UpdateSeedDateAndLogDayChange(response_date); |
598 } | 626 } |
599 return; | 627 return; |
600 } | 628 } |
601 | 629 |
602 std::string seed_data; | 630 std::string seed_data; |
603 bool success = request->GetResponseAsString(&seed_data); | 631 bool success = request->GetResponseAsString(&seed_data); |
604 DCHECK(success); | 632 DCHECK(success); |
605 | 633 |
606 std::string seed_signature; | 634 net::HttpResponseHeaders* headers = request->GetResponseHeaders(); |
607 request->GetResponseHeaders()->EnumerateHeader(NULL, | 635 const std::string signature = GetHeaderValue(headers, "X-Seed-Signature"); |
608 "X-Seed-Signature", | 636 const std::string country_code = GetHeaderValue(headers, "X-Country"); |
609 &seed_signature); | 637 const bool is_delta_compressed = (GetHeaderValue(headers, "IM") == "x-bm"); |
610 StoreSeed(seed_data, seed_signature, response_date); | 638 const bool store_success = StoreSeed(seed_data, signature, country_code, |
| 639 response_date, is_delta_compressed); |
| 640 if (!store_success && is_delta_compressed) { |
| 641 disable_deltas_for_next_request_ = true; |
| 642 request_scheduler_->ScheduleFetchShortly(); |
| 643 } |
611 } | 644 } |
612 | 645 |
613 void VariationsService::OnResourceRequestsAllowed() { | 646 void VariationsService::OnResourceRequestsAllowed() { |
614 DCHECK(thread_checker_.CalledOnValidThread()); | 647 DCHECK(thread_checker_.CalledOnValidThread()); |
615 | 648 |
616 // Note that this only attempts to fetch the seed at most once per period | 649 // Note that this only attempts to fetch the seed at most once per period |
617 // (kSeedFetchPeriodHours). This works because | 650 // (kSeedFetchPeriodHours). This works because |
618 // |resource_request_allowed_notifier_| only calls this method if an | 651 // |resource_request_allowed_notifier_| only calls this method if an |
619 // attempt was made earlier that fails (which implies that the period had | 652 // attempt was made earlier that fails (which implies that the period had |
620 // elapsed). After a successful attempt is made, the notifier will know not | 653 // elapsed). After a successful attempt is made, the notifier will know not |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 // Otherwise, update the pref with the current Chrome version and country. | 778 // Otherwise, update the pref with the current Chrome version and country. |
746 base::ListValue new_list_value; | 779 base::ListValue new_list_value; |
747 new_list_value.AppendString(version.GetString()); | 780 new_list_value.AppendString(version.GetString()); |
748 new_list_value.AppendString(latest_country); | 781 new_list_value.AppendString(latest_country); |
749 local_state_->Set(prefs::kVariationsPermanentConsistencyCountry, | 782 local_state_->Set(prefs::kVariationsPermanentConsistencyCountry, |
750 new_list_value); | 783 new_list_value); |
751 return latest_country; | 784 return latest_country; |
752 } | 785 } |
753 | 786 |
754 } // namespace chrome_variations | 787 } // namespace chrome_variations |
OLD | NEW |