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 |