| # HTTPSDate Timesource | |
| The HTTPSDate Timesource implements the | |
| [`fuchsia.time.external.PushSource`][time-fidl] protocol. It retrieves time | |
| samples by calling an HTTPS URL specified in the component configuration and | |
| pulling the time off the Date header in the response. HTTPSDate relies on the | |
| underlying TLS connection for server authentication. As the device on which | |
| HTTPSDate is running may not have a valid UTC time, expiry dates on TLS | |
| certificates are checked for consistency against the time reported by the | |
| server. | |
| ## Key Assumptions | |
| HTTPSDate relies on the server to conform to the standards defined for the Date | |
| HTTP header as defined in [RFC 2616][rfc-2616], in particular that the server | |
| has a reasonably accurate time, and that the date is sampled at the time of | |
| message generation. | |
| HTTPSDate also relies on some assumptions not in the RFC: | |
| * The servers polled to produce a single sample are synced to the same time | |
| source. | |
| * The servers truncate time down to the second. | |
| When these additional assumptions break down, the accuracy of time on the | |
| device is affected: | |
| * If servers are inconsistently synced or truncated the time samples produced | |
| will likely contain more noise. | |
| * If servers consistently round time in a different manner (such as rounding | |
| up) the time samples will contain a systemic error of up to a second. | |
| ## Design Overview | |
| HTTPSDate contains an algorithm to produce a sample from network polls, and a | |
| scheduler that determines when to produce a sample. | |
| ### Sampling Algorithm | |
| The sampling algorithm is responsible for producing a single time sample. | |
| A fundamental limitation of using HTTP Date headers is that the header has a | |
| resolution of seconds. The sampling algorithm attempts to improve the | |
| resolution of a produced sample by combining the results of multiple polls. | |
| Note that for simplicity the discussion here ignores the effects of network | |
| latency and drift between the device and server's clock, but they are taken | |
| into account in the implementation. | |
| The algorithm encapsulates the information obtained from polling a server once | |
| in a _bound_. A _bound_ is a tuple `(monotonic, utc_min, utc_max)` that defines | |
| the range of possible UTC times for a given monotonic time. When a server is | |
| polled at monotonic time `t_mono`, the server returns some UTC time `t_server`. | |
| Because the server is assumed to truncate time down to the nearest second, | |
| `t_server` is a whole number of seconds, and the actual UTC time at `t_mono` is | |
| in the range `[t_server, t_server + 1]`. This is expressed as the bound | |
| `(t_mono, t_server, t_server + 1)`. | |
| The following operations are possible on bounds: | |
| * _Projection_ - A bound `(t_mono, t_utc_min, t_utc_max)` may be _projected_ to | |
| a later monotonic time `t_mono_later` by adding `t_mono_later - t_mono` to each | |
| value in the tuple. | |
| * _Combination_ - Two bounds at the same monotonic time may be _combined_ by | |
| taking the intersection of their UTC ranges. _Combining_ two polls produces | |
| a single bound that usually has a smaller bound and therefore lower | |
| uncertainty. | |
| These operations allow combining the results of any two polls by _projecting_ | |
| the earlier bound to the time of the later poll, then _combining_ the resulting | |
| polls. | |
| The algorithm polls the server a few times and combines the resulting bounds | |
| into a single tighter bound. The algorithm makes a best effort to poll at | |
| intervals such that the size of the accumulated bound is halved after each | |
| poll. The final bound is then converted to a single sample. | |
| ### Scheduler | |
| The scheduler is responsible for periodically producing samples by invoking the | |
| sampling algorithm, and retrying in case of failure. The scheduler progresses | |
| through three phases that invoke the sampling algorithm at different timings | |
| and parameters: | |
| * _Initial phase_ - comprised of the first sample only, which is produced with | |
| fewer polls than subsequent polls. This optimizes to start the system clock as | |
| early as possible at the cost of accuracy. | |
| * _Converge phase_ - comprised of the first few subsequent samples. Samples are | |
| produced relatively frequently so that the system clock can converge on an | |
| accurate time. | |
| * _Maintain phase_ - comprised of all remaining samples. Samples are produced | |
| infrequently so that an accurate time can be maintained. | |
| [time-fidl]: https://fuchsia.dev/reference/fidl/fuchsia.time.external#PushSource | |
| [rfc-2616]: https://tools.ietf.org/html/rfc2616 |