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
3 // found in the LICENSE file.
5 #include "components/network_time/network_time_tracker.h"
7 #include "base/basictypes.h"
8 #include "base/i18n/time_formatting.h"
9 #include "base/logging.h"
10 #include "base/prefs/pref_registry_simple.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/tick_clock.h"
14 #include "components/network_time/network_time_pref_names.h"
16 namespace network_time
{
20 // Clock resolution is platform dependent.
22 const int64 kTicksResolutionMs
= base::Time::kMinLowResolutionThresholdMs
;
24 const int64 kTicksResolutionMs
= 1; // Assume 1ms for non-windows platforms.
27 // Number of time measurements performed in a given network time calculation.
28 const int kNumTimeMeasurements
= 5;
33 void NetworkTimeTracker::RegisterPrefs(PrefRegistrySimple
* registry
) {
34 registry
->RegisterDictionaryPref(prefs::kNetworkTimeMapping
,
35 new base::DictionaryValue());
38 NetworkTimeTracker::NetworkTimeTracker(scoped_ptr
<base::TickClock
> tick_clock
,
39 PrefService
* pref_service
)
40 : tick_clock_(tick_clock
.Pass()),
41 pref_service_(pref_service
),
42 received_network_time_(false) {
43 const base::DictionaryValue
* time_mapping
=
44 pref_service_
->GetDictionary(prefs::kNetworkTimeMapping
);
45 double local_time_js
= 0;
46 double network_time_js
= 0;
47 if (time_mapping
->GetDouble("local", &local_time_js
) &&
48 time_mapping
->GetDouble("network", &network_time_js
)) {
49 base::Time local_time_saved
= base::Time::FromJsTime(local_time_js
);
50 base::Time local_time_now
= base::Time::Now();
51 if (local_time_saved
> local_time_now
||
52 local_time_now
- local_time_saved
> base::TimeDelta::FromDays(7)) {
53 // Drop saved mapping if clock skew has changed or the data is too old.
54 pref_service_
->ClearPref(prefs::kNetworkTimeMapping
);
56 network_time_
= base::Time::FromJsTime(network_time_js
) +
57 (local_time_now
- local_time_saved
);
58 network_time_ticks_
= base::TimeTicks::Now();
63 NetworkTimeTracker::~NetworkTimeTracker() {
64 DCHECK(thread_checker_
.CalledOnValidThread());
67 void NetworkTimeTracker::UpdateNetworkTime(base::Time network_time
,
68 base::TimeDelta resolution
,
69 base::TimeDelta latency
,
70 base::TimeTicks post_time
) {
71 DCHECK(thread_checker_
.CalledOnValidThread());
72 DVLOG(1) << "Network time updating to "
74 base::TimeFormatFriendlyDateAndTime(network_time
));
75 // Update network time on every request to limit dependency on ticks lag.
76 // TODO(mad): Find a heuristic to avoid augmenting the
77 // network_time_uncertainty_ too much by a particularly long latency.
78 // Maybe only update when the the new time either improves in accuracy or
79 // drifts too far from |network_time_|.
80 network_time_
= network_time
;
82 // Calculate the delay since the network time was received.
83 base::TimeTicks now
= tick_clock_
->NowTicks();
84 base::TimeDelta task_delay
= now
- post_time
;
85 // Estimate that the time was set midway through the latency time.
86 network_time_ticks_
= now
- task_delay
- latency
/ 2;
88 // Can't assume a better time than the resolution of the given time
89 // and 5 ticks measurements are involved, each with their own uncertainty.
90 // 1 & 2 are the ones used to compute the latency, 3 is the Now() from when
91 // this task was posted, 4 is the Now() above and 5 will be the Now() used in
93 network_time_uncertainty_
=
94 resolution
+ latency
+ kNumTimeMeasurements
*
95 base::TimeDelta::FromMilliseconds(kTicksResolutionMs
);
97 received_network_time_
= true;
99 base::Time network_time_now
;
100 if (GetNetworkTime(base::TimeTicks::Now(), &network_time_now
, NULL
)) {
101 // Update time mapping if tracker received time update from server, i.e.
102 // mapping is accurate.
103 base::Time local_now
= base::Time::Now();
104 base::DictionaryValue time_mapping
;
105 time_mapping
.SetDouble("local", local_now
.ToJsTime());
106 time_mapping
.SetDouble("network", network_time_now
.ToJsTime());
107 pref_service_
->Set(prefs::kNetworkTimeMapping
, time_mapping
);
111 bool NetworkTimeTracker::GetNetworkTime(base::TimeTicks time_ticks
,
112 base::Time
* network_time
,
113 base::TimeDelta
* uncertainty
) const {
114 DCHECK(thread_checker_
.CalledOnValidThread());
115 DCHECK(network_time
);
116 if (network_time_
.is_null())
118 DCHECK(!network_time_ticks_
.is_null());
119 *network_time
= network_time_
+ (time_ticks
- network_time_ticks_
);
121 *uncertainty
= network_time_uncertainty_
;
125 } // namespace network_time