Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/network_time/network_time_tracker.h" | 5 #include "components/network_time/network_time_tracker.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 181 std::unique_ptr<base::Clock> clock, | 181 std::unique_ptr<base::Clock> clock, |
| 182 std::unique_ptr<base::TickClock> tick_clock, | 182 std::unique_ptr<base::TickClock> tick_clock, |
| 183 PrefService* pref_service, | 183 PrefService* pref_service, |
| 184 scoped_refptr<net::URLRequestContextGetter> getter) | 184 scoped_refptr<net::URLRequestContextGetter> getter) |
| 185 : server_url_(kTimeServiceURL), | 185 : server_url_(kTimeServiceURL), |
| 186 max_response_size_(1024), | 186 max_response_size_(1024), |
| 187 backoff_(base::TimeDelta::FromMinutes(kBackoffMinutes)), | 187 backoff_(base::TimeDelta::FromMinutes(kBackoffMinutes)), |
| 188 getter_(std::move(getter)), | 188 getter_(std::move(getter)), |
| 189 clock_(std::move(clock)), | 189 clock_(std::move(clock)), |
| 190 tick_clock_(std::move(tick_clock)), | 190 tick_clock_(std::move(tick_clock)), |
| 191 pref_service_(pref_service) { | 191 pref_service_(pref_service), |
| 192 time_query_failed_(false) { | |
| 192 const base::DictionaryValue* time_mapping = | 193 const base::DictionaryValue* time_mapping = |
| 193 pref_service_->GetDictionary(prefs::kNetworkTimeMapping); | 194 pref_service_->GetDictionary(prefs::kNetworkTimeMapping); |
| 194 double time_js = 0; | 195 double time_js = 0; |
| 195 double ticks_js = 0; | 196 double ticks_js = 0; |
| 196 double network_time_js = 0; | 197 double network_time_js = 0; |
| 197 double uncertainty_js = 0; | 198 double uncertainty_js = 0; |
| 198 if (time_mapping->GetDouble(kPrefTime, &time_js) && | 199 if (time_mapping->GetDouble(kPrefTime, &time_js) && |
| 199 time_mapping->GetDouble(kPrefTicks, &ticks_js) && | 200 time_mapping->GetDouble(kPrefTicks, &ticks_js) && |
| 200 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) && | 201 time_mapping->GetDouble(kPrefUncertainty, &uncertainty_js) && |
| 201 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) { | 202 time_mapping->GetDouble(kPrefNetworkTime, &network_time_js)) { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 303 DCHECK(timer_.IsRunning()); | 304 DCHECK(timer_.IsRunning()); |
| 304 return timer_.GetCurrentDelay(); | 305 return timer_.GetCurrentDelay(); |
| 305 } | 306 } |
| 306 | 307 |
| 307 NetworkTimeTracker::NetworkTimeResult NetworkTimeTracker::GetNetworkTime( | 308 NetworkTimeTracker::NetworkTimeResult NetworkTimeTracker::GetNetworkTime( |
| 308 base::Time* network_time, | 309 base::Time* network_time, |
| 309 base::TimeDelta* uncertainty) const { | 310 base::TimeDelta* uncertainty) const { |
| 310 DCHECK(thread_checker_.CalledOnValidThread()); | 311 DCHECK(thread_checker_.CalledOnValidThread()); |
| 311 DCHECK(network_time); | 312 DCHECK(network_time); |
| 312 if (network_time_at_last_measurement_.is_null()) { | 313 if (network_time_at_last_measurement_.is_null()) { |
| 313 return NETWORK_TIME_NO_SYNC; | 314 if (time_query_failed_) { |
| 315 // Time query attempts have been made in the past and failed. | |
| 316 if (time_fetcher_) { | |
| 317 // A fetch (not the first attempt) is in progress. | |
| 318 return NETWORK_TIME_SUBSEQUENT_SYNC_PENDING; | |
| 319 } else { | |
| 320 return NETWORK_TIME_NO_SUCCESSFUL_SYNC; | |
| 321 } | |
| 322 } else { | |
| 323 // No time queries have happened yet. | |
| 324 if (time_fetcher_) { | |
| 325 return NETWORK_TIME_FIRST_SYNC_PENDING; | |
| 326 } else { | |
| 327 return NETWORK_TIME_NO_SYNC_ATTEMPT; | |
| 328 } | |
| 329 } | |
| 314 } | 330 } |
| 315 DCHECK(!ticks_at_last_measurement_.is_null()); | 331 DCHECK(!ticks_at_last_measurement_.is_null()); |
| 316 DCHECK(!time_at_last_measurement_.is_null()); | 332 DCHECK(!time_at_last_measurement_.is_null()); |
| 317 base::TimeDelta tick_delta = | 333 base::TimeDelta tick_delta = |
| 318 tick_clock_->NowTicks() - ticks_at_last_measurement_; | 334 tick_clock_->NowTicks() - ticks_at_last_measurement_; |
| 319 base::TimeDelta time_delta = clock_->Now() - time_at_last_measurement_; | 335 base::TimeDelta time_delta = clock_->Now() - time_at_last_measurement_; |
| 320 if (time_delta.InMilliseconds() < 0) { // Has wall clock run backward? | 336 if (time_delta.InMilliseconds() < 0) { // Has wall clock run backward? |
| 321 DVLOG(1) << "Discarding network time due to wall clock running backward"; | 337 DVLOG(1) << "Discarding network time due to wall clock running backward"; |
| 322 UMA_HISTOGRAM_CUSTOM_TIMES( | 338 UMA_HISTOGRAM_CUSTOM_TIMES( |
| 323 "NetworkTimeTracker.WallClockRanBackwards", time_delta.magnitude(), | 339 "NetworkTimeTracker.WallClockRanBackwards", time_delta.magnitude(), |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 393 | 409 |
| 394 time_fetcher_->Start(); | 410 time_fetcher_->Start(); |
| 395 fetch_started_ = tick_clock_->NowTicks(); | 411 fetch_started_ = tick_clock_->NowTicks(); |
| 396 | 412 |
| 397 timer_.Stop(); // Restarted in OnURLFetchComplete(). | 413 timer_.Stop(); // Restarted in OnURLFetchComplete(). |
| 398 } | 414 } |
| 399 | 415 |
| 400 bool NetworkTimeTracker::UpdateTimeFromResponse() { | 416 bool NetworkTimeTracker::UpdateTimeFromResponse() { |
| 401 if (time_fetcher_->GetStatus().status() != net::URLRequestStatus::SUCCESS || | 417 if (time_fetcher_->GetStatus().status() != net::URLRequestStatus::SUCCESS || |
| 402 time_fetcher_->GetResponseCode() != 200) { | 418 time_fetcher_->GetResponseCode() != 200) { |
| 419 time_query_failed_ = true; | |
| 403 DVLOG(1) << "fetch failed, status=" << time_fetcher_->GetStatus().status() | 420 DVLOG(1) << "fetch failed, status=" << time_fetcher_->GetStatus().status() |
| 404 << ",code=" << time_fetcher_->GetResponseCode(); | 421 << ",code=" << time_fetcher_->GetResponseCode(); |
| 405 // The error code is negated because net errors are negative, but | 422 // The error code is negated because net errors are negative, but |
| 406 // the corresponding histogram enum is positive. | 423 // the corresponding histogram enum is positive. |
| 407 UMA_HISTOGRAM_SPARSE_SLOWLY("NetworkTimeTracker.UpdateTimeFetchFailed", | 424 UMA_HISTOGRAM_SPARSE_SLOWLY("NetworkTimeTracker.UpdateTimeFetchFailed", |
| 408 -time_fetcher_->GetStatus().error()); | 425 -time_fetcher_->GetStatus().error()); |
| 409 return false; | 426 return false; |
| 410 } | 427 } |
| 411 | 428 |
| 412 std::string response_body; | 429 std::string response_body; |
| 413 if (!time_fetcher_->GetResponseAsString(&response_body)) { | 430 if (!time_fetcher_->GetResponseAsString(&response_body)) { |
| 414 DVLOG(1) << "failed to get response"; | 431 DVLOG(1) << "failed to get response"; |
| 432 time_query_failed_ = true; | |
| 415 return false; | 433 return false; |
| 416 } | 434 } |
| 417 DCHECK(query_signer_); | 435 DCHECK(query_signer_); |
| 418 if (!query_signer_->ValidateResponse(response_body, | 436 if (!query_signer_->ValidateResponse(response_body, |
| 419 GetServerProof(time_fetcher_.get()))) { | 437 GetServerProof(time_fetcher_.get()))) { |
| 420 DVLOG(1) << "invalid signature"; | 438 DVLOG(1) << "invalid signature"; |
| 439 time_query_failed_ = true; | |
| 421 RecordFetchValidHistogram(false); | 440 RecordFetchValidHistogram(false); |
| 422 return false; | 441 return false; |
| 423 } | 442 } |
| 424 response_body = response_body.substr(5); // Skips leading )]}'\n | 443 response_body = response_body.substr(5); // Skips leading )]}'\n |
| 425 std::unique_ptr<base::Value> value = base::JSONReader::Read(response_body); | 444 std::unique_ptr<base::Value> value = base::JSONReader::Read(response_body); |
| 426 if (!value) { | 445 if (!value) { |
| 427 DVLOG(1) << "bad JSON"; | 446 DVLOG(1) << "bad JSON"; |
| 447 time_query_failed_ = true; | |
| 428 RecordFetchValidHistogram(false); | 448 RecordFetchValidHistogram(false); |
| 429 return false; | 449 return false; |
| 430 } | 450 } |
| 431 const base::DictionaryValue* dict; | 451 const base::DictionaryValue* dict; |
| 432 if (!value->GetAsDictionary(&dict)) { | 452 if (!value->GetAsDictionary(&dict)) { |
| 433 DVLOG(1) << "not a dictionary"; | 453 DVLOG(1) << "not a dictionary"; |
| 454 time_query_failed_ = true; | |
| 434 RecordFetchValidHistogram(false); | 455 RecordFetchValidHistogram(false); |
| 435 return false; | 456 return false; |
| 436 } | 457 } |
| 437 double current_time_millis; | 458 double current_time_millis; |
| 438 if (!dict->GetDouble("current_time_millis", ¤t_time_millis)) { | 459 if (!dict->GetDouble("current_time_millis", ¤t_time_millis)) { |
| 439 DVLOG(1) << "no current_time_millis"; | 460 DVLOG(1) << "no current_time_millis"; |
| 461 time_query_failed_ = true; | |
| 440 RecordFetchValidHistogram(false); | 462 RecordFetchValidHistogram(false); |
| 441 return false; | 463 return false; |
| 442 } | 464 } |
| 443 | 465 |
| 444 RecordFetchValidHistogram(true); | 466 RecordFetchValidHistogram(true); |
| 445 | 467 |
| 446 // There is a "server_nonce" key here too, but it serves no purpose other than | 468 // There is a "server_nonce" key here too, but it serves no purpose other than |
| 447 // to make the server's response unpredictable. | 469 // to make the server's response unpredictable. |
| 448 base::Time current_time = base::Time::FromJsTime(current_time_millis); | 470 base::Time current_time = base::Time::FromJsTime(current_time_millis); |
| 449 base::TimeDelta resolution = | 471 base::TimeDelta resolution = |
| 450 base::TimeDelta::FromMilliseconds(1) + | 472 base::TimeDelta::FromMilliseconds(1) + |
| 451 base::TimeDelta::FromSeconds(kTimeServerMaxSkewSeconds); | 473 base::TimeDelta::FromSeconds(kTimeServerMaxSkewSeconds); |
| 452 base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_; | 474 base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_; |
| 475 UMA_HISTOGRAM_TIMES("NetworkTimeTracker.TimeQueryLatency", latency); | |
| 453 UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks()); | 476 UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks()); |
| 454 return true; | 477 return true; |
| 455 } | 478 } |
| 456 | 479 |
| 457 void NetworkTimeTracker::OnURLFetchComplete(const net::URLFetcher* source) { | 480 void NetworkTimeTracker::OnURLFetchComplete(const net::URLFetcher* source) { |
| 458 DCHECK(thread_checker_.CalledOnValidThread()); | 481 DCHECK(thread_checker_.CalledOnValidThread()); |
| 459 DCHECK(time_fetcher_); | 482 DCHECK(time_fetcher_); |
| 460 DCHECK_EQ(source, time_fetcher_.get()); | 483 DCHECK_EQ(source, time_fetcher_.get()); |
| 461 | 484 |
| 462 // After completion of a query, whether succeeded or failed, go to sleep for a | 485 // After completion of a query, whether succeeded or failed, go to sleep for a |
| 463 // long time. | 486 // long time. |
| 464 if (!UpdateTimeFromResponse()) { // On error, back off. | 487 if (!UpdateTimeFromResponse()) { // On error, back off. |
|
mab
2016/10/14 06:35:01
Could you set time_query_failed_ here?
estark
2016/10/14 07:23:46
Oh, yes, that's much better, thanks. Done.
| |
| 465 if (backoff_ < base::TimeDelta::FromDays(2)) { | 488 if (backoff_ < base::TimeDelta::FromDays(2)) { |
| 466 backoff_ *= 2; | 489 backoff_ *= 2; |
| 467 } | 490 } |
| 468 } else { | 491 } else { |
| 469 backoff_ = base::TimeDelta::FromMinutes(kBackoffMinutes); | 492 backoff_ = base::TimeDelta::FromMinutes(kBackoffMinutes); |
| 470 } | 493 } |
| 471 QueueCheckTime(backoff_); | 494 QueueCheckTime(backoff_); |
| 472 time_fetcher_.reset(); | 495 time_fetcher_.reset(); |
| 473 if (run_loop_for_testing_ != nullptr) | 496 if (run_loop_for_testing_ != nullptr) |
| 474 run_loop_for_testing_->QuitWhenIdle(); | 497 run_loop_for_testing_->QuitWhenIdle(); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 489 base::Time network_time; | 512 base::Time network_time; |
| 490 if (GetNetworkTime(&network_time, nullptr) != NETWORK_TIME_AVAILABLE) { | 513 if (GetNetworkTime(&network_time, nullptr) != NETWORK_TIME_AVAILABLE) { |
| 491 return true; | 514 return true; |
| 492 } | 515 } |
| 493 | 516 |
| 494 // Otherwise, make the decision at random. | 517 // Otherwise, make the decision at random. |
| 495 return base::RandDouble() < RandomQueryProbability(); | 518 return base::RandDouble() < RandomQueryProbability(); |
| 496 } | 519 } |
| 497 | 520 |
| 498 } // namespace network_time | 521 } // namespace network_time |
| OLD | NEW |