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 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 #endif | 463 #endif |
454 result.reset(new VariationsService( | 464 result.reset(new VariationsService( |
455 new web_resource::ResourceRequestAllowedNotifier( | 465 new web_resource::ResourceRequestAllowedNotifier( |
456 local_state, switches::kDisableBackgroundNetworking), | 466 local_state, switches::kDisableBackgroundNetworking), |
457 local_state, state_manager)); | 467 local_state, state_manager)); |
458 return result.Pass(); | 468 return result.Pass(); |
459 } | 469 } |
460 | 470 |
461 void VariationsService::DoActualFetch() { | 471 void VariationsService::DoActualFetch() { |
462 DCHECK(thread_checker_.CalledOnValidThread()); | 472 DCHECK(thread_checker_.CalledOnValidThread()); |
| 473 DCHECK(!pending_seed_request_); |
463 | 474 |
464 pending_seed_request_ = net::URLFetcher::Create(0, variations_server_url_, | 475 pending_seed_request_ = net::URLFetcher::Create(0, variations_server_url_, |
465 net::URLFetcher::GET, this); | 476 net::URLFetcher::GET, this); |
466 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 477 pending_seed_request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
467 net::LOAD_DO_NOT_SAVE_COOKIES); | 478 net::LOAD_DO_NOT_SAVE_COOKIES); |
468 pending_seed_request_->SetRequestContext( | 479 pending_seed_request_->SetRequestContext( |
469 g_browser_process->system_request_context()); | 480 g_browser_process->system_request_context()); |
470 pending_seed_request_->SetMaxRetriesOn5xx(kMaxRetrySeedFetch); | 481 pending_seed_request_->SetMaxRetriesOn5xx(kMaxRetrySeedFetch); |
471 if (!seed_store_.variations_serial_number().empty()) { | 482 if (!seed_store_.variations_serial_number().empty() && |
| 483 !disable_deltas_for_next_request_) { |
| 484 // If the current seed includes a country code, deltas are not supported (as |
| 485 // the serial number doesn't take into account the country code). The server |
| 486 // will update us with a seed that doesn't include a country code which will |
| 487 // enable deltas to work. |
| 488 // TODO(asvitkine): Remove the check in M50+ when the percentage of clients |
| 489 // that have an old seed with a country code becomes miniscule. |
| 490 if (!seed_store_.seed_has_country_code()) { |
| 491 // Tell the server that delta-compressed seeds are supported. |
| 492 pending_seed_request_->AddExtraRequestHeader("A-IM:x-bm"); |
| 493 } |
| 494 // Get the seed only if its serial number doesn't match what we have. |
472 pending_seed_request_->AddExtraRequestHeader( | 495 pending_seed_request_->AddExtraRequestHeader( |
473 "If-Match:" + seed_store_.variations_serial_number()); | 496 "If-None-Match:" + seed_store_.variations_serial_number()); |
474 } | 497 } |
475 pending_seed_request_->Start(); | 498 pending_seed_request_->Start(); |
476 | 499 |
477 const base::TimeTicks now = base::TimeTicks::Now(); | 500 const base::TimeTicks now = base::TimeTicks::Now(); |
478 base::TimeDelta time_since_last_fetch; | 501 base::TimeDelta time_since_last_fetch; |
479 // Record a time delta of 0 (default value) if there was no previous fetch. | 502 // Record a time delta of 0 (default value) if there was no previous fetch. |
480 if (!last_request_started_time_.is_null()) | 503 if (!last_request_started_time_.is_null()) |
481 time_since_last_fetch = now - last_request_started_time_; | 504 time_since_last_fetch = now - last_request_started_time_; |
482 UMA_HISTOGRAM_CUSTOM_COUNTS("Variations.TimeSinceLastFetchAttempt", | 505 UMA_HISTOGRAM_CUSTOM_COUNTS("Variations.TimeSinceLastFetchAttempt", |
483 time_since_last_fetch.InMinutes(), 0, | 506 time_since_last_fetch.InMinutes(), 0, |
484 base::TimeDelta::FromDays(7).InMinutes(), 50); | 507 base::TimeDelta::FromDays(7).InMinutes(), 50); |
485 UMA_HISTOGRAM_COUNTS_100("Variations.RequestCount", request_count_); | 508 UMA_HISTOGRAM_COUNTS_100("Variations.RequestCount", request_count_); |
486 ++request_count_; | 509 ++request_count_; |
487 last_request_started_time_ = now; | 510 last_request_started_time_ = now; |
| 511 disable_deltas_for_next_request_ = false; |
488 } | 512 } |
489 | 513 |
490 void VariationsService::StoreSeed(const std::string& seed_data, | 514 bool VariationsService::StoreSeed(const std::string& seed_data, |
491 const std::string& seed_signature, | 515 const std::string& seed_signature, |
492 const base::Time& date_fetched) { | 516 const std::string& country_code, |
| 517 const base::Time& date_fetched, |
| 518 bool is_delta_compressed) { |
493 DCHECK(thread_checker_.CalledOnValidThread()); | 519 DCHECK(thread_checker_.CalledOnValidThread()); |
494 | 520 |
495 scoped_ptr<variations::VariationsSeed> seed(new variations::VariationsSeed); | 521 scoped_ptr<variations::VariationsSeed> seed(new variations::VariationsSeed); |
496 if (!seed_store_.StoreSeedData(seed_data, seed_signature, date_fetched, | 522 if (!seed_store_.StoreSeedData(seed_data, seed_signature, country_code, |
| 523 date_fetched, is_delta_compressed, |
497 seed.get())) { | 524 seed.get())) { |
498 return; | 525 return false; |
499 } | 526 } |
500 RecordLastFetchTime(); | 527 RecordLastFetchTime(); |
501 | 528 |
502 // Perform seed simulation only if |state_manager_| is not-NULL. The state | 529 // Perform seed simulation only if |state_manager_| is not-NULL. The state |
503 // manager may be NULL for some unit tests. | 530 // manager may be NULL for some unit tests. |
504 if (!state_manager_) | 531 if (!state_manager_) |
505 return; | 532 return true; |
506 | 533 |
507 base::PostTaskAndReplyWithResult( | 534 base::PostTaskAndReplyWithResult( |
508 content::BrowserThread::GetBlockingPool(), | 535 content::BrowserThread::GetBlockingPool(), |
509 FROM_HERE, | 536 FROM_HERE, |
510 base::Bind(&GetVersionForSimulation), | 537 base::Bind(&GetVersionForSimulation), |
511 base::Bind(&VariationsService::PerformSimulationWithVersion, | 538 base::Bind(&VariationsService::PerformSimulationWithVersion, |
512 weak_ptr_factory_.GetWeakPtr(), base::Passed(&seed))); | 539 weak_ptr_factory_.GetWeakPtr(), base::Passed(&seed))); |
| 540 return true; |
513 } | 541 } |
514 | 542 |
515 void VariationsService::FetchVariationsSeed() { | 543 void VariationsService::FetchVariationsSeed() { |
516 DCHECK(thread_checker_.CalledOnValidThread()); | 544 DCHECK(thread_checker_.CalledOnValidThread()); |
517 | 545 |
518 const web_resource::ResourceRequestAllowedNotifier::State state = | 546 const web_resource::ResourceRequestAllowedNotifier::State state = |
519 resource_request_allowed_notifier_->GetResourceRequestsAllowedState(); | 547 resource_request_allowed_notifier_->GetResourceRequestsAllowedState(); |
520 RecordRequestsAllowedHistogram(ResourceRequestStateToHistogramValue(state)); | 548 RecordRequestsAllowedHistogram(ResourceRequestStateToHistogramValue(state)); |
521 if (state != web_resource::ResourceRequestAllowedNotifier::ALLOWED) { | 549 if (state != web_resource::ResourceRequestAllowedNotifier::ALLOWED) { |
522 DVLOG(1) << "Resource requests were not allowed. Waiting for notification."; | 550 DVLOG(1) << "Resource requests were not allowed. Waiting for notification."; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
595 // next start up), since 304 is a successful response. | 623 // next start up), since 304 is a successful response. |
596 seed_store_.UpdateSeedDateAndLogDayChange(response_date); | 624 seed_store_.UpdateSeedDateAndLogDayChange(response_date); |
597 } | 625 } |
598 return; | 626 return; |
599 } | 627 } |
600 | 628 |
601 std::string seed_data; | 629 std::string seed_data; |
602 bool success = request->GetResponseAsString(&seed_data); | 630 bool success = request->GetResponseAsString(&seed_data); |
603 DCHECK(success); | 631 DCHECK(success); |
604 | 632 |
605 std::string seed_signature; | 633 net::HttpResponseHeaders* headers = request->GetResponseHeaders(); |
606 request->GetResponseHeaders()->EnumerateHeader(NULL, | 634 const std::string signature = GetHeaderValue(headers, "X-Seed-Signature"); |
607 "X-Seed-Signature", | 635 const std::string country_code = GetHeaderValue(headers, "X-Country"); |
608 &seed_signature); | 636 const bool is_delta_compressed = (GetHeaderValue(headers, "IM") == "x-bm"); |
609 StoreSeed(seed_data, seed_signature, response_date); | 637 const bool store_success = StoreSeed(seed_data, signature, country_code, |
| 638 response_date, is_delta_compressed); |
| 639 if (!store_success && is_delta_compressed) { |
| 640 disable_deltas_for_next_request_ = true; |
| 641 request_scheduler_->ScheduleFetchShortly(); |
| 642 } |
610 } | 643 } |
611 | 644 |
612 void VariationsService::OnResourceRequestsAllowed() { | 645 void VariationsService::OnResourceRequestsAllowed() { |
613 DCHECK(thread_checker_.CalledOnValidThread()); | 646 DCHECK(thread_checker_.CalledOnValidThread()); |
614 | 647 |
615 // Note that this only attempts to fetch the seed at most once per period | 648 // Note that this only attempts to fetch the seed at most once per period |
616 // (kSeedFetchPeriodHours). This works because | 649 // (kSeedFetchPeriodHours). This works because |
617 // |resource_request_allowed_notifier_| only calls this method if an | 650 // |resource_request_allowed_notifier_| only calls this method if an |
618 // attempt was made earlier that fails (which implies that the period had | 651 // attempt was made earlier that fails (which implies that the period had |
619 // elapsed). After a successful attempt is made, the notifier will know not | 652 // 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... |
744 // Otherwise, update the pref with the current Chrome version and country. | 777 // Otherwise, update the pref with the current Chrome version and country. |
745 base::ListValue new_list_value; | 778 base::ListValue new_list_value; |
746 new_list_value.AppendString(version.GetString()); | 779 new_list_value.AppendString(version.GetString()); |
747 new_list_value.AppendString(latest_country); | 780 new_list_value.AppendString(latest_country); |
748 local_state_->Set(prefs::kVariationsPermanentConsistencyCountry, | 781 local_state_->Set(prefs::kVariationsPermanentConsistencyCountry, |
749 new_list_value); | 782 new_list_value); |
750 return latest_country; | 783 return latest_country; |
751 } | 784 } |
752 | 785 |
753 } // namespace chrome_variations | 786 } // namespace chrome_variations |
OLD | NEW |