254 lines
8.6 KiB
C++
254 lines
8.6 KiB
C++
/*
|
|
* 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/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/fastboot/fastboot.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/inject.h"
|
|
#include "host/libs/metrics/metrics_receiver.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<std::string> Diagnostics() const override {
|
|
auto config_path = instance_.PerInstancePath("cuttlefish_config.json");
|
|
return {
|
|
"Launcher log: " + instance_.launcher_log_path(),
|
|
"Instance configuration: " + config_path,
|
|
};
|
|
}
|
|
|
|
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<void> LateInject(fruit::Injector<>& injector) override {
|
|
config_fragments_ = injector.getMultibindings<ConfigFragment>();
|
|
setup_features_ = injector.getMultibindings<SetupFeature>();
|
|
diagnostics_ = injector.getMultibindings<DiagnosticInformation>();
|
|
return {};
|
|
}
|
|
|
|
Result<void> 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<ConfigFragment*> config_fragments_;
|
|
std::vector<SetupFeature*> setup_features_;
|
|
std::vector<DiagnosticInformation*> diagnostics_;
|
|
};
|
|
|
|
fruit::Component<> runCvdComponent(
|
|
const CuttlefishConfig* config,
|
|
const CuttlefishConfig::InstanceSpecific* instance) {
|
|
return fruit::createComponent()
|
|
.addMultibinding<DiagnosticInformation, CuttlefishEnvironment>()
|
|
.addMultibinding<InstanceLifecycle, InstanceLifecycle>()
|
|
.addMultibinding<LateInjected, InstanceLifecycle>()
|
|
.bindInstance(*config)
|
|
.bindInstance(*instance)
|
|
.install(AdbConfigComponent)
|
|
.install(AdbConfigFragmentComponent)
|
|
.install(FastbootConfigComponent)
|
|
.install(FastbootConfigFragmentComponent)
|
|
.install(bootStateMachineComponent)
|
|
.install(ConfigFlagPlaceholder)
|
|
.install(CustomActionsComponent)
|
|
.install(LaunchAdbComponent)
|
|
.install(LaunchFastbootComponent)
|
|
.install(BluetoothConnectorComponent)
|
|
.install(UwbConnectorComponent)
|
|
.install(ConfigServerComponent)
|
|
.install(ConsoleForwarderComponent)
|
|
.install(EchoServerComponent)
|
|
.install(GnssGrpcProxyServerComponent)
|
|
.install(LogcatReceiverComponent)
|
|
.install(KernelLogMonitorComponent)
|
|
.install(MetricsServiceComponent)
|
|
.install(OpenWrtComponent)
|
|
.install(OpenwrtControlServerComponent)
|
|
.install(PicaComponent)
|
|
.install(RootCanalComponent)
|
|
.install(NetsimServerComponent)
|
|
.install(SecureEnvComponent)
|
|
.install(TombstoneReceiverComponent)
|
|
.install(WmediumdServerComponent)
|
|
.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();
|
|
|
|
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<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<> injector(runCvdComponent, config, &instance);
|
|
|
|
for (auto& late_injected : injector.getMultibindings<LateInjected>()) {
|
|
CF_EXPECT(late_injected->LateInject(injector));
|
|
}
|
|
|
|
MetricsReceiver::LogMetricsVMStart();
|
|
|
|
auto instance_bindings = injector.getMultibindings<InstanceLifecycle>();
|
|
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().Message();
|
|
LOG(DEBUG) << result.error().Trace();
|
|
abort();
|
|
}
|