/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "common/libs/fs/shared_buf.h" #include "common/libs/fs/shared_fd.h" #include "common/libs/utils/environment.h" #include "common/libs/utils/files.h" #include "common/libs/utils/size_utils.h" #include "common/libs/utils/subprocess.h" #include "common/libs/utils/tee_logging.h" #include "host/commands/run_cvd/boot_state_machine.h" #include "host/commands/run_cvd/launch/launch.h" #include "host/commands/run_cvd/reporting.h" #include "host/commands/run_cvd/server_loop.h" #include "host/commands/run_cvd/validate.h" #include "host/libs/command_util/runner/defs.h" #include "host/libs/config/adb/adb.h" #include "host/libs/config/config_flag.h" #include "host/libs/config/config_fragment.h" #include "host/libs/config/custom_actions.h" #include "host/libs/config/cuttlefish_config.h" #include "host/libs/config/fastboot/fastboot.h" #include "host/libs/config/inject.h" #include "host/libs/metrics/metrics_receiver.h" #include "host/libs/process_monitor/process_monitor.h" #include "host/libs/vm_manager/vm_manager.h" namespace cuttlefish { namespace { class CuttlefishEnvironment : public DiagnosticInformation { public: INJECT( CuttlefishEnvironment(const CuttlefishConfig::InstanceSpecific& instance)) : instance_(instance) {} // DiagnosticInformation std::vector Diagnostics() const override { auto config_path = instance_.PerInstancePath("cuttlefish_config.json"); return { "Launcher log: " + instance_.launcher_log_path(), "Instance configuration: " + config_path, // TODO(rammuthiah) replace this with a more thorough cvd host package // version scheme. Currently this only reports the Build NUmber of run_cvd // and it is possible for other host binaries to be from different versions. "Launcher Build ID: " + android::build::GetBuildNumber(), }; } private: const CuttlefishConfig::InstanceSpecific& instance_; }; class InstanceLifecycle : public LateInjected { public: INJECT(InstanceLifecycle(const CuttlefishConfig& config, ServerLoop& server_loop)) : config_(config), server_loop_(server_loop) {} Result LateInject(fruit::Injector<>& injector) override { config_fragments_ = injector.getMultibindings(); setup_features_ = injector.getMultibindings(); diagnostics_ = injector.getMultibindings(); return {}; } Result Run() { for (auto& fragment : config_fragments_) { CF_EXPECT(config_.LoadFragment(*fragment)); } // One of the setup features can consume most output, so print this early. DiagnosticInformation::PrintAll(diagnostics_); CF_EXPECT(SetupFeature::RunSetup(setup_features_)); CF_EXPECT(server_loop_.Run()); return {}; } private: const CuttlefishConfig& config_; ServerLoop& server_loop_; std::vector config_fragments_; std::vector setup_features_; std::vector diagnostics_; }; fruit::Component<> runCvdComponent( const CuttlefishConfig* config, const CuttlefishConfig::EnvironmentSpecific* environment, const CuttlefishConfig::InstanceSpecific* instance) { return fruit::createComponent() .addMultibinding() .addMultibinding() .addMultibinding() .bindInstance(*config) .bindInstance(*instance) .bindInstance(*environment) #ifdef __linux__ .install(AutoCmd::Component) .install(AutoCmd::Component) .install(AutoCmd::Component) .install(McuComponent) .install(OpenWrtComponent) .install(VhostDeviceVsockComponent) .install(WmediumdServerComponent) .install(launchStreamerComponent) .install(AutoCmd::Component) #endif .install(AdbConfigComponent) .install(AdbConfigFragmentComponent) .install(FastbootConfigComponent) .install(FastbootConfigFragmentComponent) .install(bootStateMachineComponent) .install(AutoCmd::Component) .install(AutoCmd::Component) .install(ConfigFlagPlaceholder) .install(CustomActionsComponent) .install(LaunchAdbComponent) .install(LaunchFastbootComponent) .install(AutoCmd::Component) .install(AutoCmd::Component) .install(AutoCmd::Component) .install(AutoCmd::Component) .install(AutoDiagnostic::Component) .install(ControlEnvProxyServerComponent) .install(AutoCmd::Component) .install(AutoCmd::Component) .install(AutoCmd::Component) .install(AutoDiagnostic::Component) .install(KernelLogMonitorComponent) .install(AutoCmd::Component) .install(OpenwrtControlServerComponent) .install(AutoCmd::Component) .install(RootCanalComponent) .install(AutoCmd::Component) .install(NetsimServerComponent) .install(AutoSnapshotControlFiles::Component) .install(AutoCmd::Component) .install(serverLoopComponent) .install(WebRtcRecorderComponent) .install(AutoSetup::Component) .install(AutoSetup::Component) .install(AutoSetup::Component) .install(vm_manager::VmManagerComponent); } Result StdinValid() { CF_EXPECT(!isatty(0), "stdin was a tty, expected to be passed the output of a" " previous stage. Did you mean to run launch_cvd?"); CF_EXPECT(errno != EBADF, "stdin was not a valid file descriptor, expected to be passed the " "output of assemble_cvd. Did you mean to run launch_cvd?"); return {}; } Result FindConfigFromStdin() { std::string input_files_str; { auto input_fd = SharedFD::Dup(0); auto bytes_read = ReadAll(input_fd, &input_files_str); CF_EXPECT(bytes_read >= 0, "Failed to read input files. Error was \"" << input_fd->StrError() << "\""); } std::vector input_files = android::base::Split(input_files_str, "\n"); for (const auto& file : input_files) { if (file.find("cuttlefish_config.json") != std::string::npos) { setenv(kCuttlefishConfigEnvVarName, file.c_str(), /* overwrite */ false); } } return CF_EXPECT(CuttlefishConfig::Get()); // Null check } void ConfigureLogs(const CuttlefishConfig& config, const CuttlefishConfig::InstanceSpecific& instance) { auto log_path = instance.launcher_log_path(); if (!FileHasContent(log_path)) { std::ofstream launcher_log_ofstream(log_path.c_str()); auto assembly_path = config.AssemblyPath("assemble_cvd.log"); std::ifstream assembly_log_ifstream(assembly_path); if (assembly_log_ifstream) { auto assemble_log = ReadFile(assembly_path); launcher_log_ofstream << assemble_log; } } std::string prefix; if (config.Instances().size() > 1) { prefix = instance.instance_name() + ": "; } ::android::base::SetLogger(LogToStderrAndFiles({log_path}, prefix)); } Result ChdirIntoRuntimeDir( const CuttlefishConfig::InstanceSpecific& instance) { // Change working directory to the instance directory as early as possible to // ensure all host processes have the same working dir. This helps stop_cvd // find the running processes when it can't establish a communication with the // launcher. CF_EXPECT(chdir(instance.instance_dir().c_str()) == 0, "Unable to change dir into instance directory \"" << instance.instance_dir() << "\": " << strerror(errno)); return {}; } } // namespace Result RunCvdMain(int argc, char** argv) { setenv("ANDROID_LOG_TAGS", "*:v", /* overwrite */ 0); ::android::base::InitLogging(argv, android::base::StderrLogger); google::ParseCommandLineFlags(&argc, &argv, false); CF_EXPECT(StdinValid(), "Invalid stdin"); auto config = CF_EXPECT(FindConfigFromStdin()); auto environment = config->ForDefaultEnvironment(); auto instance = config->ForDefaultInstance(); ConfigureLogs(*config, instance); CF_EXPECT(ChdirIntoRuntimeDir(instance)); fruit::Injector<> injector(runCvdComponent, config, &environment, &instance); for (auto& late_injected : injector.getMultibindings()) { CF_EXPECT(late_injected->LateInject(injector)); } if (config->enable_metrics() == cuttlefish::CuttlefishConfig::Answer::kYes) { MetricsReceiver::LogMetricsVMStart(); } auto instance_bindings = injector.getMultibindings(); CF_EXPECT(instance_bindings.size() == 1); CF_EXPECT(instance_bindings[0]->Run()); // Should not return return CF_ERR("The server loop returned, it should never happen!!"); } } // namespace cuttlefish int main(int argc, char** argv) { auto result = cuttlefish::RunCvdMain(argc, argv); if (result.ok()) { return 0; } LOG(ERROR) << result.error().FormatForEnv(); abort(); }