| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_SYS_TIME_NETWORK_TIME_SERVICE_SERVICE_H_ |
| #define SRC_SYS_TIME_NETWORK_TIME_SERVICE_SERVICE_H_ |
| |
| #include <fuchsia/time/external/cpp/fidl.h> |
| #include <lib/async/cpp/task.h> |
| #include <lib/sys/cpp/component_context.h> |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include "lib/fidl/cpp/binding_set.h" |
| #include "src/sys/time/lib/network_time/time_server_config.h" |
| #include "src/sys/time/network_time_service/inspect.h" |
| #include "src/sys/time/network_time_service/watcher.h" |
| |
| const uint64_t kMinNanosBetweenFailures = 1 * 1'000'000'000u; |
| const uint32_t kMaxRetryExponent = 3; |
| const uint32_t kTriesPerExponent = 3; |
| const uint64_t kNanosBetweenSuccesses = 30 * 60 * ((uint64_t)1'000'000'000u); |
| |
| namespace time_external = fuchsia::time::external; |
| namespace network_time_service { |
| |
| // Defines how the |TimeServiceImpl| PushSource polls for updates. Retry time for |
| // errors begins with |min_nanos_between_failures|, and doubles after |tries_per_exponent| |
| // failures. |
| class RetryConfig { |
| public: |
| RetryConfig(uint64_t min_nanos_between_failures = kMinNanosBetweenFailures, |
| uint32_t max_exponent = kMaxRetryExponent, |
| uint32_t tries_per_exponent = kTriesPerExponent, |
| uint64_t nanos_between_successes = kNanosBetweenSuccesses) |
| : nanos_between_successes(nanos_between_successes), |
| min_nanos_between_failures_(min_nanos_between_failures), |
| max_exponent_(max_exponent), |
| tries_per_exponent_(tries_per_exponent){}; |
| |
| // Returns the duration to wait for the |retry_number|th retry. The first retry |
| // is denoted 0. |
| zx::duration WaitAfterFailure(uint32_t retry_number) { |
| uint32_t exponent = std::min(retry_number / tries_per_exponent_, max_exponent_); |
| return zx::nsec(min_nanos_between_failures_ << exponent); |
| } |
| |
| uint64_t nanos_between_successes; |
| |
| private: |
| uint64_t min_nanos_between_failures_; |
| uint32_t max_exponent_; |
| uint32_t tries_per_exponent_; |
| }; |
| |
| // Implementation of the FIDL time services. |
| // TODO(fxbug.dev/58068): This currently assumes that there is only a single client. To support |
| // multiple clients, this needs to retain per-client state so that it understands when |
| // a value hasn't been returned yet to a particular client, and so that it can close |
| // channels to only a single client as needed. |
| class TimeServiceImpl : public time_external::PushSource { |
| public: |
| // Constructs the time service with a caller-owned application context. |
| TimeServiceImpl(std::unique_ptr<sys::ComponentContext> context, |
| time_server::RoughTimeServer rough_time_server, async_dispatcher_t* dispatcher, |
| Inspect inspect, RetryConfig retry_config = RetryConfig()); |
| ~TimeServiceImpl(); |
| |
| // |PushSource|: |
| void UpdateDeviceProperties(time_external::Properties properties) override; |
| |
| // |PushSource|: |
| void WatchSample(WatchSampleCallback callback) override; |
| |
| // |PushSource|: |
| void WatchStatus(WatchStatusCallback callback) override; |
| |
| private: |
| // Polls for new time samples and post changes to the time source status. |
| void AsyncPollSamples(async_dispatcher_t* dispatcher, async::TaskBase* task, zx_status_t status); |
| |
| // Schedules a sample poll to begin at the specified time in the dispatcher's clock. |
| void ScheduleAsyncPoll(zx::time dispatch_time); |
| |
| // Remove the PushSource client with the specified epitaph and reset client state. |
| void ResetPushSourceClient(zx_status_t epitaph); |
| |
| std::unique_ptr<sys::ComponentContext> context_; |
| time_server::RoughTimeServer rough_time_server_; |
| Inspect inspect_; |
| |
| fidl::Binding<time_external::PushSource> push_source_binding_; |
| Watcher<time_external::Status> status_watcher_; |
| Watcher<time_external::TimeSample> sample_watcher_; |
| |
| async_dispatcher_t* dispatcher_; |
| // Time of last successful update. Reported in the dispatcher's clock which may not be monotonic. |
| std::optional<zx::time> dispatcher_last_success_time_; |
| uint32_t consecutive_poll_failures_; |
| async::TaskMethod<TimeServiceImpl, &TimeServiceImpl::AsyncPollSamples> sample_poll_task_{this}; |
| RetryConfig retry_config_; |
| }; |
| |
| // Estimate the standard deviation based on the monotonic times taken before and after a server was |
| // polled. |
| zx_time_t EstimateStandardDeviation(zx_time_t mono_before, zx_time_t mono_after); |
| |
| } // namespace network_time_service |
| |
| #endif // SRC_SYS_TIME_NETWORK_TIME_SERVICE_SERVICE_H_ |