// Copyright 2014 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_NETWORK_TIME_NETWORK_TIME_TRACKER_H_ #define COMPONENTS_NETWORK_TIME_NETWORK_TIME_TRACKER_H_ #include #include #include #include #include "base/feature_list.h" #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "base/observer_list_types.h" #include "base/threading/thread_checker.h" #include "base/time/clock.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "build/build_config.h" #include "components/network_time/time_tracker/time_tracker.h" #include "url/gurl.h" class PrefRegistrySimple; class PrefService; namespace base { class TickClock; } // namespace base namespace client_update_protocol { class Ecdsa; } // namespace client_update_protocol namespace network { class SimpleURLLoader; class SharedURLLoaderFactory; } // namespace network namespace network_time { // Clock resolution is platform dependent. #if BUILDFLAG(IS_WIN) const int64_t kTicksResolutionMs = base::Time::kMinLowResolutionThresholdMs; #else const int64_t kTicksResolutionMs = 1; // Assume 1ms for non-windows platforms. #endif // Feature that enables network time service querying. BASE_DECLARE_FEATURE(kNetworkTimeServiceQuerying); // A class that receives network time updates and can provide the network time // for a corresponding local time. This class is not thread safe. class NetworkTimeTracker { public: // Describes the result of a GetNetworkTime() call, describing whether // network time was available and if not, why not. enum NetworkTimeResult { // Network time is available. NETWORK_TIME_AVAILABLE, // A time has been retrieved from the network in the past, but // network time is no longer available because the tracker fell out // of sync due to, for example, a suspend/resume. NETWORK_TIME_SYNC_LOST, // Network time is unavailable because the tracker has not yet // attempted to retrieve a time from the network. NETWORK_TIME_NO_SYNC_ATTEMPT, // Network time is unavailable because the tracker has not yet // successfully retrieved a time from the network (at least one // attempt has been made but all have failed). NETWORK_TIME_NO_SUCCESSFUL_SYNC, // Network time is unavailable because the tracker has not yet // attempted to retrieve a time from the network, but the first // attempt is currently pending. NETWORK_TIME_FIRST_SYNC_PENDING, // Network time is unavailable because the tracker has made failed // attempts to retrieve a time from the network, but an attempt is // currently pending. NETWORK_TIME_SUBSEQUENT_SYNC_PENDING, }; // Describes the behavior of fetches to the network time service. enum FetchBehavior { // Only used in case of an unrecognize Finch experiment parameter. FETCH_BEHAVIOR_UNKNOWN, // Time queries will be issued in the background as needed. FETCHES_IN_BACKGROUND_ONLY, // Time queries will not be issued except when StartTimeFetch() is called. FETCHES_ON_DEMAND_ONLY, // Time queries will be issued both in the background as needed and also // on-demand. FETCHES_IN_BACKGROUND_AND_ON_DEMAND, }; class NetworkTimeObserver : public base::CheckedObserver { public: virtual void OnNetworkTimeChanged( const TimeTracker::TimeTrackerState state) = 0; }; static void RegisterPrefs(PrefRegistrySimple* registry); // Constructor. Arguments may be stubbed out for tests. |url_loader_factory| // must be non-null unless the kNetworkTimeServiceQuerying is disabled. // Otherwise, time is available only if |UpdateNetworkTime| is called. // If |fetch_behavior| is not nullopt, it will control the behavior of the // NetworkTimeTracker, if it is nullopt, it will be controlled via a feature // parameter. NetworkTimeTracker( std::unique_ptr clock, std::unique_ptr tick_clock, PrefService* pref_service, scoped_refptr url_loader_factory, std::optional fetch_behavior); NetworkTimeTracker(const NetworkTimeTracker&) = delete; NetworkTimeTracker& operator=(const NetworkTimeTracker&) = delete; ~NetworkTimeTracker(); // Sets |network_time| to an estimate of the true time. Returns // NETWORK_TIME_AVAILABLE if time is available. If |uncertainty| is // non-NULL, it will be set to an estimate of the error range. // // If network time is unavailable, this method returns // NETWORK_TIME_SYNC_LOST or NETWORK_TIME_NO_SYNC to indicate the // reason. // // Network time may be available on startup if deserialized from a pref. // Failing that, a call to |UpdateNetworkTime| is required to make time // available to callers of |GetNetworkTime|. Subsequently, network time may // become unavailable if |NetworkTimeTracker| has reason to believe it is no // longer accurate. Consumers should even be prepared to handle the case // where calls to |GetNetworkTime| never once succeeds. NetworkTimeResult GetNetworkTime(base::Time* network_time, base::TimeDelta* uncertainty) const; // Starts a network time query if network time isn't already available // and if there isn't already a time query in progress. If a new query // is started or if there is one already in progress, |callback| will // run when the query completes. // // Returns true if a time query is started or was already in progress, // and false otherwise. For example, this method may return false if // time queries are disabled or if network time is already available. bool StartTimeFetch(base::OnceClosure callback); // Calculates corresponding time ticks according to the given parameters. // The provided |network_time| is precise at the given |resolution| and // represent the time between now and up to |latency| + (now - |post_time|) // ago. void UpdateNetworkTime(base::Time network_time, base::TimeDelta resolution, base::TimeDelta latency, base::TimeTicks post_time); bool AreTimeFetchesEnabled() const; FetchBehavior GetFetchBehavior() const; // Blocks until the the next time query completes. void WaitForFetch(); void AddObserver(NetworkTimeObserver* obs); void RemoveObserver(NetworkTimeObserver* obs); bool GetTrackerState(TimeTracker::TimeTrackerState* state) const; void SetMaxResponseSizeForTesting(size_t limit); void SetPublicKeyForTesting(std::string_view key); void SetTimeServerURLForTesting(const GURL& url); GURL GetTimeServerURLForTesting() const; bool QueryTimeServiceForTesting(); void WaitForFetchForTesting(uint32_t nonce); void OverrideNonceForTesting(uint32_t nonce); base::TimeDelta GetTimerDelayForTesting() const; void ClearNetworkTimeForTesting(); private: // Checks whether a network time query should be issued, and issues one if so. // Upon response, execution resumes in |OnURLFetchComplete|. void CheckTime(); // Updates network time from a time server response, returning true // if successful. bool UpdateTimeFromResponse(std::unique_ptr response_body); // Called to process responses from the secure time service. void OnURLLoaderComplete(std::unique_ptr response_body); // Sets the next time query to be run at the specified time. void QueueCheckTime(base::TimeDelta delay); // Returns true if there's sufficient reason to suspect that // NetworkTimeTracker does not know what time it is. This returns true // unconditionally every once in a long while, just to be on the safe side. bool ShouldIssueTimeQuery(); void NotifyObservers(); // State variables for internally-managed secure time service queries. GURL server_url_; size_t max_response_size_; base::TimeDelta backoff_; // Timer that runs CheckTime(). All backoff and delay is implemented by // changing the delay of this timer, with the result that CheckTime() may // assume that if it runs, it is eligible to issue a time query. base::RepeatingTimer timer_; scoped_refptr url_loader_factory_; std::unique_ptr time_fetcher_; std::unique_ptr query_signer_; // The |Clock| and |TickClock| are used to sanity-check one another, allowing // the NetworkTimeTracker to notice e.g. suspend/resume events and clock // resets. std::unique_ptr clock_; std::unique_ptr tick_clock_; raw_ptr pref_service_; // True if any time query has completed (but not necessarily succeeded) in // this NetworkTimeTracker's lifetime. bool time_query_completed_; // The time that was received from the last network time fetch made by // CheckTime(). Unlike the time used inside |tracker_| this time is not // updated when UpdateNetworkTime() is called. Used for UMA metrics. base::Time last_fetched_time_; // Callbacks to run when the in-progress time fetch completes. std::vector fetch_completion_callbacks_; base::ThreadChecker thread_checker_; std::optional fetch_behavior_; std::optional tracker_; base::ObserverList observers_; }; } // namespace network_time #endif // COMPONENTS_NETWORK_TIME_NETWORK_TIME_TRACKER_H_