| // Copyright 2018 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/main_service.h" | 
 |  | 
 | #include <lib/syslog/cpp/macros.h> | 
 | #include <zircon/errors.h> | 
 | #include <zircon/types.h> | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "src/developer/forensics/crash_reports/config.h" | 
 | #include "src/developer/forensics/crash_reports/crash_register.h" | 
 | #include "src/lib/files/file.h" | 
 | #include "src/lib/fxl/strings/trim.h" | 
 |  | 
 | namespace forensics { | 
 | namespace crash_reports { | 
 | namespace { | 
 |  | 
 | const char kDefaultConfigPath[] = "/pkg/data/crash_reports/default_config.json"; | 
 | const char kOverrideConfigPath[] = "/config/data/crash_reports/override_config.json"; | 
 | const char kCrashRegisterPath[] = "/tmp/crash_register.json"; | 
 |  | 
 | }  // namespace | 
 |  | 
 | std::unique_ptr<MainService> MainService::TryCreate(async_dispatcher_t* dispatcher, | 
 |                                                     std::shared_ptr<sys::ServiceDirectory> services, | 
 |                                                     timekeeper::Clock* clock, | 
 |                                                     std::shared_ptr<InfoContext> info_context) { | 
 |   Config config; | 
 |  | 
 |   // We use the default config included in the package of this component if no override config was | 
 |   // specified or if we failed to parse the override config. | 
 |   bool use_default_config = true; | 
 |  | 
 |   if (files::IsFile(kOverrideConfigPath)) { | 
 |     use_default_config = false; | 
 |     if (const zx_status_t status = ParseConfig(kOverrideConfigPath, &config); status != ZX_OK) { | 
 |       // We failed to parse the override config: fall back to the default config. | 
 |       use_default_config = true; | 
 |       FX_PLOGS(ERROR, status) << "Failed to read override config file at " << kOverrideConfigPath | 
 |                               << " - falling back to default config file"; | 
 |     } | 
 |   } | 
 |  | 
 |   // Either there was no override config or we failed to parse it. | 
 |   if (use_default_config) { | 
 |     if (const zx_status_t status = ParseConfig(kDefaultConfigPath, &config); status != ZX_OK) { | 
 |       FX_PLOGS(ERROR, status) << "Failed to read default config file at " << kDefaultConfigPath; | 
 |  | 
 |       FX_LOGS(FATAL) << "Failed to set up main service"; | 
 |       return nullptr; | 
 |     } | 
 |   } | 
 |  | 
 |   return MainService::TryCreate(dispatcher, std::move(services), clock, std::move(info_context), | 
 |                                 std::move(config)); | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | ErrorOr<std::string> ReadStringFromFile(const std::string& filepath) { | 
 |   std::string content; | 
 |   if (!files::ReadFileToString(filepath, &content)) { | 
 |     FX_LOGS(ERROR) << "Failed to read content from " << filepath; | 
 |     return Error::kFileReadFailure; | 
 |   } | 
 |   return std::string(fxl::TrimString(content, "\r\n")); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | std::unique_ptr<MainService> MainService::TryCreate(async_dispatcher_t* dispatcher, | 
 |                                                     std::shared_ptr<sys::ServiceDirectory> services, | 
 |                                                     timekeeper::Clock* clock, | 
 |                                                     std::shared_ptr<InfoContext> info_context, | 
 |                                                     Config config) { | 
 |   const ErrorOr<std::string> build_version = ReadStringFromFile("/config/build-info/version"); | 
 |  | 
 |   std::unique_ptr<CrashRegister> crash_register = std::make_unique<CrashRegister>( | 
 |       dispatcher, services, info_context, build_version, kCrashRegisterPath); | 
 |  | 
 |   auto crash_reporter = CrashReporter::TryCreate(dispatcher, services, clock, info_context, &config, | 
 |                                                  build_version, crash_register.get()); | 
 |   if (!crash_reporter) { | 
 |     FX_LOGS(FATAL) << "Failed to set up main service"; | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   return std::unique_ptr<MainService>(new MainService( | 
 |       dispatcher, std::move(services), std::move(info_context), std::move(config), | 
 |       std::move(build_version), std::move(crash_register), std::move(crash_reporter))); | 
 | } | 
 |  | 
 | MainService::MainService(async_dispatcher_t* dispatcher, | 
 |                          std::shared_ptr<sys::ServiceDirectory> services, | 
 |                          std::shared_ptr<InfoContext> info_context, Config config, | 
 |                          const ErrorOr<std::string>& build_version, | 
 |                          std::unique_ptr<CrashRegister> crash_register, | 
 |                          std::unique_ptr<CrashReporter> crash_reporter) | 
 |     : dispatcher_(dispatcher), | 
 |       info_(info_context), | 
 |       config_(std::move(config)), | 
 |       crash_register_(std::move(crash_register)), | 
 |       crash_reporter_(std::move(crash_reporter)) { | 
 |   FX_CHECK(crash_register_); | 
 |   FX_CHECK(crash_reporter_); | 
 |  | 
 |   info_.ExposeConfig(config_); | 
 | } | 
 |  | 
 | void MainService::HandleCrashRegisterRequest( | 
 |     ::fidl::InterfaceRequest<fuchsia::feedback::CrashReportingProductRegister> request) { | 
 |   crash_register_connections_.AddBinding( | 
 |       crash_register_.get(), std::move(request), dispatcher_, [this](const zx_status_t status) { | 
 |         info_.UpdateCrashRegisterProtocolStats(&InspectProtocolStats::CloseConnection); | 
 |       }); | 
 |   info_.UpdateCrashRegisterProtocolStats(&InspectProtocolStats::NewConnection); | 
 | } | 
 |  | 
 | void MainService::HandleCrashReporterRequest( | 
 |     ::fidl::InterfaceRequest<fuchsia::feedback::CrashReporter> request) { | 
 |   crash_reporter_connections_.AddBinding( | 
 |       crash_reporter_.get(), std::move(request), dispatcher_, [this](const zx_status_t status) { | 
 |         info_.UpdateCrashReporterProtocolStats(&InspectProtocolStats::CloseConnection); | 
 |       }); | 
 |   info_.UpdateCrashReporterProtocolStats(&InspectProtocolStats::NewConnection); | 
 | } | 
 |  | 
 | }  // namespace crash_reports | 
 | }  // namespace forensics |