blob: 9beda5fff4d58202d3ee94db110abadc43ec3a69 [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/crash_reports/info/inspect_manager.h"
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/time.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <map>
#include <utility>
#include "src/developer/forensics/crash_reports/constants.h"
#include "src/developer/forensics/crash_reports/errors.h"
#include "src/developer/forensics/utils/time.h"
#include "src/lib/files/path.h"
#include "src/lib/fxl/strings/substitute.h"
namespace forensics {
namespace crash_reports {
namespace {
using files::JoinPath;
using inspect::Node;
std::string CurrentTime(timekeeper::Clock* clock) {
auto current_time = CurrentUtcTime(clock);
if (current_time.has_value()) {
return current_time.value();
} else {
FX_LOGS(ERROR) << "Failed to get current UTC time";
return "unknown";
}
}
} // namespace
InspectManager::Report::Report(const std::string& program_name,
const std::string& local_report_id) {
path_ = JoinPath("/crash_reporter/reports",
JoinPath(InspectNodeManager::SanitizeString(program_name), local_report_id));
}
InspectManager::InspectManager(inspect::Node* root_node, timekeeper::Clock* clock)
: node_manager_(root_node), clock_(clock) {
node_manager_.Get("/config/crash_server");
node_manager_.Get("/crash_reporter/queue");
node_manager_.Get("/crash_reporter/reports");
node_manager_.Get("/crash_reporter/settings");
}
bool InspectManager::AddReport(const std::string& program_name,
const std::string& local_report_id) {
if (Contains(local_report_id)) {
FX_LOGS(ERROR) << fxl::Substitute("Local report $0 already exposed in Inspect",
local_report_id);
return false;
}
reports_.emplace(local_report_id, Report(program_name, local_report_id));
Report& report = reports_.at(local_report_id);
inspect::Node& report_node = node_manager_.Get(report.Path());
report.creation_time_ = report_node.CreateString("creation_time", CurrentTime(clock_));
return true;
}
bool InspectManager::SetUploadAttempt(const std::string& local_report_id, uint64_t upload_attempt) {
if (!Contains(local_report_id)) {
FX_LOGS(ERROR) << "Failed to find local report " << local_report_id;
return false;
}
Report& report = reports_.at(local_report_id);
if (!report.upload_attempts_) {
report.upload_attempts_ = node_manager_.Get(report.Path()).CreateUint("upload_attempts", 1u);
} else {
report.upload_attempts_.Set(upload_attempt);
}
return true;
}
bool InspectManager::MarkReportAsUploaded(const std::string& local_report_id,
const std::string& server_properties_report_id) {
if (!Contains(local_report_id)) {
FX_LOGS(ERROR) << "Failed to find local report " << local_report_id;
return false;
}
Report& report = reports_.at(local_report_id);
report.final_state_ = node_manager_.Get(report.Path()).CreateString("final_state", "uploaded");
const std::string server_path = JoinPath(report.Path(), "crash_server");
inspect::Node& server = node_manager_.Get(server_path);
report.server_id_ = server.CreateString("id", server_properties_report_id);
report.server_creation_time_ = server.CreateString("creation_time", CurrentTime(clock_));
return true;
}
bool InspectManager::MarkReportAsArchived(const std::string& local_report_id) {
if (!Contains(local_report_id)) {
FX_LOGS(ERROR) << "Failed to find local report " << local_report_id;
return false;
}
Report& report = reports_.at(local_report_id);
report.final_state_ = node_manager_.Get(report.Path()).CreateString("final_state", "archived");
return true;
}
bool InspectManager::MarkReportAsGarbageCollected(const std::string& local_report_id) {
if (!Contains(local_report_id)) {
FX_LOGS(ERROR) << "Failed to find local report " << local_report_id;
return false;
}
Report& report = reports_.at(local_report_id);
report.final_state_ =
node_manager_.Get(report.Path()).CreateString("final_state", "garbage_collected");
return true;
}
void InspectManager::ExposeConfig(const crash_reports::Config& config) {
auto* crash_server = &config_.crash_server;
inspect::Node& server = node_manager_.Get("/config/crash_server");
crash_server->upload_policy =
server.CreateString(kCrashServerUploadPolicyKey, ToString(config.crash_server.upload_policy));
}
void InspectManager::ExposeReportingPolicy(ReportingPolicyWatcher* watcher) {
settings_.upload_policy = node_manager_.Get("/crash_reporter/settings")
.CreateString("upload_policy", ToString(watcher->CurrentPolicy()));
watcher->OnPolicyChange(
[=](const ReportingPolicy policy) { settings_.upload_policy.Set(ToString(policy)); });
}
void InspectManager::SetQueueSize(const uint64_t size) {
inspect::Node& queue = node_manager_.Get("/crash_reporter/queue");
if (!queue_.size) {
queue_.size = queue.CreateUint("size", size);
} else {
queue_.size.Set(size);
}
}
bool InspectManager::Contains(const std::string& local_report_id) {
return reports_.find(local_report_id) != reports_.end();
}
void InspectManager::ExposeStore(const StorageSize max_size) {
store_.max_size_in_kb = node_manager_.Get("/crash_reporter/store")
.CreateUint("max_size_in_kb", max_size.ToKilobytes());
}
void InspectManager::IncreaseReportsGarbageCollectedBy(uint64_t num_reports) {
if (!store_.num_garbage_collected) {
store_.num_garbage_collected = node_manager_.Get("/crash_reporter/store")
.CreateUint("num_reports_garbage_collected", num_reports);
} else {
store_.num_garbage_collected.Add(num_reports);
}
}
void InspectManager::UpsertComponentToProductMapping(const std::string& component_url,
const crash_reports::Product& product) {
const std::string path =
JoinPath("/crash_register/mappings", InspectNodeManager::SanitizeString(component_url));
inspect::Node& node = node_manager_.Get(path);
component_to_products_[component_url] = Product{
.name = node.CreateString("name", product.name),
.version = node.CreateString("version", product.version.HasValue()
? product.version.Value()
: ToReason(product.version.Error())),
.channel = node.CreateString("channel", product.channel.HasValue()
? product.channel.Value()
: ToReason(product.channel.Error())),
};
}
} // namespace crash_reports
} // namespace forensics