blob: 644de34879062eb0c57d8779b92b94a6bbf3e452 [file] [log] [blame]
// Copyright 2021 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 <fuchsia/feedback/cpp/fidl.h>
#include <fuchsia/process/lifecycle/cpp/fidl.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/processargs.h>
#include <cstdlib>
#include <memory>
#include <fbl/unique_fd.h>
#include "src/developer/forensics/feedback/annotations/startup_annotations.h"
#include "src/developer/forensics/feedback/constants.h"
#include "src/developer/forensics/feedback/main_service.h"
#include "src/developer/forensics/feedback/namespace_init.h"
#include "src/developer/forensics/feedback/reboot_log/annotations.h"
#include "src/developer/forensics/feedback/reboot_log/reboot_log.h"
#include "src/developer/forensics/utils/cobalt/logger.h"
#include "src/developer/forensics/utils/component/component.h"
#include "src/developer/forensics/utils/storage_size.h"
#include "src/lib/files/file.h"
#include "src/lib/uuid/uuid.h"
namespace forensics::feedback {
int main() {
fuchsia_logging::SetTags({"forensics", "feedback"});
const std::optional<SnapshotConfig> snapshot_config = GetSnapshotConfig();
if (!snapshot_config) {
FX_LOGS(FATAL) << "Failed to get config for snapshot";
return EXIT_FAILURE;
}
const std::optional<BuildTypeConfig> build_type_config = GetBuildTypeConfig();
if (!build_type_config) {
FX_LOGS(FATAL) << "Failed to get config for build type";
return EXIT_FAILURE;
}
const std::optional<feedback::ProductConfig> product_config = feedback::GetProductConfig();
if (!product_config.has_value()) {
FX_LOGS(FATAL) << "Failed to parse product config";
return EXIT_FAILURE;
}
forensics::component::Component component;
std::unique_ptr<cobalt::Logger> cobalt = std::make_unique<cobalt::Logger>(
component.Dispatcher(), component.Services(), component.Clock());
const bool run_log_persistence = product_config->persisted_logs_num_files.has_value() &&
product_config->persisted_logs_total_size.has_value();
if (component.IsFirstInstance()) {
MovePreviousRebootReason();
if (run_log_persistence) {
CreatePreviousLogsFile(cobalt.get(), *product_config->persisted_logs_total_size);
} else {
// This is mostly done to preserve the previous boot logs when the device is migrating from
// "log persistence turned on" to "log persistence turned off" and then clean up the
// directory. It's a no-op if the directory doesn't exist in the first place.
// It does mean we need to give it a hint as to how large the total size now that the config
// no longer contains a number for it though.
CreatePreviousLogsFile(cobalt.get(), StorageSize::Kilobytes(512));
}
MoveAndRecordBootId(uuid::Generate());
if (std::string build_version; files::ReadFileToString(kBuildVersionPath, &build_version)) {
MoveAndRecordBuildVersion(build_version);
}
}
ExposeConfig(*component.InspectRoot(), *build_type_config, *product_config);
auto reboot_log = RebootLog::ParseRebootLog(
"/boot/log/last-panic.txt", kPreviousGracefulRebootReasonFile, TestAndSetNotAFdr());
std::optional<std::string> local_device_id_path = kDeviceIdPath;
if (files::IsFile(kUseRemoteDeviceIdProviderPath)) {
local_device_id_path = std::nullopt;
}
std::optional<zx::duration> delete_previous_boot_logs_time(std::nullopt);
if (files::IsFile(kPreviousLogsFilePath)) {
delete_previous_boot_logs_time = zx::hour(24);
}
const auto startup_annotations = GetStartupAnnotations(reboot_log);
zx::channel lifecycle_channel(zx_take_startup_handle(PA_LIFECYCLE));
std::unique_ptr<MainService> main_service = std::make_unique<MainService>(
component.Dispatcher(), component.Services(), component.Clock(), component.InspectRoot(),
cobalt.get(), startup_annotations,
fidl::InterfaceRequest<fuchsia::process::lifecycle::Lifecycle>(std::move(lifecycle_channel)),
MainService::Options{*build_type_config, local_device_id_path,
kCurrentGracefulRebootReasonFile,
LastReboot::Options{
.is_first_instance = component.IsFirstInstance(),
.reboot_log = reboot_log,
.oom_crash_reporting_delay = kOOMCrashReportingDelay,
},
CrashReports::Options{
.build_type_config = *build_type_config,
.snapshot_store_max_archives_size = kSnapshotArchivesMaxSize,
.snapshot_persistence_max_tmp_size =
product_config->snapshot_persistence_max_tmp_size,
.snapshot_persistence_max_cache_size =
product_config->snapshot_persistence_max_cache_size,
.snapshot_collector_window_duration = kSnapshotSharedRequestWindow,
},
FeedbackData::Options{
.config = *snapshot_config,
.is_first_instance = component.IsFirstInstance(),
.limit_inspect_data = build_type_config->enable_limit_inspect_data,
.run_log_persistence = run_log_persistence,
.delete_previous_boot_logs_time = delete_previous_boot_logs_time,
}});
component.AddPublicService(main_service->GetHandler<fuchsia::feedback::LastRebootInfoProvider>());
component.AddPublicService(main_service->GetHandler<fuchsia::feedback::CrashReporter>());
component.AddPublicService(
main_service->GetHandler<fuchsia::feedback::CrashReportingProductRegister>());
component.AddPublicService(main_service->GetHandler<fuchsia::feedback::ComponentDataRegister>());
component.AddPublicService(main_service->GetHandler<fuchsia::feedback::DataProvider>());
component.RunLoop();
return EXIT_SUCCESS;
}
} // namespace forensics::feedback