| // |
| // Copyright (C) 2019 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 "host/commands/run_cvd/launch.h" |
| |
| #include <android-base/logging.h> |
| |
| #include <unordered_set> |
| #include <utility> |
| #include <vector> |
| |
| #include "common/libs/fs/shared_fd.h" |
| #include "common/libs/utils/files.h" |
| #include "common/libs/utils/network.h" |
| #include "common/libs/utils/result.h" |
| #include "common/libs/utils/subprocess.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/libs/config/cuttlefish_config.h" |
| #include "host/libs/config/inject.h" |
| #include "host/libs/config/known_paths.h" |
| #include "host/libs/vm_manager/crosvm_builder.h" |
| #include "host/libs/vm_manager/crosvm_manager.h" |
| #include "host/libs/vm_manager/vm_manager.h" |
| |
| namespace cuttlefish { |
| |
| using vm_manager::VmManager; |
| |
| namespace { |
| |
| template <typename T> |
| std::vector<T> single_element_emplace(T&& element) { |
| std::vector<T> vec; |
| vec.emplace_back(std::move(element)); |
| return vec; |
| } |
| |
| } // namespace |
| |
| class KernelLogMonitor : public CommandSource, |
| public KernelLogPipeProvider, |
| public DiagnosticInformation { |
| public: |
| INJECT(KernelLogMonitor(const CuttlefishConfig::InstanceSpecific& instance)) |
| : instance_(instance) {} |
| |
| // DiagnosticInformation |
| std::vector<std::string> Diagnostics() const override { |
| return {"Kernel log: " + instance_.PerInstancePath("kernel.log")}; |
| } |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| Command command(KernelLogMonitorBinary()); |
| command.AddParameter("-log_pipe_fd=", fifo_); |
| |
| if (!event_pipe_write_ends_.empty()) { |
| command.AddParameter("-subscriber_fds="); |
| for (size_t i = 0; i < event_pipe_write_ends_.size(); i++) { |
| if (i > 0) { |
| command.AppendToLastParameter(","); |
| } |
| command.AppendToLastParameter(event_pipe_write_ends_[i]); |
| } |
| } |
| |
| return single_element_emplace(std::move(command)); |
| } |
| |
| // KernelLogPipeProvider |
| SharedFD KernelLogPipe() override { |
| CHECK(!event_pipe_read_ends_.empty()) << "No more kernel pipes left"; |
| SharedFD ret = event_pipe_read_ends_.back(); |
| event_pipe_read_ends_.pop_back(); |
| return ret; |
| } |
| |
| private: |
| // SetupFeature |
| bool Enabled() const override { return true; } |
| std::string Name() const override { return "KernelLogMonitor"; } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| Result<void> ResultSetup() override { |
| auto log_name = instance_.kernel_log_pipe_name(); |
| CF_EXPECT(mkfifo(log_name.c_str(), 0600) == 0, |
| "Unable to create named pipe at " << log_name << ": " |
| << strerror(errno)); |
| |
| // Open the pipe here (from the launcher) to ensure the pipe is not deleted |
| // due to the usage counters in the kernel reaching zero. If this is not |
| // done and the kernel_log_monitor crashes for some reason the VMM may get |
| // SIGPIPE. |
| fifo_ = SharedFD::Open(log_name, O_RDWR); |
| CF_EXPECT(fifo_->IsOpen(), |
| "Unable to open \"" << log_name << "\": " << fifo_->StrError()); |
| |
| // TODO(schuffelen): Find a way to calculate this dynamically. |
| int number_of_event_pipes = 4; |
| if (number_of_event_pipes > 0) { |
| for (unsigned int i = 0; i < number_of_event_pipes; ++i) { |
| SharedFD event_pipe_write_end, event_pipe_read_end; |
| CF_EXPECT(SharedFD::Pipe(&event_pipe_read_end, &event_pipe_write_end), |
| "Failed creating kernel log pipe: " << strerror(errno)); |
| event_pipe_write_ends_.push_back(event_pipe_write_end); |
| event_pipe_read_ends_.push_back(event_pipe_read_end); |
| } |
| } |
| return {}; |
| } |
| |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| SharedFD fifo_; |
| std::vector<SharedFD> event_pipe_write_ends_; |
| std::vector<SharedFD> event_pipe_read_ends_; |
| }; |
| |
| class LogTeeCreator { |
| public: |
| INJECT(LogTeeCreator(const CuttlefishConfig::InstanceSpecific& instance)) |
| : instance_(instance) {} |
| |
| Command CreateLogTee(Command& cmd, const std::string& process_name) { |
| auto name_with_ext = process_name + "_logs.fifo"; |
| auto logs_path = instance_.PerInstanceInternalPath(name_with_ext.c_str()); |
| auto logs = SharedFD::Fifo(logs_path, 0666); |
| if (!logs->IsOpen()) { |
| LOG(FATAL) << "Failed to create fifo for " << process_name |
| << " output: " << logs->StrError(); |
| } |
| |
| cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, logs); |
| cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdErr, logs); |
| |
| return Command(HostBinaryPath("log_tee")) |
| .AddParameter("--process_name=", process_name) |
| .AddParameter("--log_fd_in=", logs); |
| } |
| |
| private: |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| }; |
| |
| class RootCanal : public CommandSource { |
| public: |
| INJECT(RootCanal(const CuttlefishConfig& config, |
| const CuttlefishConfig::InstanceSpecific& instance, |
| LogTeeCreator& log_tee)) |
| : config_(config), instance_(instance), log_tee_(log_tee) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| if (!Enabled()) { |
| return {}; |
| } |
| Command command(RootCanalBinary()); |
| |
| // Test port |
| command.AddParameter(config_.rootcanal_test_port()); |
| // HCI server port |
| command.AddParameter(config_.rootcanal_hci_port()); |
| // Link server port |
| command.AddParameter(config_.rootcanal_link_port()); |
| // Bluetooth controller properties file |
| command.AddParameter("--controller_properties_file=", |
| config_.rootcanal_config_file()); |
| // Default commands file |
| command.AddParameter("--default_commands_file=", |
| config_.rootcanal_default_commands_file()); |
| |
| std::vector<Command> commands; |
| commands.emplace_back(log_tee_.CreateLogTee(command, "rootcanal")); |
| commands.emplace_back(std::move(command)); |
| return commands; |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "RootCanal"; } |
| bool Enabled() const override { |
| return config_.enable_host_bluetooth() && instance_.start_rootcanal(); |
| } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| bool Setup() override { return true; } |
| |
| const CuttlefishConfig& config_; |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| LogTeeCreator& log_tee_; |
| }; |
| |
| class LogcatReceiver : public CommandSource, public DiagnosticInformation { |
| public: |
| INJECT(LogcatReceiver(const CuttlefishConfig::InstanceSpecific& instance)) |
| : instance_(instance) {} |
| // DiagnosticInformation |
| std::vector<std::string> Diagnostics() const override { |
| return {"Logcat output: " + instance_.logcat_path()}; |
| } |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| return single_element_emplace( |
| Command(LogcatReceiverBinary()).AddParameter("-log_pipe_fd=", pipe_)); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "LogcatReceiver"; } |
| bool Enabled() const override { return true; } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| Result<void> ResultSetup() { |
| auto log_name = instance_.logcat_pipe_name(); |
| CF_EXPECT(mkfifo(log_name.c_str(), 0600) == 0, |
| "Unable to create named pipe at " << log_name << ": " |
| << strerror(errno)); |
| // Open the pipe here (from the launcher) to ensure the pipe is not deleted |
| // due to the usage counters in the kernel reaching zero. If this is not |
| // done and the logcat_receiver crashes for some reason the VMM may get |
| // SIGPIPE. |
| pipe_ = SharedFD::Open(log_name.c_str(), O_RDWR); |
| CF_EXPECT(pipe_->IsOpen(), |
| "Can't open \"" << log_name << "\": " << pipe_->StrError()); |
| return {}; |
| } |
| |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| SharedFD pipe_; |
| }; |
| |
| class ConfigServer : public CommandSource { |
| public: |
| INJECT(ConfigServer(const CuttlefishConfig::InstanceSpecific& instance)) |
| : instance_(instance) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| return single_element_emplace( |
| Command(ConfigServerBinary()).AddParameter("-server_fd=", socket_)); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "ConfigServer"; } |
| bool Enabled() const override { return true; } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| Result<void> ResultSetup() override { |
| auto port = instance_.config_server_port(); |
| socket_ = SharedFD::VsockServer(port, SOCK_STREAM); |
| CF_EXPECT(socket_->IsOpen(), |
| "Unable to create configuration server socket: " |
| << socket_->StrError()); |
| return {}; |
| } |
| |
| private: |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| SharedFD socket_; |
| }; |
| |
| class TombstoneReceiver : public CommandSource { |
| public: |
| INJECT(TombstoneReceiver(const CuttlefishConfig::InstanceSpecific& instance)) |
| : instance_(instance) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| return single_element_emplace( |
| Command(TombstoneReceiverBinary()) |
| .AddParameter("-server_fd=", socket_) |
| .AddParameter("-tombstone_dir=", tombstone_dir_)); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "TombstoneReceiver"; } |
| bool Enabled() const override { return true; } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| Result<void> ResultSetup() override { |
| tombstone_dir_ = instance_.PerInstancePath("tombstones"); |
| if (!DirectoryExists(tombstone_dir_)) { |
| LOG(DEBUG) << "Setting up " << tombstone_dir_; |
| CF_EXPECT(mkdir(tombstone_dir_.c_str(), |
| S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0, |
| "Failed to create tombstone directory: " |
| << tombstone_dir_ << ". Error: " << strerror(errno)); |
| } |
| |
| auto port = instance_.tombstone_receiver_port(); |
| socket_ = SharedFD::VsockServer(port, SOCK_STREAM); |
| CF_EXPECT(socket_->IsOpen(), "Unable to create tombstone server socket: " |
| << socket_->StrError()); |
| return {}; |
| } |
| |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| SharedFD socket_; |
| std::string tombstone_dir_; |
| }; |
| |
| class MetricsService : public CommandSource { |
| public: |
| INJECT(MetricsService(const CuttlefishConfig& config)) : config_(config) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| return single_element_emplace(Command(MetricsBinary())); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "MetricsService"; } |
| bool Enabled() const override { |
| return config_.enable_metrics() == CuttlefishConfig::kYes; |
| } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| bool Setup() override { return true; } |
| |
| private: |
| const CuttlefishConfig& config_; |
| }; |
| |
| class GnssGrpcProxyServer : public CommandSource { |
| public: |
| INJECT( |
| GnssGrpcProxyServer(const CuttlefishConfig& config, |
| const CuttlefishConfig::InstanceSpecific& instance)) |
| : config_(config), instance_(instance) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| Command gnss_grpc_proxy_cmd(GnssGrpcProxyBinary()); |
| const unsigned gnss_grpc_proxy_server_port = |
| instance_.gnss_grpc_proxy_server_port(); |
| gnss_grpc_proxy_cmd.AddParameter("--gnss_in_fd=", gnss_grpc_proxy_in_wr_); |
| gnss_grpc_proxy_cmd.AddParameter("--gnss_out_fd=", gnss_grpc_proxy_out_rd_); |
| gnss_grpc_proxy_cmd.AddParameter("--gnss_grpc_port=", |
| gnss_grpc_proxy_server_port); |
| if (!instance_.gnss_file_path().empty()) { |
| // If path is provided, proxy will start as local mode. |
| gnss_grpc_proxy_cmd.AddParameter("--gnss_file_path=", |
| instance_.gnss_file_path()); |
| } |
| return single_element_emplace(std::move(gnss_grpc_proxy_cmd)); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "GnssGrpcProxyServer"; } |
| bool Enabled() const override { |
| return config_.enable_gnss_grpc_proxy() && |
| FileExists(GnssGrpcProxyBinary()); |
| } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| Result<void> ResultSetup() override { |
| std::vector<SharedFD> fifos; |
| std::vector<std::string> fifo_paths = { |
| instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.in"), |
| instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.out"), |
| instance_.PerInstanceInternalPath("locationhvc_fifo_vm.in"), |
| instance_.PerInstanceInternalPath("locationhvc_fifo_vm.out"), |
| }; |
| for (const auto& path : fifo_paths) { |
| unlink(path.c_str()); |
| CF_EXPECT(mkfifo(path.c_str(), 0660) == 0, "Could not create " << path); |
| auto fd = SharedFD::Open(path, O_RDWR); |
| CF_EXPECT(fd->IsOpen(), |
| "Could not open " << path << ": " << fd->StrError()); |
| fifos.push_back(fd); |
| } |
| |
| gnss_grpc_proxy_in_wr_ = fifos[0]; |
| gnss_grpc_proxy_out_rd_ = fifos[1]; |
| return {}; |
| } |
| |
| private: |
| const CuttlefishConfig& config_; |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| SharedFD gnss_grpc_proxy_in_wr_; |
| SharedFD gnss_grpc_proxy_out_rd_; |
| }; |
| |
| class BluetoothConnector : public CommandSource { |
| public: |
| INJECT(BluetoothConnector(const CuttlefishConfig& config, |
| const CuttlefishConfig::InstanceSpecific& instance)) |
| : config_(config), instance_(instance) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| Command command(HostBinaryPath("bt_connector")); |
| command.AddParameter("-bt_out=", fifos_[0]); |
| command.AddParameter("-bt_in=", fifos_[1]); |
| command.AddParameter("-hci_port=", config_.rootcanal_hci_port()); |
| command.AddParameter("-link_port=", config_.rootcanal_link_port()); |
| command.AddParameter("-test_port=", config_.rootcanal_test_port()); |
| return single_element_emplace(std::move(command)); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "BluetoothConnector"; } |
| bool Enabled() const override { return config_.enable_host_bluetooth(); } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| Result<void> ResultSetup() { |
| std::vector<std::string> fifo_paths = { |
| instance_.PerInstanceInternalPath("bt_fifo_vm.in"), |
| instance_.PerInstanceInternalPath("bt_fifo_vm.out"), |
| }; |
| for (const auto& path : fifo_paths) { |
| unlink(path.c_str()); |
| CF_EXPECT(mkfifo(path.c_str(), 0660) == 0, "Could not create " << path); |
| auto fd = SharedFD::Open(path, O_RDWR); |
| CF_EXPECT(fd->IsOpen(), |
| "Could not open " << path << ": " << fd->StrError()); |
| fifos_.push_back(fd); |
| } |
| return {}; |
| } |
| |
| private: |
| const CuttlefishConfig& config_; |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| std::vector<SharedFD> fifos_; |
| }; |
| |
| class SecureEnvironment : public CommandSource { |
| public: |
| INJECT(SecureEnvironment(const CuttlefishConfig& config, |
| const CuttlefishConfig::InstanceSpecific& instance, |
| KernelLogPipeProvider& kernel_log_pipe_provider)) |
| : config_(config), |
| instance_(instance), |
| kernel_log_pipe_provider_(kernel_log_pipe_provider) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| Command command(HostBinaryPath("secure_env")); |
| command.AddParameter("-confui_server_fd=", confui_server_fd_); |
| command.AddParameter("-keymaster_fd_out=", fifos_[0]); |
| command.AddParameter("-keymaster_fd_in=", fifos_[1]); |
| command.AddParameter("-gatekeeper_fd_out=", fifos_[2]); |
| command.AddParameter("-gatekeeper_fd_in=", fifos_[3]); |
| |
| const auto& secure_hals = config_.secure_hals(); |
| bool secure_keymint = secure_hals.count(SecureHal::Keymint) > 0; |
| command.AddParameter("-keymint_impl=", secure_keymint ? "tpm" : "software"); |
| bool secure_gatekeeper = secure_hals.count(SecureHal::Gatekeeper) > 0; |
| auto gatekeeper_impl = secure_gatekeeper ? "tpm" : "software"; |
| command.AddParameter("-gatekeeper_impl=", gatekeeper_impl); |
| |
| command.AddParameter("-kernel_events_fd=", kernel_log_pipe_); |
| |
| return single_element_emplace(std::move(command)); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "SecureEnvironment"; } |
| bool Enabled() const override { return true; } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { |
| return {&kernel_log_pipe_provider_}; |
| } |
| Result<void> ResultSetup() override { |
| std::vector<std::string> fifo_paths = { |
| instance_.PerInstanceInternalPath("keymaster_fifo_vm.in"), |
| instance_.PerInstanceInternalPath("keymaster_fifo_vm.out"), |
| instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.in"), |
| instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.out"), |
| }; |
| std::vector<SharedFD> fifos; |
| for (const auto& path : fifo_paths) { |
| unlink(path.c_str()); |
| CF_EXPECT(mkfifo(path.c_str(), 0660) == 0, "Could not create " << path); |
| auto fd = SharedFD::Open(path, O_RDWR); |
| CF_EXPECT(fd->IsOpen(), |
| "Could not open " << path << ": " << fd->StrError()); |
| fifos_.push_back(fd); |
| } |
| |
| auto confui_socket_path = |
| instance_.PerInstanceInternalPath("confui_sign.sock"); |
| confui_server_fd_ = SharedFD::SocketLocalServer(confui_socket_path, false, |
| SOCK_STREAM, 0600); |
| CF_EXPECT(confui_server_fd_->IsOpen(), |
| "Could not open " << confui_socket_path << ": " |
| << confui_server_fd_->StrError()); |
| kernel_log_pipe_ = kernel_log_pipe_provider_.KernelLogPipe(); |
| |
| return {}; |
| } |
| |
| const CuttlefishConfig& config_; |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| SharedFD confui_server_fd_; |
| std::vector<SharedFD> fifos_; |
| KernelLogPipeProvider& kernel_log_pipe_provider_; |
| SharedFD kernel_log_pipe_; |
| }; |
| |
| class VehicleHalServer : public CommandSource { |
| public: |
| INJECT(VehicleHalServer(const CuttlefishConfig& config, |
| const CuttlefishConfig::InstanceSpecific& instance)) |
| : config_(config), instance_(instance) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| Command grpc_server(VehicleHalGrpcServerBinary()); |
| |
| const unsigned vhal_server_cid = 2; |
| const unsigned vhal_server_port = instance_.vehicle_hal_server_port(); |
| const std::string vhal_server_power_state_file = |
| AbsolutePath(instance_.PerInstancePath("power_state")); |
| const std::string vhal_server_power_state_socket = |
| AbsolutePath(instance_.PerInstancePath("power_state_socket")); |
| |
| grpc_server.AddParameter("--server_cid=", vhal_server_cid); |
| grpc_server.AddParameter("--server_port=", vhal_server_port); |
| grpc_server.AddParameter("--power_state_file=", |
| vhal_server_power_state_file); |
| grpc_server.AddParameter("--power_state_socket=", |
| vhal_server_power_state_socket); |
| return single_element_emplace(std::move(grpc_server)); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "VehicleHalServer"; } |
| bool Enabled() const override { |
| return config_.enable_vehicle_hal_grpc_server() && |
| FileExists(VehicleHalGrpcServerBinary()); |
| } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| bool Setup() override { return true; } |
| |
| private: |
| const CuttlefishConfig& config_; |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| }; |
| |
| class ConsoleForwarder : public CommandSource, public DiagnosticInformation { |
| public: |
| INJECT(ConsoleForwarder(const CuttlefishConfig& config, |
| const CuttlefishConfig::InstanceSpecific& instance)) |
| : config_(config), instance_(instance) {} |
| // DiagnosticInformation |
| std::vector<std::string> Diagnostics() const override { |
| if (Enabled()) { |
| return {"To access the console run: screen " + instance_.console_path()}; |
| } else { |
| return {"Serial console is disabled; use -console=true to enable it."}; |
| } |
| } |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| Command console_forwarder_cmd(ConsoleForwarderBinary()); |
| |
| console_forwarder_cmd.AddParameter("--console_in_fd=", |
| console_forwarder_in_wr_); |
| console_forwarder_cmd.AddParameter("--console_out_fd=", |
| console_forwarder_out_rd_); |
| return single_element_emplace(std::move(console_forwarder_cmd)); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "ConsoleForwarder"; } |
| bool Enabled() const override { return config_.console(); } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| Result<void> ResultSetup() override { |
| auto console_in_pipe_name = instance_.console_in_pipe_name(); |
| CF_EXPECT( |
| mkfifo(console_in_pipe_name.c_str(), 0600) == 0, |
| "Failed to create console input fifo for crosvm: " << strerror(errno)); |
| |
| auto console_out_pipe_name = instance_.console_out_pipe_name(); |
| CF_EXPECT( |
| mkfifo(console_out_pipe_name.c_str(), 0660) == 0, |
| "Failed to create console output fifo for crosvm: " << strerror(errno)); |
| |
| // These fds will only be read from or written to, but open them with |
| // read and write access to keep them open in case the subprocesses exit |
| console_forwarder_in_wr_ = |
| SharedFD::Open(console_in_pipe_name.c_str(), O_RDWR); |
| CF_EXPECT(console_forwarder_in_wr_->IsOpen(), |
| "Failed to open console_forwarder input fifo for writes: " |
| << console_forwarder_in_wr_->StrError()); |
| |
| console_forwarder_out_rd_ = |
| SharedFD::Open(console_out_pipe_name.c_str(), O_RDWR); |
| CF_EXPECT(console_forwarder_out_rd_->IsOpen(), |
| "Failed to open console_forwarder output fifo for reads: " |
| << console_forwarder_out_rd_->StrError()); |
| return {}; |
| } |
| |
| const CuttlefishConfig& config_; |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| SharedFD console_forwarder_in_wr_; |
| SharedFD console_forwarder_out_rd_; |
| }; |
| |
| class WmediumdServer : public CommandSource { |
| public: |
| INJECT(WmediumdServer(const CuttlefishConfig& config, |
| const CuttlefishConfig::InstanceSpecific& instance, |
| LogTeeCreator& log_tee)) |
| : config_(config), instance_(instance), log_tee_(log_tee) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| Command cmd(WmediumdBinary()); |
| cmd.AddParameter("-u", config_.vhost_user_mac80211_hwsim()); |
| cmd.AddParameter("-a", config_.wmediumd_api_server_socket()); |
| cmd.AddParameter("-c", config_path_); |
| |
| std::vector<Command> commands; |
| commands.emplace_back(log_tee_.CreateLogTee(cmd, "wmediumd")); |
| commands.emplace_back(std::move(cmd)); |
| return commands; |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "WmediumdServer"; } |
| bool Enabled() const override { |
| #ifndef ENFORCE_MAC80211_HWSIM |
| return false; |
| #else |
| return instance_.start_wmediumd(); |
| #endif |
| } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| Result<void> ResultSetup() override { |
| // If wmediumd configuration is given, use it |
| if (!config_.wmediumd_config().empty()) { |
| config_path_ = config_.wmediumd_config(); |
| return {}; |
| } |
| // Otherwise, generate wmediumd configuration using the current wifi mac |
| // prefix before start |
| config_path_ = instance_.PerInstanceInternalPath("wmediumd.cfg"); |
| Command gen_config_cmd(WmediumdGenConfigBinary()); |
| gen_config_cmd.AddParameter("-o", config_path_); |
| gen_config_cmd.AddParameter("-p", instance_.wifi_mac_prefix()); |
| |
| int success = gen_config_cmd.Start().Wait(); |
| CF_EXPECT(success == 0, "Unable to run " << gen_config_cmd.Executable() |
| << ". Exited with status " |
| << success); |
| return {}; |
| } |
| |
| const CuttlefishConfig& config_; |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| LogTeeCreator& log_tee_; |
| std::string config_path_; |
| }; |
| |
| class VmmCommands : public CommandSource { |
| public: |
| INJECT(VmmCommands(const CuttlefishConfig& config, VmManager& vmm)) |
| : config_(config), vmm_(vmm) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| return vmm_.StartCommands(config_); |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "VirtualMachineManager"; } |
| bool Enabled() const override { return true; } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| bool Setup() override { return true; } |
| |
| const CuttlefishConfig& config_; |
| VmManager& vmm_; |
| }; |
| |
| class OpenWrt : public CommandSource { |
| public: |
| INJECT(OpenWrt(const CuttlefishConfig& config, |
| const CuttlefishConfig::InstanceSpecific& instance, |
| LogTeeCreator& log_tee)) |
| : config_(config), instance_(instance), log_tee_(log_tee) {} |
| |
| // CommandSource |
| std::vector<Command> Commands() override { |
| constexpr auto crosvm_for_ap_socket = "ap_control.sock"; |
| |
| CrosvmBuilder ap_cmd; |
| ap_cmd.SetBinary(config_.crosvm_binary()); |
| ap_cmd.AddControlSocket( |
| instance_.PerInstanceInternalPath(crosvm_for_ap_socket)); |
| |
| if (!config_.vhost_user_mac80211_hwsim().empty()) { |
| ap_cmd.Cmd().AddParameter("--vhost-user-mac80211-hwsim=", |
| config_.vhost_user_mac80211_hwsim()); |
| } |
| SharedFD wifi_tap = ap_cmd.AddTap(instance_.wifi_tap_name()); |
| // Only run the leases workaround if we are not using the new network |
| // bridge architecture - in that case, we have a wider DHCP address |
| // space and stale leases should be much less of an issue |
| if (!FileExists("/var/run/cuttlefish-dnsmasq-cvd-wbr.leases") && |
| wifi_tap->IsOpen()) { |
| // TODO(schuffelen): QEMU also needs this and this is not the best place |
| // for this code. Find a better place to put it. |
| auto lease_file = |
| ForCurrentInstance("/var/run/cuttlefish-dnsmasq-cvd-wbr-") + |
| ".leases"; |
| std::uint8_t dhcp_server_ip[] = { |
| 192, 168, 96, (std::uint8_t)(ForCurrentInstance(1) * 4 - 3)}; |
| if (!ReleaseDhcpLeases(lease_file, wifi_tap, dhcp_server_ip)) { |
| LOG(ERROR) |
| << "Failed to release wifi DHCP leases. Connecting to the wifi " |
| << "network may not work."; |
| } |
| } |
| if (config_.enable_sandbox()) { |
| ap_cmd.Cmd().AddParameter("--seccomp-policy-dir=", |
| config_.seccomp_policy_dir()); |
| } else { |
| ap_cmd.Cmd().AddParameter("--disable-sandbox"); |
| } |
| ap_cmd.Cmd().AddParameter("--rwdisk=", |
| instance_.PerInstancePath("ap_overlay.img")); |
| ap_cmd.Cmd().AddParameter( |
| "--disk=", instance_.PerInstancePath("persistent_composite.img")); |
| ap_cmd.Cmd().AddParameter("--params=\"root=" + config_.ap_image_dev_path() + |
| "\""); |
| |
| auto kernel_logs_path = instance_.PerInstanceLogPath("crosvm_openwrt.log"); |
| ap_cmd.AddSerialConsoleReadOnly(kernel_logs_path); |
| |
| ap_cmd.Cmd().AddParameter(config_.ap_kernel_image()); |
| |
| std::vector<Command> commands; |
| commands.emplace_back(log_tee_.CreateLogTee(ap_cmd.Cmd(), "openwrt")); |
| commands.emplace_back(std::move(ap_cmd.Cmd())); |
| return commands; |
| } |
| |
| // SetupFeature |
| std::string Name() const override { return "OpenWrt"; } |
| bool Enabled() const override { |
| #ifndef ENFORCE_MAC80211_HWSIM |
| return false; |
| #else |
| return instance_.start_ap() && |
| config_.vm_manager() == vm_manager::CrosvmManager::name(); |
| #endif |
| } |
| |
| private: |
| std::unordered_set<SetupFeature*> Dependencies() const override { return {}; } |
| bool Setup() override { return true; } |
| |
| const CuttlefishConfig& config_; |
| const CuttlefishConfig::InstanceSpecific& instance_; |
| LogTeeCreator& log_tee_; |
| }; |
| |
| using PublicDeps = fruit::Required<const CuttlefishConfig, VmManager, |
| const CuttlefishConfig::InstanceSpecific>; |
| fruit::Component<PublicDeps, KernelLogPipeProvider> launchComponent() { |
| using InternalDeps = fruit::Required<const CuttlefishConfig, VmManager, |
| const CuttlefishConfig::InstanceSpecific, |
| KernelLogPipeProvider>; |
| using Multi = Multibindings<InternalDeps>; |
| using Bases = |
| Multi::Bases<CommandSource, DiagnosticInformation, SetupFeature>; |
| return fruit::createComponent() |
| .bind<KernelLogPipeProvider, KernelLogMonitor>() |
| .install(Bases::Impls<BluetoothConnector>) |
| .install(Bases::Impls<ConfigServer>) |
| .install(Bases::Impls<ConsoleForwarder>) |
| .install(Bases::Impls<GnssGrpcProxyServer>) |
| .install(Bases::Impls<KernelLogMonitor>) |
| .install(Bases::Impls<LogcatReceiver>) |
| .install(Bases::Impls<MetricsService>) |
| .install(Bases::Impls<RootCanal>) |
| .install(Bases::Impls<SecureEnvironment>) |
| .install(Bases::Impls<TombstoneReceiver>) |
| .install(Bases::Impls<VehicleHalServer>) |
| .install(Bases::Impls<VmmCommands>) |
| .install(Bases::Impls<WmediumdServer>) |
| .install(Bases::Impls<OpenWrt>); |
| } |
| |
| } // namespace cuttlefish |