| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/network_time/network_time_tracker.h" | 5 #include "chrome/browser/network_time/network_time_tracker.h" |
| 6 | 6 |
| 7 #include "base/sequenced_task_runner.h" | 7 #include "base/basictypes.h" |
| 8 #include "chrome/browser/browser_process.h" | 8 #include "base/i18n/time_formatting.h" |
| 9 #include "chrome/browser/io_thread.h" | 9 #include "base/logging.h" |
| 10 #include "base/strings/utf_string_conversions.h" |
| 11 #include "base/time/tick_clock.h" |
| 10 | 12 |
| 11 namespace { | 13 namespace { |
| 12 | 14 |
| 13 // Helper functions for interacting with the NetworkTimeNotifier. | 15 // Clock resolution is platform dependent. |
| 14 // Registration happens as follows (assuming tracker lives on thread N): | 16 #if defined(OS_WIN) |
| 15 // | Thread N | | UI thread| | IO Thread | | 17 const int64 kTicksResolutionMs = base::Time::kMinLowResolutionThresholdMs; |
| 16 // Start | 18 #else |
| 17 // RegisterObserverOnUIThread | 19 const int64 kTicksResolutionMs = 1; // Assume 1ms for non-windows platforms. |
| 18 // RegisterObserverOnIOThread | 20 #endif |
| 19 // NetworkTimeNotifier::AddObserver | |
| 20 // after which updates to the notifier and the subsequent observer calls | |
| 21 // happen as follows (assuming the network time update comes from the same | |
| 22 // thread): | |
| 23 // | Thread N | | UI thread| | IO Thread | | |
| 24 // UpdateNetworkNotifier | |
| 25 // UpdateNetworkNotifierOnIOThread | |
| 26 // NetworkTimeNotifier::UpdateNetworkTime | |
| 27 // OnNetworkTimeUpdatedOnIOThread | |
| 28 // OnNetworkTimeUpdated | |
| 29 void RegisterObserverOnIOThread( | |
| 30 IOThread* io_thread, | |
| 31 const net::NetworkTimeNotifier::ObserverCallback& observer_callback) { | |
| 32 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
| 33 io_thread->globals()->network_time_notifier->AddObserver(observer_callback); | |
| 34 } | |
| 35 | 21 |
| 36 void RegisterObserverOnUIThread( | 22 // Number of time measurements performed in a given network time calculation. |
| 37 const net::NetworkTimeNotifier::ObserverCallback& observer_callback) { | 23 const int kNumTimeMeasurements = 5; |
| 38 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 39 content::BrowserThread::PostTask( | |
| 40 content::BrowserThread::IO, FROM_HERE, | |
| 41 base::Bind(&RegisterObserverOnIOThread, | |
| 42 g_browser_process->io_thread(), | |
| 43 observer_callback)); | |
| 44 } | |
| 45 | |
| 46 void UpdateNetworkNotifierOnIOThread(IOThread* io_thread, | |
| 47 const base::Time& network_time, | |
| 48 const base::TimeDelta& resolution, | |
| 49 const base::TimeDelta& latency, | |
| 50 const base::TimeTicks& post_time) { | |
| 51 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
| 52 io_thread->globals()->network_time_notifier->UpdateNetworkTime( | |
| 53 network_time, resolution, latency, post_time); | |
| 54 } | |
| 55 | |
| 56 void UpdateNetworkNotifier(IOThread* io_thread, | |
| 57 const base::Time& network_time, | |
| 58 const base::TimeDelta& resolution, | |
| 59 const base::TimeDelta& latency) { | |
| 60 content::BrowserThread::PostTask( | |
| 61 content::BrowserThread::IO, | |
| 62 FROM_HERE, | |
| 63 base::Bind(&UpdateNetworkNotifierOnIOThread, | |
| 64 io_thread, | |
| 65 network_time, | |
| 66 resolution, | |
| 67 latency, | |
| 68 base::TimeTicks::Now())); | |
| 69 } | |
| 70 | |
| 71 void OnNetworkTimeUpdatedOnIOThread( | |
| 72 const scoped_refptr<base::SequencedTaskRunner>& task_runner, | |
| 73 const net::NetworkTimeNotifier::ObserverCallback& observer_callback, | |
| 74 const base::Time& network_time, | |
| 75 const base::TimeTicks& network_time_ticks, | |
| 76 const base::TimeDelta& network_time_uncertainty) { | |
| 77 task_runner->PostTask( | |
| 78 FROM_HERE, | |
| 79 base::Bind(observer_callback, | |
| 80 network_time, | |
| 81 network_time_ticks, | |
| 82 network_time_uncertainty)); | |
| 83 } | |
| 84 | 24 |
| 85 } // namespace | 25 } // namespace |
| 86 | 26 |
| 87 NetworkTimeTracker::TimeMapping::TimeMapping(base::Time local_time, | 27 NetworkTimeTracker::TimeMapping::TimeMapping(const base::Time& local_time, |
| 88 base::Time network_time) | 28 const base::Time& network_time) |
| 89 : local_time(local_time), | 29 : local_time(local_time), |
| 90 network_time(network_time) {} | 30 network_time(network_time) {} |
| 91 | 31 |
| 92 NetworkTimeTracker::NetworkTimeTracker() | 32 NetworkTimeTracker::NetworkTimeTracker(scoped_ptr<base::TickClock> tick_clock) |
| 93 : weak_ptr_factory_(this), | 33 : tick_clock_(tick_clock.Pass()), |
| 94 received_network_time_(false) { | 34 received_network_time_(false) { |
| 95 } | 35 } |
| 96 | 36 |
| 97 NetworkTimeTracker::~NetworkTimeTracker() { | 37 NetworkTimeTracker::~NetworkTimeTracker() { |
| 98 } | |
| 99 | |
| 100 void NetworkTimeTracker::Start() { | |
| 101 DCHECK(thread_checker_.CalledOnValidThread()); | 38 DCHECK(thread_checker_.CalledOnValidThread()); |
| 102 content::BrowserThread::PostTask( | |
| 103 content::BrowserThread::UI, | |
| 104 FROM_HERE, | |
| 105 base::Bind(&RegisterObserverOnUIThread, | |
| 106 BuildObserverCallback())); | |
| 107 } | 39 } |
| 108 | 40 |
| 109 void NetworkTimeTracker::InitFromSavedTime(const TimeMapping& saved) { | 41 void NetworkTimeTracker::InitFromSavedTime(const TimeMapping& saved) { |
| 110 DCHECK(thread_checker_.CalledOnValidThread()); | 42 DCHECK(thread_checker_.CalledOnValidThread()); |
| 111 if (!network_time_.is_null() || saved.local_time.is_null() || | 43 if (!network_time_.is_null() || saved.local_time.is_null() || |
| 112 saved.network_time.is_null()) | 44 saved.network_time.is_null()) |
| 113 return; | 45 return; |
| 114 | 46 |
| 115 base::Time local_time_now = base::Time::Now(); | 47 base::Time local_time_now = base::Time::Now(); |
| 116 if (local_time_now < saved.local_time) { | 48 if (local_time_now < saved.local_time) { |
| 117 DLOG(WARNING) << "Can't initialize because clock skew has changed."; | 49 DLOG(WARNING) << "Can't initialize because clock skew has changed."; |
| 118 return; | 50 return; |
| 119 } | 51 } |
| 120 | 52 |
| 121 network_time_ = saved.network_time + (local_time_now - saved.local_time); | 53 network_time_ = saved.network_time + (local_time_now - saved.local_time); |
| 122 network_time_ticks_ = base::TimeTicks::Now(); | 54 network_time_ticks_ = base::TimeTicks::Now(); |
| 123 } | 55 } |
| 124 | 56 |
| 57 void NetworkTimeTracker::UpdateNetworkTime(const base::Time& network_time, |
| 58 const base::TimeDelta& resolution, |
| 59 const base::TimeDelta& latency, |
| 60 const base::TimeTicks& post_time) { |
| 61 DCHECK(thread_checker_.CalledOnValidThread()); |
| 62 DVLOG(1) << "Network time updating to " |
| 63 << base::UTF16ToUTF8( |
| 64 base::TimeFormatFriendlyDateAndTime(network_time)); |
| 65 // Update network time on every request to limit dependency on ticks lag. |
| 66 // TODO(mad): Find a heuristic to avoid augmenting the |
| 67 // network_time_uncertainty_ too much by a particularly long latency. |
| 68 // Maybe only update when the the new time either improves in accuracy or |
| 69 // drifts too far from |network_time_|. |
| 70 network_time_ = network_time; |
| 71 |
| 72 // Calculate the delay since the network time was received. |
| 73 base::TimeTicks now = tick_clock_->NowTicks(); |
| 74 base::TimeDelta task_delay = now - post_time; |
| 75 // Estimate that the time was set midway through the latency time. |
| 76 network_time_ticks_ = now - task_delay - latency / 2; |
| 77 |
| 78 // Can't assume a better time than the resolution of the given time |
| 79 // and 5 ticks measurements are involved, each with their own uncertainty. |
| 80 // 1 & 2 are the ones used to compute the latency, 3 is the Now() from when |
| 81 // this task was posted, 4 is the Now() above and 5 will be the Now() used in |
| 82 // GetNetworkTime(). |
| 83 network_time_uncertainty_ = |
| 84 resolution + latency + kNumTimeMeasurements * |
| 85 base::TimeDelta::FromMilliseconds(kTicksResolutionMs); |
| 86 |
| 87 received_network_time_ = true; |
| 88 } |
| 89 |
| 125 bool NetworkTimeTracker::GetNetworkTime(const base::TimeTicks& time_ticks, | 90 bool NetworkTimeTracker::GetNetworkTime(const base::TimeTicks& time_ticks, |
| 126 base::Time* network_time, | 91 base::Time* network_time, |
| 127 base::TimeDelta* uncertainty) const { | 92 base::TimeDelta* uncertainty) const { |
| 128 DCHECK(thread_checker_.CalledOnValidThread()); | 93 DCHECK(thread_checker_.CalledOnValidThread()); |
| 129 DCHECK(network_time); | 94 DCHECK(network_time); |
| 130 if (network_time_.is_null()) | 95 if (network_time_.is_null()) |
| 131 return false; | 96 return false; |
| 132 DCHECK(!network_time_ticks_.is_null()); | 97 DCHECK(!network_time_ticks_.is_null()); |
| 133 *network_time = network_time_ + (time_ticks - network_time_ticks_); | 98 *network_time = network_time_ + (time_ticks - network_time_ticks_); |
| 134 if (uncertainty) | 99 if (uncertainty) |
| 135 *uncertainty = network_time_uncertainty_; | 100 *uncertainty = network_time_uncertainty_; |
| 136 return true; | 101 return true; |
| 137 } | 102 } |
| 138 | |
| 139 // static | |
| 140 // Note: UpdateNetworkNotifier is exposed via callback because getting the IO | |
| 141 // thread pointer must be done on the UI thread, while components that provide | |
| 142 // network time updates may live on other threads. | |
| 143 NetworkTimeTracker::UpdateCallback | |
| 144 NetworkTimeTracker::BuildNotifierUpdateCallback() { | |
| 145 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 146 return base::Bind(&UpdateNetworkNotifier, | |
| 147 g_browser_process->io_thread()); | |
| 148 } | |
| 149 | |
| 150 net::NetworkTimeNotifier::ObserverCallback | |
| 151 NetworkTimeTracker::BuildObserverCallback() { | |
| 152 return base::Bind(&OnNetworkTimeUpdatedOnIOThread, | |
| 153 base::MessageLoop::current()->message_loop_proxy(), | |
| 154 base::Bind(&NetworkTimeTracker::OnNetworkTimeUpdate, | |
| 155 weak_ptr_factory_.GetWeakPtr())); | |
| 156 } | |
| 157 | |
| 158 void NetworkTimeTracker::OnNetworkTimeUpdate( | |
| 159 const base::Time& network_time, | |
| 160 const base::TimeTicks& network_time_ticks, | |
| 161 const base::TimeDelta& network_time_uncertainty) { | |
| 162 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 163 network_time_ = network_time; | |
| 164 network_time_ticks_ = network_time_ticks; | |
| 165 network_time_uncertainty_ = network_time_uncertainty; | |
| 166 received_network_time_ = true; | |
| 167 } | |
| 168 | |
| OLD | NEW |