| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/network_time/network_time_tracker.h" |
| |
| #include "base/sequenced_task_runner.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/io_thread.h" |
| |
| namespace { |
| |
| // Helper functions for interacting with the NetworkTimeNotifier. |
| // Registration happens as follows (assuming tracker lives on thread N): |
| // | Thread N | | UI thread| | IO Thread | |
| // Start |
| // RegisterObserverOnUIThread |
| // RegisterObserverOnIOThread |
| // NetworkTimeNotifier::AddObserver |
| // after which updates to the notifier and the subsequent observer calls |
| // happen as follows (assuming the network time update comes from the same |
| // thread): |
| // | Thread N | | UI thread| | IO Thread | |
| // UpdateNetworkNotifier |
| // UpdateNetworkNotifierOnIOThread |
| // NetworkTimeNotifier::UpdateNetworkTime |
| // OnNetworkTimeUpdatedOnIOThread |
| // OnNetworkTimeUpdated |
| void RegisterObserverOnIOThread( |
| IOThread* io_thread, |
| const net::NetworkTimeNotifier::ObserverCallback& observer_callback) { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| io_thread->globals()->network_time_notifier->AddObserver(observer_callback); |
| } |
| |
| void RegisterObserverOnUIThread( |
| const net::NetworkTimeNotifier::ObserverCallback& observer_callback) { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| content::BrowserThread::PostTask( |
| content::BrowserThread::IO, FROM_HERE, |
| base::Bind(&RegisterObserverOnIOThread, |
| g_browser_process->io_thread(), |
| observer_callback)); |
| } |
| |
| void UpdateNetworkNotifierOnIOThread(IOThread* io_thread, |
| const base::Time& network_time, |
| const base::TimeDelta& resolution, |
| const base::TimeDelta& latency, |
| const base::TimeTicks& post_time) { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| io_thread->globals()->network_time_notifier->UpdateNetworkTime( |
| network_time, resolution, latency, post_time); |
| } |
| |
| void UpdateNetworkNotifier(IOThread* io_thread, |
| const base::Time& network_time, |
| const base::TimeDelta& resolution, |
| const base::TimeDelta& latency) { |
| content::BrowserThread::PostTask( |
| content::BrowserThread::IO, |
| FROM_HERE, |
| base::Bind(&UpdateNetworkNotifierOnIOThread, |
| io_thread, |
| network_time, |
| resolution, |
| latency, |
| base::TimeTicks::Now())); |
| } |
| |
| void OnNetworkTimeUpdatedOnIOThread( |
| const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| const net::NetworkTimeNotifier::ObserverCallback& observer_callback, |
| const base::Time& network_time, |
| const base::TimeTicks& network_time_ticks, |
| const base::TimeDelta& network_time_uncertainty) { |
| task_runner->PostTask( |
| FROM_HERE, |
| base::Bind(observer_callback, |
| network_time, |
| network_time_ticks, |
| network_time_uncertainty)); |
| } |
| |
| } // namespace |
| |
| NetworkTimeTracker::TimeMapping::TimeMapping(base::Time local_time, |
| base::Time network_time) |
| : local_time(local_time), |
| network_time(network_time) {} |
| |
| NetworkTimeTracker::NetworkTimeTracker() |
| : weak_ptr_factory_(this), |
| received_network_time_(false) { |
| } |
| |
| NetworkTimeTracker::~NetworkTimeTracker() { |
| } |
| |
| void NetworkTimeTracker::Start() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| content::BrowserThread::PostTask( |
| content::BrowserThread::UI, |
| FROM_HERE, |
| base::Bind(&RegisterObserverOnUIThread, |
| BuildObserverCallback())); |
| } |
| |
| void NetworkTimeTracker::InitFromSavedTime(const TimeMapping& saved) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| if (!network_time_.is_null() || saved.local_time.is_null() || |
| saved.network_time.is_null()) |
| return; |
| |
| base::Time local_time_now = base::Time::Now(); |
| if (local_time_now < saved.local_time) { |
| DLOG(WARNING) << "Can't initialize because clock skew has changed."; |
| return; |
| } |
| |
| network_time_ = saved.network_time + (local_time_now - saved.local_time); |
| network_time_ticks_ = base::TimeTicks::Now(); |
| } |
| |
| bool NetworkTimeTracker::GetNetworkTime(const base::TimeTicks& time_ticks, |
| base::Time* network_time, |
| base::TimeDelta* uncertainty) const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| DCHECK(network_time); |
| if (network_time_.is_null()) |
| return false; |
| DCHECK(!network_time_ticks_.is_null()); |
| *network_time = network_time_ + (time_ticks - network_time_ticks_); |
| if (uncertainty) |
| *uncertainty = network_time_uncertainty_; |
| return true; |
| } |
| |
| // static |
| // Note: UpdateNetworkNotifier is exposed via callback because getting the IO |
| // thread pointer must be done on the UI thread, while components that provide |
| // network time updates may live on other threads. |
| NetworkTimeTracker::UpdateCallback |
| NetworkTimeTracker::BuildNotifierUpdateCallback() { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| return base::Bind(&UpdateNetworkNotifier, |
| g_browser_process->io_thread()); |
| } |
| |
| net::NetworkTimeNotifier::ObserverCallback |
| NetworkTimeTracker::BuildObserverCallback() { |
| return base::Bind(&OnNetworkTimeUpdatedOnIOThread, |
| base::MessageLoop::current()->message_loop_proxy(), |
| base::Bind(&NetworkTimeTracker::OnNetworkTimeUpdate, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void NetworkTimeTracker::OnNetworkTimeUpdate( |
| const base::Time& network_time, |
| const base::TimeTicks& network_time_ticks, |
| const base::TimeDelta& network_time_uncertainty) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| network_time_ = network_time; |
| network_time_ticks_ = network_time_ticks; |
| network_time_uncertainty_ = network_time_uncertainty; |
| received_network_time_ = true; |
| } |
| |