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 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 93 // be that badly wrong, but all the same it's included here to document the very | 93 // be that badly wrong, but all the same it's included here to document the very |
| 94 // rough nature of the time service provided by this class.) | 94 // rough nature of the time service provided by this class.) |
| 95 const uint32_t kTimeServerMaxSkewSeconds = 10; | 95 const uint32_t kTimeServerMaxSkewSeconds = 10; |
| 96 | 96 |
| 97 const char kTimeServiceURL[] = "http://clients2.google.com/time/1/current"; | 97 const char kTimeServiceURL[] = "http://clients2.google.com/time/1/current"; |
| 98 | 98 |
| 99 const char kVariationsServiceCheckTimeIntervalSeconds[] = | 99 const char kVariationsServiceCheckTimeIntervalSeconds[] = |
| 100 "CheckTimeIntervalSeconds"; | 100 "CheckTimeIntervalSeconds"; |
| 101 const char kVariationsServiceRandomQueryProbability[] = | 101 const char kVariationsServiceRandomQueryProbability[] = |
| 102 "RandomQueryProbability"; | 102 "RandomQueryProbability"; |
| 103 // This parameter must have the value "true" in order for | |
| 104 // StartTimeFetch() to start time queries on demand. | |
| 105 const char kVariationsServiceEnableFetchesOnDemand[] = "EnableFetchesOnDemand"; | |
| 103 | 106 |
| 104 // This is an ECDSA prime256v1 named-curve key. | 107 // This is an ECDSA prime256v1 named-curve key. |
| 105 const int kKeyVersion = 1; | 108 const int kKeyVersion = 1; |
| 106 const uint8_t kKeyPubBytes[] = { | 109 const uint8_t kKeyPubBytes[] = { |
| 107 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, | 110 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, |
| 108 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, | 111 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, |
| 109 0x42, 0x00, 0x04, 0xeb, 0xd8, 0xad, 0x0b, 0x8f, 0x75, 0xe8, 0x84, 0x36, | 112 0x42, 0x00, 0x04, 0xeb, 0xd8, 0xad, 0x0b, 0x8f, 0x75, 0xe8, 0x84, 0x36, |
| 110 0x23, 0x48, 0x14, 0x24, 0xd3, 0x93, 0x42, 0x25, 0x43, 0xc1, 0xde, 0x36, | 113 0x23, 0x48, 0x14, 0x24, 0xd3, 0x93, 0x42, 0x25, 0x43, 0xc1, 0xde, 0x36, |
| 111 0x29, 0xc6, 0x95, 0xca, 0xeb, 0x28, 0x85, 0xff, 0x09, 0xdc, 0x08, 0xec, | 114 0x29, 0xc6, 0x95, 0xca, 0xeb, 0x28, 0x85, 0xff, 0x09, 0xdc, 0x08, 0xec, |
| 112 0x45, 0x74, 0x6e, 0x4b, 0xc3, 0xa5, 0xfd, 0x8a, 0x2f, 0x02, 0xa0, 0x4b, | 115 0x45, 0x74, 0x6e, 0x4b, 0xc3, 0xa5, 0xfd, 0x8a, 0x2f, 0x02, 0xa0, 0x4b, |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 288 } | 291 } |
| 289 | 292 |
| 290 bool NetworkTimeTracker::QueryTimeServiceForTesting() { | 293 bool NetworkTimeTracker::QueryTimeServiceForTesting() { |
| 291 CheckTime(); | 294 CheckTime(); |
| 292 return time_fetcher_ != nullptr; | 295 return time_fetcher_ != nullptr; |
| 293 } | 296 } |
| 294 | 297 |
| 295 void NetworkTimeTracker::WaitForFetchForTesting(uint32_t nonce) { | 298 void NetworkTimeTracker::WaitForFetchForTesting(uint32_t nonce) { |
| 296 query_signer_->OverrideNonceForTesting(kKeyVersion, nonce); | 299 query_signer_->OverrideNonceForTesting(kKeyVersion, nonce); |
| 297 base::RunLoop run_loop; | 300 base::RunLoop run_loop; |
| 298 run_loop_for_testing_ = &run_loop; | 301 fetch_completion_callbacks_.push_back(run_loop.QuitClosure()); |
| 299 run_loop.Run(); | 302 run_loop.Run(); |
| 300 run_loop_for_testing_ = nullptr; | |
| 301 } | 303 } |
| 302 | 304 |
| 303 base::TimeDelta NetworkTimeTracker::GetTimerDelayForTesting() const { | 305 base::TimeDelta NetworkTimeTracker::GetTimerDelayForTesting() const { |
| 304 DCHECK(timer_.IsRunning()); | 306 DCHECK(timer_.IsRunning()); |
| 305 return timer_.GetCurrentDelay(); | 307 return timer_.GetCurrentDelay(); |
| 306 } | 308 } |
| 307 | 309 |
| 308 NetworkTimeTracker::NetworkTimeResult NetworkTimeTracker::GetNetworkTime( | 310 NetworkTimeTracker::NetworkTimeResult NetworkTimeTracker::GetNetworkTime( |
| 309 base::Time* network_time, | 311 base::Time* network_time, |
| 310 base::TimeDelta* uncertainty) const { | 312 base::TimeDelta* uncertainty) const { |
| 311 DCHECK(thread_checker_.CalledOnValidThread()); | 313 DCHECK(thread_checker_.CalledOnValidThread()); |
| 312 DCHECK(network_time); | 314 DCHECK(network_time); |
| 313 if (network_time_at_last_measurement_.is_null()) { | 315 if (network_time_at_last_measurement_.is_null()) { |
| 314 if (time_query_completed_) { | 316 if (time_query_completed_) { |
| 315 // Time query attempts have been made in the past and failed. | 317 // Time query attempts have been made in the past and failed. |
| 316 if (time_fetcher_) { | 318 if (time_fetcher_) { |
| 317 // A fetch (not the first attempt) is in progress. | 319 // A fetch (not the first attempt) is in progress. |
| 318 return NETWORK_TIME_SUBSEQUENT_SYNC_PENDING; | 320 return NETWORK_TIME_SUBSEQUENT_SYNC_PENDING; |
| 319 } else { | |
| 320 return NETWORK_TIME_NO_SUCCESSFUL_SYNC; | |
| 321 } | 321 } |
| 322 } else { | 322 return NETWORK_TIME_NO_SUCCESSFUL_SYNC; |
|
estark
2016/10/25 20:14:00
unrelated cleanup, sorry. there was too much inden
| |
| 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 } | 323 } |
| 324 // No time queries have happened yet. | |
| 325 if (time_fetcher_) { | |
| 326 return NETWORK_TIME_FIRST_SYNC_PENDING; | |
| 327 } | |
| 328 return NETWORK_TIME_NO_SYNC_ATTEMPT; | |
| 330 } | 329 } |
| 330 | |
| 331 DCHECK(!ticks_at_last_measurement_.is_null()); | 331 DCHECK(!ticks_at_last_measurement_.is_null()); |
| 332 DCHECK(!time_at_last_measurement_.is_null()); | 332 DCHECK(!time_at_last_measurement_.is_null()); |
| 333 base::TimeDelta tick_delta = | 333 base::TimeDelta tick_delta = |
| 334 tick_clock_->NowTicks() - ticks_at_last_measurement_; | 334 tick_clock_->NowTicks() - ticks_at_last_measurement_; |
| 335 base::TimeDelta time_delta = clock_->Now() - time_at_last_measurement_; | 335 base::TimeDelta time_delta = clock_->Now() - time_at_last_measurement_; |
| 336 if (time_delta.InMilliseconds() < 0) { // Has wall clock run backward? | 336 if (time_delta.InMilliseconds() < 0) { // Has wall clock run backward? |
| 337 DVLOG(1) << "Discarding network time due to wall clock running backward"; | 337 DVLOG(1) << "Discarding network time due to wall clock running backward"; |
| 338 UMA_HISTOGRAM_CUSTOM_TIMES( | 338 UMA_HISTOGRAM_CUSTOM_TIMES( |
| 339 "NetworkTimeTracker.WallClockRanBackwards", time_delta.magnitude(), | 339 "NetworkTimeTracker.WallClockRanBackwards", time_delta.magnitude(), |
| 340 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(7), 50); | 340 base::TimeDelta::FromSeconds(1), base::TimeDelta::FromDays(7), 50); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 365 network_time_at_last_measurement_ = base::Time(); | 365 network_time_at_last_measurement_ = base::Time(); |
| 366 return NETWORK_TIME_SYNC_LOST; | 366 return NETWORK_TIME_SYNC_LOST; |
| 367 } | 367 } |
| 368 *network_time = network_time_at_last_measurement_ + tick_delta; | 368 *network_time = network_time_at_last_measurement_ + tick_delta; |
| 369 if (uncertainty) { | 369 if (uncertainty) { |
| 370 *uncertainty = network_time_uncertainty_ + divergence; | 370 *uncertainty = network_time_uncertainty_ + divergence; |
| 371 } | 371 } |
| 372 return NETWORK_TIME_AVAILABLE; | 372 return NETWORK_TIME_AVAILABLE; |
| 373 } | 373 } |
| 374 | 374 |
| 375 bool NetworkTimeTracker::StartTimeFetch(const base::Closure& closure) { | |
|
meacer
2016/10/26 19:19:22
Could you add a DCHECK(thread_checker_.CalledOnVal
estark
2016/10/26 20:35:13
Done.
| |
| 376 // Check if the user is opted in to on-demand time fetches. | |
| 377 const std::string param = variations::GetVariationParamValueByFeature( | |
| 378 kNetworkTimeServiceQuerying, kVariationsServiceEnableFetchesOnDemand); | |
| 379 if (param != "true") { | |
| 380 return false; | |
| 381 } | |
| 382 | |
| 383 // Enqueue the callback before calling CheckTime(), so that if | |
| 384 // CheckTime() completes synchronously, the callback gets called. | |
| 385 fetch_completion_callbacks_.push_back(closure); | |
| 386 | |
| 387 // If a time query is already in progress, do not start another one. | |
| 388 if (time_fetcher_) { | |
| 389 return true; | |
| 390 } | |
| 391 | |
| 392 // Cancel any fetches that are scheduled for the future, and try to | |
| 393 // start one now. | |
|
meacer
2016/10/26 00:38:15
For my own education: If two clients call StartTim
meacer
2016/10/26 01:07:37
"If two clients call StartTimeFetch one of the oth
| |
| 394 timer_.Stop(); | |
| 395 CheckTime(); | |
| 396 | |
| 397 // CheckTime() does not necessarily start a fetch; for example, time | |
| 398 // queries might be disabled or network time might already be | |
| 399 // available. | |
| 400 if (!time_fetcher_) { | |
| 401 // If no query is in progress, there should be no callbacks waiting for it | |
| 402 // to complete. | |
|
meacer
2016/10/26 19:19:22
nit: I'm a bit confused by this comment, it sounds
estark
2016/10/26 20:35:13
Oh, yes, what I wrote was confusing. Done.
| |
| 403 fetch_completion_callbacks_.clear(); | |
| 404 return false; | |
| 405 } | |
| 406 return true; | |
| 407 } | |
| 408 | |
| 375 void NetworkTimeTracker::CheckTime() { | 409 void NetworkTimeTracker::CheckTime() { |
| 376 DCHECK(thread_checker_.CalledOnValidThread()); | 410 DCHECK(thread_checker_.CalledOnValidThread()); |
| 377 | 411 |
| 378 // If NetworkTimeTracker is waking up after a backoff, this will reset the | 412 // If NetworkTimeTracker is waking up after a backoff, this will reset the |
| 379 // timer to its default faster frequency. | 413 // timer to its default faster frequency. |
| 380 QueueCheckTime(CheckTimeInterval()); | 414 QueueCheckTime(CheckTimeInterval()); |
| 381 | 415 |
| 382 if (!ShouldIssueTimeQuery()) { | 416 if (!ShouldIssueTimeQuery()) { |
| 383 return; | 417 return; |
| 384 } | 418 } |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 483 // long time. | 517 // long time. |
| 484 if (!UpdateTimeFromResponse()) { // On error, back off. | 518 if (!UpdateTimeFromResponse()) { // On error, back off. |
| 485 if (backoff_ < base::TimeDelta::FromDays(2)) { | 519 if (backoff_ < base::TimeDelta::FromDays(2)) { |
| 486 backoff_ *= 2; | 520 backoff_ *= 2; |
| 487 } | 521 } |
| 488 } else { | 522 } else { |
| 489 backoff_ = base::TimeDelta::FromMinutes(kBackoffMinutes); | 523 backoff_ = base::TimeDelta::FromMinutes(kBackoffMinutes); |
| 490 } | 524 } |
| 491 QueueCheckTime(backoff_); | 525 QueueCheckTime(backoff_); |
| 492 time_fetcher_.reset(); | 526 time_fetcher_.reset(); |
| 493 if (run_loop_for_testing_ != nullptr) | 527 |
| 494 run_loop_for_testing_->QuitWhenIdle(); | 528 // Clear |fetch_completion_callbacks_| before running any of them, |
| 529 // because a callback could call StartTimeFetch() to enqueue another | |
| 530 // callback. | |
| 531 std::vector<base::Closure> callbacks = fetch_completion_callbacks_; | |
| 532 fetch_completion_callbacks_.clear(); | |
| 533 for (const auto& callback : callbacks) { | |
| 534 callback.Run(); | |
| 535 } | |
| 495 } | 536 } |
| 496 | 537 |
| 497 void NetworkTimeTracker::QueueCheckTime(base::TimeDelta delay) { | 538 void NetworkTimeTracker::QueueCheckTime(base::TimeDelta delay) { |
| 498 timer_.Start(FROM_HERE, delay, this, &NetworkTimeTracker::CheckTime); | 539 timer_.Start(FROM_HERE, delay, this, &NetworkTimeTracker::CheckTime); |
| 499 } | 540 } |
| 500 | 541 |
| 501 bool NetworkTimeTracker::ShouldIssueTimeQuery() { | 542 bool NetworkTimeTracker::ShouldIssueTimeQuery() { |
| 502 // Do not query the time service if not enabled via Variations Service. | 543 // Do not query the time service if not enabled via Variations Service. |
| 503 if (!base::FeatureList::IsEnabled(kNetworkTimeServiceQuerying)) { | 544 if (!base::FeatureList::IsEnabled(kNetworkTimeServiceQuerying)) { |
| 504 return false; | 545 return false; |
| 505 } | 546 } |
| 506 | 547 |
| 507 // If GetNetworkTime() does not return NETWORK_TIME_AVAILABLE, | 548 // If GetNetworkTime() does not return NETWORK_TIME_AVAILABLE, |
| 508 // synchronization has been lost and a query is needed. | 549 // synchronization has been lost and a query is needed. |
| 509 base::Time network_time; | 550 base::Time network_time; |
| 510 if (GetNetworkTime(&network_time, nullptr) != NETWORK_TIME_AVAILABLE) { | 551 if (GetNetworkTime(&network_time, nullptr) != NETWORK_TIME_AVAILABLE) { |
| 511 return true; | 552 return true; |
| 512 } | 553 } |
| 513 | 554 |
| 514 // Otherwise, make the decision at random. | 555 // Otherwise, make the decision at random. |
| 515 return base::RandDouble() < RandomQueryProbability(); | 556 return base::RandDouble() < RandomQueryProbability(); |
| 516 } | 557 } |
| 517 | 558 |
| 518 } // namespace network_time | 559 } // namespace network_time |
| OLD | NEW |