| /* |
| * 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 <android-base/logging.h> |
| #include <android-base/strings.h> |
| #include <fruit/fruit.h> |
| #include <gflags/gflags.h> |
| #include <unistd.h> |
| |
| #include <fstream> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #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.h" |
| #include "host/commands/run_cvd/process_monitor.h" |
| #include "host/commands/run_cvd/reporting.h" |
| #include "host/commands/run_cvd/runner_defs.h" |
| #include "host/commands/run_cvd/server_loop.h" |
| #include "host/commands/run_cvd/validate.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/vm_manager/vm_manager.h" |
| |
| namespace cuttlefish { |
| |
| namespace { |
| |
| class CuttlefishEnvironment : public SetupFeature, |
| public DiagnosticInformation { |
| public: |
| INJECT( |
| CuttlefishEnvironment(const CuttlefishConfig& config, |
| const CuttlefishConfig::InstanceSpecific& instance)) |
| : config_(config), instance_(instance) {} |
| |
| // DiagnosticInformation |
| std::vector<std::string> Diagnostics() const override { |
| auto config_path = instance_.PerInstancePath("cuttlefish_config.json"); |
| return { |
| "Launcher log: " + instance_.launcher_log_path(), |
| "Instance configuration: " + config_path, |
| "Instance environment: " + config_.cuttlefish_env_path(), |
| }; |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "CuttlefishEnvironment"; } |
| bool Enabled() const override { return true; } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| bool Setup() override { |
| auto env = |
| SharedFD::Open(config_.cuttlefish_env_path(), O_CREAT | O_RDWR, 0755); |
| if (!env->IsOpen()) { |
| LOG(ERROR) << "Unable to create cuttlefish.env file"; |
| return false; |
| } |
| std::string config_env = "export CUTTLEFISH_PER_INSTANCE_PATH=\"" + |
| instance_.PerInstancePath(".") + "\"\n"; |
| config_env += "export ANDROID_SERIAL=" + instance_.adb_ip_and_port() + "\n"; |
| auto written = WriteAll(env, config_env); |
| if (written != config_env.size()) { |
| LOG(ERROR) << "Failed to write all of \"" << config_env << "\", " |
| << "only wrote " << written << " bytes. Error was " |
| << env->StrError(); |
| return false; |
| } |
| return true; |
| } |
| |
| private: |
| const CuttlefishConfig& config_; |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| }; |
| |
| fruit::Component<ServerLoop> runCvdComponent( |
| const CuttlefishConfig* config, |
| const CuttlefishConfig::InstanceSpecific* instance) { |
| return fruit::createComponent() |
| .addMultibinding<DiagnosticInformation, CuttlefishEnvironment>() |
| .addMultibinding<SetupFeature, CuttlefishEnvironment>() |
| .bindInstance(*config) |
| .bindInstance(*instance) |
| .install(AdbConfigComponent) |
| .install(AdbConfigFragmentComponent) |
| .install(bootStateMachineComponent) |
| .install(ConfigFlagPlaceholder) |
| .install(CustomActionsComponent) |
| .install(LaunchAdbComponent) |
| .install(launchComponent) |
| .install(launchModemComponent) |
| .install(launchStreamerComponent) |
| .install(serverLoopComponent) |
| .install(validationComponent) |
| .install(vm_manager::VmManagerComponent); |
| } |
| |
| Result<void> 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<const CuttlefishConfig*> 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<std::string> 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(); |
| |
| 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<void> 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<void> 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 instance = config->ForDefaultInstance(); |
| |
| ConfigureLogs(*config, instance); |
| CF_EXPECT(ChdirIntoRuntimeDir(instance)); |
| |
| fruit::Injector<ServerLoop> injector(runCvdComponent, config, &instance); |
| |
| for (auto& fragment : injector.getMultibindings<ConfigFragment>()) { |
| CF_EXPECT(config->LoadFragment(*fragment)); |
| } |
| |
| // One of the setup features can consume most output, so print this early. |
| DiagnosticInformation::PrintAll( |
| injector.getMultibindings<DiagnosticInformation>()); |
| |
| const auto& features = injector.getMultibindings<SetupFeature>(); |
| CF_EXPECT(SetupFeature::RunSetup(features)); |
| |
| // Monitor and restart host processes supporting the CVD |
| ProcessMonitor::Properties process_monitor_properties; |
| process_monitor_properties.RestartSubprocesses( |
| config->restart_subprocesses()); |
| |
| for (auto& command_source : injector.getMultibindings<CommandSource>()) { |
| if (command_source->Enabled()) { |
| process_monitor_properties.AddCommands(command_source->Commands()); |
| } |
| } |
| |
| ProcessMonitor process_monitor(std::move(process_monitor_properties)); |
| |
| CF_EXPECT(process_monitor.StartAndMonitorProcesses()); |
| |
| injector.get<ServerLoop&>().Run(process_monitor); // 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); |
| CHECK(result.ok()) << result.error(); |
| return 0; |
| } |