blob: ae1daf19ef443012adb62fe4bc45883c2041a01f [file] [log] [blame]
// Copyright 2019 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.
#include "src/developer/forensics/feedback/annotations/time_provider.h"
#include <fuchsia/time/cpp/fidl.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/time.h>
#include <string>
#include "src/developer/forensics/feedback/annotations/constants.h"
#include "src/developer/forensics/utils/errors.h"
#include "src/developer/forensics/utils/time.h"
namespace forensics::feedback {
namespace {
ErrorOrString GetFormattedDuration(zx::duration duration, std::string_view error_source) {
const std::optional<std::string> formatted_duration = FormatDuration(duration);
if (!formatted_duration) {
FX_LOGS(ERROR) << "Got negative value from '" << error_source << "'";
return ErrorOrString(Error::kBadValue);
}
return ErrorOrString(*formatted_duration);
}
} // namespace
TimeProvider::TimeProvider(async_dispatcher_t* dispatcher, zx::unowned_clock clock_handle,
std::unique_ptr<timekeeper::Clock> clock)
: clock_(std::move(clock)),
wait_for_logging_quality_clock_(this, clock_handle->get_handle(),
fuchsia::time::SIGNAL_UTC_CLOCK_LOGGING_QUALITY,
/*options=*/0) {
if (const zx_status_t status = wait_for_logging_quality_clock_.Begin(dispatcher);
status != ZX_OK) {
FX_PLOGS(FATAL, status) << "Failed to wait for logging quality clock";
}
}
std::set<std::string> TimeProvider::GetAnnotationKeys() {
return {
kDeviceRuntimeKey,
kDeviceTotalSuspendedTimeKey,
kDeviceUptimeKey,
kDeviceUtcTimeKey,
};
}
std::set<std::string> TimeProvider::GetKeys() const { return TimeProvider::GetAnnotationKeys(); }
Annotations TimeProvider::Get() {
const auto utc_time = [this]() -> ErrorOrString {
if (is_utc_time_accurate_) {
return ErrorOrString(CurrentUtcTime(clock_.get()));
}
return ErrorOrString(Error::kMissingValue);
}();
const zx::duration monotonic_now = zx::duration(clock_->MonotonicNow().to_timespec());
const zx::duration boot_now = zx::duration(clock_->BootNow().to_timespec());
const zx::duration time_suspended = boot_now - monotonic_now;
return {
{kDeviceRuntimeKey, GetFormattedDuration(monotonic_now, "timekeeper::Clock::MonotonicNow()")},
{kDeviceTotalSuspendedTimeKey,
GetFormattedDuration(time_suspended,
"timekeeper::Clock::BootNow() - timekeeper::Clock::MonotonicNow()")},
{kDeviceUptimeKey, GetFormattedDuration(boot_now, "timekeeper::Clock::BootNow()")},
{kDeviceUtcTimeKey, utc_time},
};
}
void TimeProvider::OnClockLoggingQuality(async_dispatcher_t* dispatcher, async::WaitBase* wait,
zx_status_t status, const zx_packet_signal_t* signal) {
if (status != ZX_OK) {
FX_PLOGS(WARNING, status)
<< "Wait for logging quality clock completed with error, trying again";
// Attempt to wait for the clock to achieve logging quality again.
wait->Begin(dispatcher);
return;
}
FX_LOGS(INFO) << "Received signal that UTC clock is accurate";
is_utc_time_accurate_ = true;
}
} // namespace forensics::feedback