| 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 |