blob: 84392dc053f83387483ee0178653f907b9c83f60 [file] [log] [blame] [edit]
// Copyright 2026 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/system_time_tracker.h"
#include <lib/syslog/cpp/macros.h>
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include "src/developer/forensics/feedback/constants.h"
#include "src/lib/files/file.h"
namespace forensics::feedback {
namespace {
constexpr char kSystemTimeTrackerRuntimeKey[] = "runtime_ms";
constexpr char kSystemTimeTrackerUptimeKey[] = "uptime_ms";
} // namespace
std::optional<SystemTime> GetPreviousSystemTime(const std::string& path) {
std::string time_str;
if (!files::ReadFileToString(path, &time_str)) {
FX_LOGS(WARNING) << "Failed to read system time from: " << path;
return std::nullopt;
}
rapidjson::Document doc;
if (doc.Parse(time_str.c_str()).HasParseError() || !doc.IsObject()) {
FX_LOGS(WARNING) << "Failed to parse system time JSON from: " << path;
return std::nullopt;
}
SystemTime time;
if (doc.HasMember(kSystemTimeTrackerUptimeKey) && doc[kSystemTimeTrackerUptimeKey].IsInt64()) {
time.uptime = zx::msec(doc[kSystemTimeTrackerUptimeKey].GetInt64());
}
if (doc.HasMember(kSystemTimeTrackerRuntimeKey) && doc[kSystemTimeTrackerRuntimeKey].IsInt64()) {
time.runtime = zx::msec(doc[kSystemTimeTrackerRuntimeKey].GetInt64());
}
return time;
}
SystemTimeTracker::SystemTimeTracker(async_dispatcher_t* dispatcher, timekeeper::Clock* clock,
zx::duration write_period, std::string write_path)
: dispatcher_(dispatcher),
clock_(clock),
write_period_(write_period),
write_path_(std::move(write_path)) {}
void SystemTimeTracker::Start() { WriteTimeTask(); }
void SystemTimeTracker::RecordSystemShutdownSignal() { WriteUptimeAndRuntime(); }
void SystemTimeTracker::WriteTimeTask() {
WriteUptimeAndRuntime();
write_time_task_.PostDelayed(dispatcher_, write_period_);
}
void SystemTimeTracker::WriteUptimeAndRuntime() {
rapidjson::Document doc;
doc.SetObject();
const int64_t uptime = zx::duration(clock_->BootNow().to_timespec()).to_msecs();
const int64_t runtime = zx::duration(clock_->MonotonicNow().to_timespec()).to_msecs();
doc.AddMember(kSystemTimeTrackerUptimeKey, uptime, doc.GetAllocator());
doc.AddMember(kSystemTimeTrackerRuntimeKey, runtime, doc.GetAllocator());
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
doc.Accept(writer);
if (!files::WriteFile(write_path_, buffer.GetString(), buffer.GetSize())) {
FX_LOGS_FIRST_N(ERROR, 10) << "Failed to write system time to: " << write_path_;
}
}
} // namespace forensics::feedback