text: // 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_service.h"
  
  #include "base/command_line.h"
  #include "base/prefs/pref_service.h"
  #include "chrome/browser/network_time/network_time_tracker.h"
  #include "chrome/browser/profiles/profile.h"
  #include "chrome/common/chrome_switches.h"
  #include "chrome/common/pref_names.h"
  #include "components/user_prefs/pref_registry_syncable.h"
  
  // static
  void NetworkTimeService::RegisterProfilePrefs(
      user_prefs::PrefRegistrySyncable* registry) {
    registry->RegisterDictionaryPref(
        prefs::kNetworkTimeMapping,
        new base::DictionaryValue(),
        user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  }
  
  NetworkTimeService::NetworkTimeService(Profile* profile)
      : profile_(profile) {
    if (!CommandLine::ForCurrentProcess()->HasSwitch(
        switches::kEnableNetworkTime)) {
      return;
    }
  
    network_time_tracker_.reset(new NetworkTimeTracker);
    network_time_tracker_->Start();
  
    const base::DictionaryValue* time_mapping =
        profile_->GetPrefs()->GetDictionary(prefs::kNetworkTimeMapping);
    double local_time_js;
    double network_time_js;
    if (time_mapping->GetDouble("local", &local_time_js) &&
        time_mapping->GetDouble("network", &network_time_js)) {
      base::Time local_time_saved = base::Time::FromJsTime(local_time_js);
      if (local_time_saved > base::Time::Now() ||
          base::Time::Now() - local_time_saved > base::TimeDelta::FromDays(7)) {
        // Drop saved mapping if clock skew has changed or the data is too old.
        profile_->GetPrefs()->ClearPref(prefs::kNetworkTimeMapping);
      } else {
        network_time_tracker_->InitFromSavedTime(
            NetworkTimeTracker::TimeMapping(
                local_time_saved, base::Time::FromJsTime(network_time_js)));
      }
    }
  }
  
  NetworkTimeService::~NetworkTimeService() {}
  
  void NetworkTimeService::Shutdown() {
    if (!network_time_tracker_)
      return;
  
    if (network_time_tracker_->received_network_time()) {
      // Update time mapping if tracker received time update from server, i.e.
      // mapping is accurate.
      base::Time local_now = base::Time::Now();
      base::Time network_now = GetNetworkTime(local_now);
      base::DictionaryValue time_mapping;
      time_mapping.SetDouble("local", local_now.ToJsTime());
      time_mapping.SetDouble("network", network_now.ToJsTime());
      profile_->GetPrefs()->Set(prefs::kNetworkTimeMapping, time_mapping);
    }
  }
  
  base::Time NetworkTimeService::GetNetworkTime(
      const base::Time& local_time) {
    if (!network_time_tracker_.get() || local_time.is_null() ||
        local_time.is_max())
      return local_time;
  
    base::Time network_time_now;
    if (!network_time_tracker_->GetNetworkTime(base::TimeTicks::Now(),
                                               &network_time_now, NULL)) {
      return local_time;
    }
    return local_time + (network_time_now - base::Time::Now());
  }
  
  base::Time NetworkTimeService::GetNetworkNow() {
    return GetNetworkTime(base::Time::Now());
  }
  