blob: c37718faaf8f0147abcc44b4ecb14dd69907ef26 [file] [log] [blame]
// 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_