text: // Copyright (c) 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 "net/base/network_time_notifier.h"
  
  #include "base/basictypes.h"
  #include "base/bind.h"
  #include "base/i18n/time_formatting.h"
  #include "base/location.h"
  #include "base/message_loop/message_loop.h"
  #include "base/stl_util.h"
  #include "base/strings/utf_string_conversions.h"
  
  namespace {
  
  // Clock resolution is platform dependent.
  #if defined(OS_WIN)
  const int64 kTicksResolutionMs = base::Time::kMinLowResolutionThresholdMs;
  #else
  const int64 kTicksResolutionMs = 1;  // Assume 1ms for non-windows platforms.
  #endif
  
  // Number of time measurements performed in a given network time calculation.
  const int kNumTimeMeasurements = 5;
  
  }  // namespace
  
  namespace net {
  
  NetworkTimeNotifier::NetworkTimeNotifier(
      scoped_ptr<base::TickClock> tick_clock) {
    tick_clock_ = tick_clock.Pass();
  }
  
  NetworkTimeNotifier::~NetworkTimeNotifier() {}
  
  void NetworkTimeNotifier::UpdateNetworkTime(const base::Time& network_time,
                                              const base::TimeDelta& resolution,
                                              const base::TimeDelta& latency,
                                              const base::TimeTicks& post_time) {
    DCHECK(thread_checker_.CalledOnValidThread());
    DVLOG(1) << "Network time updating to "
             << base::UTF16ToUTF8(
                    base::TimeFormatFriendlyDateAndTime(network_time));
    // Update network time on every request to limit dependency on ticks lag.
    // TODO(mad): Find a heuristic to avoid augmenting the
    // network_time_uncertainty_ too much by a particularly long latency.
    // Maybe only update when the the new time either improves in accuracy or
    // drifts too far from |network_time_|.
    network_time_ = network_time;
  
    // Calculate the delay since the network time was received.
    base::TimeTicks now = tick_clock_->NowTicks();
    base::TimeDelta task_delay = now - post_time;
    // Estimate that the time was set midway through the latency time.
    network_time_ticks_ = now - task_delay - latency / 2;
  
    // Can't assume a better time than the resolution of the given time
    // and 5 ticks measurements are involved, each with their own uncertainty.
    // 1 & 2 are the ones used to compute the latency, 3 is the Now() from when
    // this task was posted, 4 is the Now() above and 5 will be the Now() used in
    // GetNetworkTime().
    network_time_uncertainty_ =
        resolution + latency + kNumTimeMeasurements *
        base::TimeDelta::FromMilliseconds(kTicksResolutionMs);
  
    for (size_t i = 0; i < observers_.size(); ++i) {
      base::MessageLoop::current()->PostTask(
          FROM_HERE,
          base::Bind(observers_[i],
                     network_time_,
                     network_time_ticks_,
                     network_time_uncertainty_));
    }
  }
  
  void NetworkTimeNotifier::AddObserver(
      const ObserverCallback& observer_callback) {
    DCHECK(thread_checker_.CalledOnValidThread());
    observers_.push_back(observer_callback);
    if (!network_time_.is_null()) {
      base::MessageLoop::current()->PostTask(
          FROM_HERE,
          base::Bind(observer_callback,
                     network_time_,
                     network_time_ticks_,
                     network_time_uncertainty_));
    }
  }
  
  }  // namespace net
  